Martin Kreichgauer | 7c12587 | 2017-04-24 13:29:11 -0700 | [diff] [blame] | 1 | /* Copyright (c) 2017, Google Inc. |
| 2 | * |
| 3 | * Permission to use, copy, modify, and/or distribute this software for any |
| 4 | * purpose with or without fee is hereby granted, provided that the above |
| 5 | * copyright notice and this permission notice appear in all copies. |
| 6 | * |
| 7 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
| 8 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
| 9 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY |
| 10 | * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
| 11 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION |
| 12 | * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN |
| 13 | * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ |
| 14 | |
| 15 | #include "cavp_test_util.h" |
| 16 | |
David Benjamin | 90801c1 | 2017-04-28 17:08:45 -0400 | [diff] [blame] | 17 | #include <openssl/bn.h> |
David Benjamin | 0c292ed | 2017-04-28 17:41:28 -0400 | [diff] [blame] | 18 | #include <openssl/digest.h> |
David Benjamin | 90801c1 | 2017-04-28 17:08:45 -0400 | [diff] [blame] | 19 | #include <openssl/ec.h> |
| 20 | #include <openssl/nid.h> |
| 21 | |
Martin Kreichgauer | 7c12587 | 2017-04-24 13:29:11 -0700 | [diff] [blame] | 22 | |
| 23 | std::string EncodeHex(const uint8_t *in, size_t in_len) { |
| 24 | static const char kHexDigits[] = "0123456789abcdef"; |
| 25 | std::string ret; |
| 26 | ret.reserve(in_len * 2); |
| 27 | for (size_t i = 0; i < in_len; i++) { |
| 28 | ret += kHexDigits[in[i] >> 4]; |
| 29 | ret += kHexDigits[in[i] & 0xf]; |
| 30 | } |
| 31 | return ret; |
| 32 | } |
| 33 | |
| 34 | const EVP_CIPHER *GetCipher(const std::string &name) { |
| 35 | if (name == "des-cbc") { |
| 36 | return EVP_des_cbc(); |
| 37 | } else if (name == "des-ecb") { |
| 38 | return EVP_des_ecb(); |
| 39 | } else if (name == "des-ede") { |
| 40 | return EVP_des_ede(); |
| 41 | } else if (name == "des-ede3") { |
| 42 | return EVP_des_ede3(); |
| 43 | } else if (name == "des-ede-cbc") { |
| 44 | return EVP_des_ede_cbc(); |
| 45 | } else if (name == "des-ede3-cbc") { |
| 46 | return EVP_des_ede3_cbc(); |
| 47 | } else if (name == "rc4") { |
| 48 | return EVP_rc4(); |
| 49 | } else if (name == "aes-128-ecb") { |
| 50 | return EVP_aes_128_ecb(); |
| 51 | } else if (name == "aes-256-ecb") { |
| 52 | return EVP_aes_256_ecb(); |
| 53 | } else if (name == "aes-128-cbc") { |
| 54 | return EVP_aes_128_cbc(); |
| 55 | } else if (name == "aes-128-gcm") { |
| 56 | return EVP_aes_128_gcm(); |
| 57 | } else if (name == "aes-128-ofb") { |
| 58 | return EVP_aes_128_ofb(); |
| 59 | } else if (name == "aes-192-cbc") { |
| 60 | return EVP_aes_192_cbc(); |
| 61 | } else if (name == "aes-192-ctr") { |
| 62 | return EVP_aes_192_ctr(); |
| 63 | } else if (name == "aes-192-ecb") { |
| 64 | return EVP_aes_192_ecb(); |
| 65 | } else if (name == "aes-256-cbc") { |
| 66 | return EVP_aes_256_cbc(); |
| 67 | } else if (name == "aes-128-ctr") { |
| 68 | return EVP_aes_128_ctr(); |
| 69 | } else if (name == "aes-256-ctr") { |
| 70 | return EVP_aes_256_ctr(); |
| 71 | } else if (name == "aes-256-gcm") { |
| 72 | return EVP_aes_256_gcm(); |
| 73 | } else if (name == "aes-256-ofb") { |
| 74 | return EVP_aes_256_ofb(); |
| 75 | } |
| 76 | return nullptr; |
| 77 | } |
| 78 | |
| 79 | bool CipherOperation(const EVP_CIPHER *cipher, std::vector<uint8_t> *out, |
| 80 | bool encrypt, const std::vector<uint8_t> &key, |
| 81 | const std::vector<uint8_t> &iv, |
| 82 | const std::vector<uint8_t> &in) { |
| 83 | bssl::ScopedEVP_CIPHER_CTX ctx; |
| 84 | if (!EVP_CipherInit_ex(ctx.get(), cipher, nullptr, nullptr, nullptr, |
| 85 | encrypt ? 1 : 0)) { |
| 86 | return false; |
| 87 | } |
| 88 | if (!iv.empty() && iv.size() != EVP_CIPHER_CTX_iv_length(ctx.get())) { |
| 89 | return false; |
| 90 | } |
| 91 | |
| 92 | int result_len1 = 0, result_len2; |
| 93 | *out = std::vector<uint8_t>(in.size()); |
| 94 | if (!EVP_CIPHER_CTX_set_key_length(ctx.get(), key.size()) || |
| 95 | !EVP_CipherInit_ex(ctx.get(), nullptr, nullptr, key.data(), iv.data(), |
| 96 | -1) || |
| 97 | !EVP_CIPHER_CTX_set_padding(ctx.get(), 0) || |
| 98 | !EVP_CipherUpdate(ctx.get(), out->data(), &result_len1, in.data(), |
| 99 | in.size()) || |
| 100 | !EVP_CipherFinal_ex(ctx.get(), out->data() + result_len1, &result_len2)) { |
| 101 | return false; |
| 102 | } |
| 103 | out->resize(result_len1 + result_len2); |
| 104 | |
| 105 | return true; |
| 106 | } |
| 107 | |
| 108 | bool AEADEncrypt(const EVP_AEAD *aead, std::vector<uint8_t> *ct, |
| 109 | std::vector<uint8_t> *tag, size_t tag_len, |
| 110 | const std::vector<uint8_t> &key, |
| 111 | const std::vector<uint8_t> &pt, |
Adam Langley | 563924b | 2017-05-30 11:43:25 -0700 | [diff] [blame] | 112 | const std::vector<uint8_t> &aad, |
| 113 | const std::vector<uint8_t> &iv) { |
Martin Kreichgauer | 7c12587 | 2017-04-24 13:29:11 -0700 | [diff] [blame] | 114 | bssl::ScopedEVP_AEAD_CTX ctx; |
Adam Langley | 563924b | 2017-05-30 11:43:25 -0700 | [diff] [blame] | 115 | if (!EVP_AEAD_CTX_init(ctx.get(), aead, key.data(), key.size(), tag_len, |
| 116 | nullptr)) { |
Martin Kreichgauer | 7c12587 | 2017-04-24 13:29:11 -0700 | [diff] [blame] | 117 | return false; |
| 118 | } |
| 119 | |
| 120 | std::vector<uint8_t> out; |
| 121 | out.resize(pt.size() + EVP_AEAD_max_overhead(aead)); |
| 122 | size_t out_len; |
Adam Langley | 563924b | 2017-05-30 11:43:25 -0700 | [diff] [blame] | 123 | if (!EVP_AEAD_CTX_seal(ctx.get(), out.data(), &out_len, out.size(), iv.data(), |
| 124 | iv.size(), pt.data(), pt.size(), aad.data(), |
| 125 | aad.size())) { |
Martin Kreichgauer | 7c12587 | 2017-04-24 13:29:11 -0700 | [diff] [blame] | 126 | return false; |
| 127 | } |
Adam Langley | 563924b | 2017-05-30 11:43:25 -0700 | [diff] [blame] | 128 | out.resize(out_len); |
Martin Kreichgauer | 7c12587 | 2017-04-24 13:29:11 -0700 | [diff] [blame] | 129 | |
Steven Valdez | 2f3404b | 2017-05-24 16:54:35 -0400 | [diff] [blame] | 130 | ct->assign(out.begin(), out.end() - tag_len); |
Martin Kreichgauer | 7c12587 | 2017-04-24 13:29:11 -0700 | [diff] [blame] | 131 | tag->assign(out.end() - tag_len, out.end()); |
| 132 | |
| 133 | return true; |
| 134 | } |
| 135 | |
Adam Langley | 563924b | 2017-05-30 11:43:25 -0700 | [diff] [blame] | 136 | bool AEADDecrypt(const EVP_AEAD *aead, std::vector<uint8_t> *pt, size_t pt_len, |
Martin Kreichgauer | 7c12587 | 2017-04-24 13:29:11 -0700 | [diff] [blame] | 137 | const std::vector<uint8_t> &key, |
Adam Langley | 563924b | 2017-05-30 11:43:25 -0700 | [diff] [blame] | 138 | const std::vector<uint8_t> &aad, |
Martin Kreichgauer | 7c12587 | 2017-04-24 13:29:11 -0700 | [diff] [blame] | 139 | const std::vector<uint8_t> &ct, |
Adam Langley | 563924b | 2017-05-30 11:43:25 -0700 | [diff] [blame] | 140 | const std::vector<uint8_t> &tag, |
| 141 | const std::vector<uint8_t> &iv) { |
Martin Kreichgauer | 7c12587 | 2017-04-24 13:29:11 -0700 | [diff] [blame] | 142 | bssl::ScopedEVP_AEAD_CTX ctx; |
| 143 | if (!EVP_AEAD_CTX_init_with_direction(ctx.get(), aead, key.data(), key.size(), |
| 144 | tag.size(), evp_aead_open)) { |
| 145 | return false; |
| 146 | } |
Steven Valdez | 2f3404b | 2017-05-24 16:54:35 -0400 | [diff] [blame] | 147 | std::vector<uint8_t> in = ct; |
| 148 | in.reserve(ct.size() + tag.size()); |
Martin Kreichgauer | 7c12587 | 2017-04-24 13:29:11 -0700 | [diff] [blame] | 149 | in.insert(in.end(), tag.begin(), tag.end()); |
| 150 | |
| 151 | pt->resize(pt_len); |
Martin Kreichgauer | 7c12587 | 2017-04-24 13:29:11 -0700 | [diff] [blame] | 152 | size_t out_pt_len; |
| 153 | if (!EVP_AEAD_CTX_open(ctx.get(), pt->data(), &out_pt_len, pt->size(), |
Adam Langley | 563924b | 2017-05-30 11:43:25 -0700 | [diff] [blame] | 154 | iv.data(), iv.size(), in.data(), in.size(), aad.data(), |
| 155 | aad.size()) || |
Martin Kreichgauer | 7c12587 | 2017-04-24 13:29:11 -0700 | [diff] [blame] | 156 | out_pt_len != pt_len) { |
| 157 | return false; |
| 158 | } |
| 159 | return true; |
| 160 | } |
David Benjamin | 90801c1 | 2017-04-28 17:08:45 -0400 | [diff] [blame] | 161 | |
| 162 | static int HexToBIGNUM(bssl::UniquePtr<BIGNUM> *out, const char *in) { |
| 163 | BIGNUM *raw = NULL; |
| 164 | int ret = BN_hex2bn(&raw, in); |
| 165 | out->reset(raw); |
| 166 | return ret; |
| 167 | } |
| 168 | |
| 169 | bssl::UniquePtr<BIGNUM> GetBIGNUM(FileTest *t, const char *attribute) { |
| 170 | std::string hex; |
| 171 | if (!t->GetAttribute(&hex, attribute)) { |
| 172 | return nullptr; |
| 173 | } |
| 174 | |
| 175 | bssl::UniquePtr<BIGNUM> ret; |
| 176 | if (HexToBIGNUM(&ret, hex.c_str()) != static_cast<int>(hex.size())) { |
| 177 | t->PrintLine("Could not decode '%s'.", hex.c_str()); |
| 178 | return nullptr; |
| 179 | } |
| 180 | return ret; |
| 181 | } |
| 182 | |
David Benjamin | eb59989 | 2017-05-01 14:56:22 -0400 | [diff] [blame] | 183 | int GetECGroupNIDFromInstruction(FileTest *t, const char **out_str) { |
| 184 | const char *dummy; |
| 185 | if (out_str == nullptr) { |
| 186 | out_str = &dummy; |
| 187 | } |
| 188 | |
David Benjamin | 90801c1 | 2017-04-28 17:08:45 -0400 | [diff] [blame] | 189 | if (t->HasInstruction("P-224")) { |
David Benjamin | eb59989 | 2017-05-01 14:56:22 -0400 | [diff] [blame] | 190 | *out_str = "P-224"; |
David Benjamin | 90801c1 | 2017-04-28 17:08:45 -0400 | [diff] [blame] | 191 | return NID_secp224r1; |
| 192 | } |
| 193 | if (t->HasInstruction("P-256")) { |
David Benjamin | eb59989 | 2017-05-01 14:56:22 -0400 | [diff] [blame] | 194 | *out_str = "P-256"; |
David Benjamin | 90801c1 | 2017-04-28 17:08:45 -0400 | [diff] [blame] | 195 | return NID_X9_62_prime256v1; |
| 196 | } |
| 197 | if (t->HasInstruction("P-384")) { |
David Benjamin | eb59989 | 2017-05-01 14:56:22 -0400 | [diff] [blame] | 198 | *out_str = "P-384"; |
David Benjamin | 90801c1 | 2017-04-28 17:08:45 -0400 | [diff] [blame] | 199 | return NID_secp384r1; |
| 200 | } |
| 201 | if (t->HasInstruction("P-521")) { |
David Benjamin | eb59989 | 2017-05-01 14:56:22 -0400 | [diff] [blame] | 202 | *out_str = "P-521"; |
David Benjamin | 90801c1 | 2017-04-28 17:08:45 -0400 | [diff] [blame] | 203 | return NID_secp521r1; |
| 204 | } |
| 205 | t->PrintLine("No supported group specified."); |
| 206 | return NID_undef; |
| 207 | } |
David Benjamin | 0c292ed | 2017-04-28 17:41:28 -0400 | [diff] [blame] | 208 | |
| 209 | const EVP_MD *GetDigestFromInstruction(FileTest *t) { |
| 210 | if (t->HasInstruction("SHA-1")) { |
| 211 | return EVP_sha1(); |
| 212 | } |
| 213 | if (t->HasInstruction("SHA-224")) { |
| 214 | return EVP_sha224(); |
| 215 | } |
| 216 | if (t->HasInstruction("SHA-256")) { |
| 217 | return EVP_sha256(); |
| 218 | } |
| 219 | if (t->HasInstruction("SHA-384")) { |
| 220 | return EVP_sha384(); |
| 221 | } |
| 222 | if (t->HasInstruction("SHA-512")) { |
| 223 | return EVP_sha512(); |
| 224 | } |
| 225 | t->PrintLine("No supported digest function specified."); |
| 226 | return nullptr; |
| 227 | } |
Adam Langley | d79bc9d | 2017-05-30 15:37:27 -0700 | [diff] [blame] | 228 | |
| 229 | void EchoComment(const std::string& comment) { |
| 230 | fwrite(comment.c_str(), comment.size(), 1, stdout); |
| 231 | } |