1 module smimeasym;
2 
3 import std.stdio;
4 import std.array : empty;
5 import std.exception : enforce;
6 import std.file : exists, isFile;
7 import std.format : format;
8 import std.string;
9 
10 import smimeasym.sslimports;
11 
12 public import smimeasym.sslimports : X509, EVP_PKEY;
13 
14 extern(C) {
15 private:
16 struct Buffer {
17 	ubyte* source;
18 	long len;
19 }
20 
21 X509 *load_cert(const char *file);
22 EVP_PKEY* load_key_from_memory(const char* ptr, int len, const char* password);
23 EVP_PKEY* load_key(const char* keyfile);
24 public void freePrivKey(EVP_PKEY* key);
25 Buffer smime_main_encryption_with_certs(Buffer buf, X509** certs
26 		, size_t numCerts);
27 Buffer smime_main_encryption(Buffer buf, char** certs, size_t numCerts);
28 Buffer smime_main_decryption(Buffer inFile, char* privKeyFilename);
29 Buffer smime_main_decryption_with_key(Buffer inFile, EVP_PKEY* privKey);
30 void freeBuffer(Buffer buf);
31 int lengthErrorsArray();
32 X509* load_cert_from_memory(const char* d, size_t len);
33 
34 struct Error {
35 	int errorCode;
36 	const char* msg;
37 }
38 Error* errorsSmimeHandler();
39 public void freeCert(X509* certToFree);
40 }
41 
42 private ubyte[] copyAnFreeBuffer(Buffer rslt) {
43 	import std.stdio;
44 	enforce(rslt.len >= 0, getErrorString(rslt.len));
45 	ubyte[] ret = new ubyte[](rslt.len);
46 	foreach(it; 0 .. rslt.len) {
47 		ret[it] = rslt.source[it];
48 	}
49 	freeBuffer(rslt);
50 	return ret;
51 }
52 
53 private string getErrorString(const long errCode) {
54 	Error* errorArr = errorsSmimeHandler();
55 	for(int i = 0; i < lengthErrorsArray(); ++i) {
56 		if(errorArr[i].errorCode == errCode) {
57 			return fromStringz(errorArr[i].msg).idup;
58 		}
59 	}
60 	return "Unknonw error";
61 }
62 
63 X509* loadCert(string filename) {
64 	enforce(exists(filename), format("Cert '%s' doesn't exist", filename));
65 	enforce(isFile(filename), format("Cert '%s' is not a file", filename));
66 	return load_cert(filename.toStringz());
67 }
68 
69 X509* loadCertFromString(string data) {
70 	import std.string : toStringz;
71 	const(char)* c = toStringz(data);
72 	return load_cert_from_memory(c, data.length);
73 }
74 
75 EVP_PKEY* loadKey(string keyfilename) {
76 	import std.string : toStringz;
77 	const(char)* c = toStringz(keyfilename);
78 	return load_key(c);
79 }
80 
81 EVP_PKEY* loadKeyFromString(string data, string password = "") {
82 	import std.string : toStringz;
83 	const(char)* c = toStringz(data);
84 	return load_key_from_memory(c, cast(int)data.length, toStringz(password));
85 }
86 
87 ubyte[] smimeEncryption(ubyte[] buf, string[] publicKeyFilenames) {
88 	const(char)*[] asCstrings;
89 	foreach(key; publicKeyFilenames) {
90 		enforce(exists(key), format("Cert '%s' doesn't exist", key));
91 		enforce(isFile(key), format("Cert '%s' is not a file", key));
92 		asCstrings ~= key.toStringz();
93 	}
94 
95 	Buffer toPass;
96 	toPass.len = buf.length;
97 	toPass.source = buf.ptr;
98 
99 	Buffer rslt = smime_main_encryption(toPass, cast(char**)asCstrings.ptr,
100 			asCstrings.length);
101 	return copyAnFreeBuffer(rslt);
102 }
103 
104 ubyte[] smimeEncryptionWithCerts(ubyte[] buf, X509*[] certs) {
105 	import std.algorithm.searching : all;
106 
107 	enforce(!certs.empty, "certs array must not be empty");
108 	enforce(certs.all!(c => c != null), "no cert must be null");
109 	Buffer toPass;
110 	toPass.len = buf.length;
111 	toPass.source = buf.ptr;
112 
113 	Buffer rslt = smime_main_encryption_with_certs(toPass, certs.ptr,
114 			certs.length);
115 	return copyAnFreeBuffer(rslt);
116 }
117 
118 ubyte[] smimeDecryption(ubyte[] buf, string privateKeyFilename) {
119 	enforce(exists(privateKeyFilename)
120 			, format("Private key '%s' doesn't exist", privateKeyFilename));
121 	enforce(isFile(privateKeyFilename)
122 			, format("Private key '%s' is not a file", privateKeyFilename));
123 
124 	Buffer toPass;
125 	toPass.len = buf.length;
126 	toPass.source = buf.ptr;
127 
128 	Buffer rslt = smime_main_decryption(toPass
129 			, cast(char*)privateKeyFilename.ptr);
130 
131 	return copyAnFreeBuffer(rslt);
132 }
133 
134 ubyte[] smimeDecryptionWithKey(ubyte[] buf, EVP_PKEY* key) {
135 	Buffer toPass;
136 	toPass.len = buf.length;
137 	toPass.source = buf.ptr;
138 
139 	Buffer rslt = smime_main_decryption_with_key(toPass, key);
140 
141 	return copyAnFreeBuffer(rslt);
142 }