1 module smimeasym.test; 2 3 import std.algorithm.comparison : equal; 4 import std.conv : to; 5 import std.exception : assertThrown; 6 import std.file : read, readText, deleteme, write; 7 import std.format : format; 8 import std.process : executeShell; 9 import std.stdio; 10 11 import smimeasym; 12 13 private void deleteThat(string fn) { 14 import std.file : exists, remove; 15 if(exists(fn)) { 16 remove(fn); 17 } 18 } 19 20 unittest { 21 string[3] pubKeys = 22 [ "./alice.pub" 23 , "./bob.pub" 24 , "./frank.pub" 25 ]; 26 27 string[3] privKeys = 28 [ "./alice.key" 29 , "./bob.key" 30 , "./frank.key" 31 ]; 32 33 // the unencrypted data written to a file 34 string data = "Hello openssl world"; 35 string dataFilename = deleteme ~ ".orig"; 36 write(dataFilename, data); 37 scope(success) { 38 deleteThat(dataFilename); 39 } 40 41 string encFilenameFromShell = deleteme ~ ".sh.src"; 42 43 // encrypt the data with the openssl cli 44 string encFromShell = format( 45 "openssl smime -encrypt -aes256 -in %s -out %s -outform PEM %--(%s %)" 46 , dataFilename, encFilenameFromShell, pubKeys); 47 auto encSh = executeShell(encFromShell); 48 assert(encSh.status == 0, format("%s\n%s\n%s", encSh.status, encSh.output 49 , encSh)); 50 scope(success) { 51 deleteThat(encFilenameFromShell); 52 } 53 54 // decrypt data encrypt by the openssl cli 55 ubyte[] encFileFromCli = cast(ubyte[])read(encFilenameFromShell); 56 foreach(privKey; privKeys) { 57 ubyte[] decrp = smimeDecryption(encFileFromCli, privKey); 58 string decrpStr = cast(string)decrp; 59 assert(data == decrpStr, format("\norig: %s\ndecr: %s", data, decrpStr)); 60 } 61 62 X509*[] keys; 63 X509*[] keys2; 64 assertThrown(smimeEncryptionWithCerts(cast(ubyte[])data, keys)); 65 keys ~= null; 66 assertThrown(smimeEncryptionWithCerts(cast(ubyte[])data, keys)); 67 keys = []; 68 69 EVP_PKEY*[] privKeysPtr; 70 foreach(pk; privKeys) { 71 privKeysPtr ~= loadKey(pk); 72 } 73 74 EVP_PKEY*[] privKeysPtr2; 75 foreach(pk; privKeys) { 76 privKeysPtr2 ~= loadKeyFromString(readText(pk)); 77 } 78 79 80 foreach(pubKey; pubKeys) { 81 auto t = loadCert(pubKey); 82 assert(t != null, pubKey); 83 keys ~= t; 84 } 85 foreach(pubKey; pubKeys) { 86 string c = readText(pubKey); 87 keys2 ~= loadCertFromString(c); 88 } 89 ubyte[] encArray = smimeEncryptionWithCerts(cast(ubyte[])data, keys); 90 ubyte[] encArray2 = smimeEncryptionWithCerts(cast(ubyte[])data, keys2); 91 92 // encrypt with this library and write to disk 93 string encFilename = deleteme ~ ".src"; 94 ubyte[] enc = smimeEncryption(cast(ubyte[])data, pubKeys); 95 96 // as the aes key should be random these shouldn't match 97 assert(!equal(enc, encArray)); 98 99 write(encFilename, enc); 100 scope(success) { 101 deleteThat(encFilename); 102 } 103 104 // decrypt with private keys 105 foreach(privKey; privKeys) { 106 ubyte[] decrp = smimeDecryption(enc, privKey); 107 string decrpStr = cast(string)decrp; 108 assert(data == decrpStr, format("\norig: %s\ndecr: %s", data, decrpStr)); 109 } 110 111 foreach(privKey; privKeys) { 112 ubyte[] decrp = smimeDecryption(encArray2, privKey); 113 string decrpStr = cast(string)decrp; 114 assert(data == decrpStr, format("\norig: %s\ndecr: %s", data, decrpStr)); 115 } 116 117 // decrypt with private keys in memory 118 foreach(privKey; privKeysPtr) { 119 ubyte[] decrp = smimeDecryptionWithKey(encArray2, privKey); 120 string decrpStr = cast(string)decrp; 121 assert(data == decrpStr, format("\norig: %s\ndecr: %s", data, decrpStr)); 122 } 123 124 // decrypt with private keys in memory 125 foreach(privKey; privKeysPtr2) { 126 ubyte[] decrp = smimeDecryptionWithKey(encArray2, privKey); 127 string decrpStr = cast(string)decrp; 128 assert(data == decrpStr, format("\norig: %s\ndecr: %s", data, decrpStr)); 129 } 130 131 // decrypt with private keys on cli 132 foreach(idx, privKey; privKeys) { 133 string decLibFilename = format("%s.%d.enc.lib", deleteme, idx); 134 string decFromShell = format( 135 "openssl smime -decrypt -in %s -out %s -inform PEM -inkey %s" 136 , encFilename, decLibFilename, privKey); 137 auto decSH = executeShell(decFromShell); 138 assert(decSH.status == 0, format("%s\n%s\n%s", decSH.status, decSH.output 139 , decFromShell)); 140 ubyte[] decFileFromCli = cast(ubyte[])read(decLibFilename); 141 string decrpStr = cast(string)decFileFromCli; 142 assert(data == decrpStr, format("\norig: %s\ndecr: %s", data, decrpStr)); 143 scope(success) { 144 deleteThat(decLibFilename); 145 } 146 } 147 foreach(cert; keys) { 148 freeCert(cert); 149 } 150 foreach(cert; keys2) { 151 freeCert(cert); 152 } 153 foreach(cert; privKeysPtr) { 154 freePrivKey(cert); 155 } 156 foreach(cert; privKeysPtr2) { 157 freePrivKey(cert); 158 } 159 } 160 161 unittest { 162 string data = "Hello openssl world"; 163 string[] pubKeys = [ "dub.json"]; 164 assertThrown(smimeEncryption(cast(ubyte[])data, pubKeys)); 165 } 166 167 unittest { 168 string data = "Hello openssl world"; 169 string privKeys = "dub.json"; 170 assertThrown(smimeDecryption(cast(ubyte[])data, privKeys)); 171 } 172 173 unittest { 174 string data = "Hello openssl world"; 175 string privKeys = "alice.key"; 176 assertThrown(smimeDecryption(cast(ubyte[])data, privKeys)); 177 } 178 179 unittest { 180 string data = "Hello openssl world"; 181 string privKeys = "source"; 182 assertThrown(smimeDecryption(cast(ubyte[])data, privKeys)); 183 } 184 185 unittest { 186 string data = "Hello openssl world"; 187 string privKeys = "doesnotexist"; 188 assertThrown(smimeDecryption(cast(ubyte[])data, privKeys)); 189 } 190 191 unittest { 192 string notAKey = "Not a key"; 193 auto k = loadCertFromString(notAKey); 194 assert(k is null); 195 } 196 197 unittest { 198 auto r = cast(ubyte[])read("README.md"); 199 auto p = loadCert("./alice.pub"); 200 auto e = smimeEncryptionWithCerts(r, [p]); 201 auto d = smimeDecryption(e, "./alice.key"); 202 write("textOrBinary.enc", e); 203 assert(r == d, format("%.3s %.3s\n%s\n\n%s\n%s", r.length, d.length, r, d, 204 cast(string)d)); 205 } 206 207 unittest { 208 string data = "Hello openssl world"; 209 ubyte[] r = smimeEncryption(cast(ubyte[])data, ["frank_with_pass.pub"]); 210 EVP_PKEY* privKey = loadKeyFromString(readText("frank_with_pass.key") 211 , "foobar"); 212 assert(privKey != null); 213 ubyte[] d = smimeDecryptionWithKey(r, privKey); 214 string rslt = cast(string)d; 215 assert(data == rslt, rslt); 216 freePrivKey(privKey); 217 }