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 }