pk11_aes_gcm_unittest.cc (17142B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim: set ts=2 et sw=2 tw=80: */ 3 /* This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this file, 5 * You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #include <memory> 8 #include "nss.h" 9 #include "pk11pub.h" 10 #include "pk11priv.h" 11 #include "secerr.h" 12 #include "sechash.h" 13 14 #include "nss_scoped_ptrs.h" 15 16 #include "testvectors/gcm-vectors.h" 17 #include "gtest/gtest.h" 18 #include "util.h" 19 20 namespace nss_test { 21 22 class Pkcs11AesGcmTest : public ::testing::TestWithParam<AesGcmKatValue> { 23 protected: 24 void RunTest(const AesGcmKatValue vec) { 25 std::vector<uint8_t> key = hex_string_to_bytes(vec.key); 26 std::vector<uint8_t> iv = hex_string_to_bytes(vec.iv); 27 std::vector<uint8_t> plaintext = hex_string_to_bytes(vec.plaintext); 28 std::vector<uint8_t> aad = hex_string_to_bytes(vec.additional_data); 29 std::vector<uint8_t> result = hex_string_to_bytes(vec.result); 30 bool invalid_ct = vec.invalid_ct; 31 bool invalid_iv = vec.invalid_iv; 32 std::string msg = "Test #" + std::to_string(vec.id) + " failed"; 33 // Ignore GHASH-only vectors. 34 if (key.empty()) { 35 return; 36 } 37 38 // Prepare AEAD params. 39 CK_NSS_GCM_PARAMS gcm_params; 40 gcm_params.pIv = iv.data(); 41 gcm_params.ulIvLen = iv.size(); 42 gcm_params.pAAD = aad.data(); 43 gcm_params.ulAADLen = aad.size(); 44 gcm_params.ulTagBits = 128; 45 46 SECItem params = {siBuffer, reinterpret_cast<unsigned char*>(&gcm_params), 47 sizeof(gcm_params)}; 48 49 ScopedPK11SlotInfo slot(PK11_GetInternalSlot()); 50 SECItem key_item = {siBuffer, key.data(), 51 static_cast<unsigned int>(key.size())}; 52 53 // Import key. 54 ScopedPK11SymKey sym_key(PK11_ImportSymKey( 55 slot.get(), mech, PK11_OriginUnwrap, CKA_ENCRYPT, &key_item, nullptr)); 56 ASSERT_TRUE(!!sym_key) << msg; 57 58 // Encrypt with bogus parameters. 59 unsigned int output_len = 0; 60 std::vector<uint8_t> output(plaintext.size() + gcm_params.ulTagBits / 8); 61 // "maxout" must be at least "inlen + tagBytes", or, in this case: 62 // "output.size()" must be at least "plaintext.size() + tagBytes" 63 gcm_params.ulTagBits = 128; 64 SECStatus rv = 65 PK11_Encrypt(sym_key.get(), mech, ¶ms, output.data(), &output_len, 66 output.size() - 10, plaintext.data(), plaintext.size()); 67 EXPECT_EQ(SECFailure, rv); 68 EXPECT_EQ(0U, output_len); 69 70 // The valid values for tag size in AES_GCM are: 71 // 32, 64, 96, 104, 112, 120 and 128. 72 gcm_params.ulTagBits = 110; 73 rv = PK11_Encrypt(sym_key.get(), mech, ¶ms, output.data(), &output_len, 74 output.size(), plaintext.data(), plaintext.size()); 75 EXPECT_EQ(SECFailure, rv); 76 EXPECT_EQ(0U, output_len); 77 78 // Encrypt. 79 gcm_params.ulTagBits = 128; 80 rv = PK11_Encrypt(sym_key.get(), mech, ¶ms, output.data(), &output_len, 81 output.size(), plaintext.data(), plaintext.size()); 82 if (invalid_iv) { 83 EXPECT_EQ(SECFailure, rv) << msg; 84 EXPECT_EQ(0U, output_len); 85 return; 86 } 87 EXPECT_EQ(SECSuccess, rv) << msg; 88 89 ASSERT_EQ(output_len, output.size()) << msg; 90 91 // Check ciphertext and tag. 92 if (invalid_ct) { 93 EXPECT_NE(result, output) << msg; 94 } else { 95 EXPECT_EQ(result, output) << msg; 96 } 97 98 // Decrypt. 99 unsigned int decrypted_len = 0; 100 // The PK11 AES API is stupid, it expects an explicit IV and thus wants 101 // a block more of available output memory. 102 std::vector<uint8_t> decrypted(output.size()); 103 rv = PK11_Decrypt(sym_key.get(), mech, ¶ms, decrypted.data(), 104 &decrypted_len, decrypted.size(), output.data(), 105 output_len); 106 EXPECT_EQ(SECSuccess, rv) << msg; 107 ASSERT_EQ(decrypted_len, plaintext.size()) << msg; 108 109 // Check the plaintext. 110 EXPECT_EQ(plaintext, 111 std::vector<uint8_t>(decrypted.begin(), 112 decrypted.begin() + decrypted_len)) 113 << msg; 114 } 115 116 SECStatus EncryptWithIV(std::vector<uint8_t>& iv) { 117 // Generate a random key. 118 ScopedPK11SlotInfo slot(PK11_GetInternalSlot()); 119 ScopedPK11SymKey sym_key( 120 PK11_KeyGen(slot.get(), mech, nullptr, 16, nullptr)); 121 EXPECT_TRUE(!!sym_key); 122 123 std::vector<uint8_t> data(17); 124 std::vector<uint8_t> output(33); 125 std::vector<uint8_t> aad(0); 126 127 // Prepare AEAD params. 128 CK_NSS_GCM_PARAMS gcm_params; 129 gcm_params.pIv = iv.data(); 130 gcm_params.ulIvLen = iv.size(); 131 gcm_params.pAAD = aad.data(); 132 gcm_params.ulAADLen = aad.size(); 133 gcm_params.ulTagBits = 128; 134 135 SECItem params = {siBuffer, reinterpret_cast<unsigned char*>(&gcm_params), 136 sizeof(gcm_params)}; 137 138 // Try to encrypt. 139 unsigned int output_len = 0; 140 return PK11_Encrypt(sym_key.get(), mech, ¶ms, output.data(), 141 &output_len, output.size(), data.data(), data.size()); 142 } 143 144 SECStatus MessageInterfaceTest(int iterations, int ivFixedBits, 145 CK_GENERATOR_FUNCTION ivGen, 146 PRBool separateTag) { 147 // Generate a random key. 148 ScopedPK11SlotInfo slot(PK11_GetInternalSlot()); 149 EXPECT_NE(nullptr, slot); 150 ScopedPK11SymKey sym_key( 151 PK11_KeyGen(slot.get(), mech, nullptr, 16, nullptr)); 152 EXPECT_NE(nullptr, sym_key); 153 154 const int kTagSize = 16; 155 int cipher_simulated_size; 156 int output_len_message = 0; 157 int output_len_simulated = 0; 158 unsigned int output_len_v24 = 0; 159 160 std::vector<uint8_t> plainIn(17); 161 std::vector<uint8_t> plainOut_message(17); 162 std::vector<uint8_t> plainOut_simulated(17); 163 std::vector<uint8_t> plainOut_v24(17); 164 std::vector<uint8_t> iv(16); 165 std::vector<uint8_t> iv_init(16); 166 std::vector<uint8_t> iv_simulated(16); 167 std::vector<uint8_t> cipher_message(33); 168 std::vector<uint8_t> cipher_simulated(33); 169 std::vector<uint8_t> cipher_v24(33); 170 std::vector<uint8_t> aad(16); 171 std::vector<uint8_t> tag_message(16); 172 std::vector<uint8_t> tag_simulated(16); 173 174 // Prepare AEAD v2.40 params. 175 CK_GCM_PARAMS_V3 gcm_params; 176 gcm_params.pIv = iv.data(); 177 gcm_params.ulIvLen = iv.size(); 178 gcm_params.ulIvBits = iv.size() * 8; 179 gcm_params.pAAD = aad.data(); 180 gcm_params.ulAADLen = aad.size(); 181 gcm_params.ulTagBits = kTagSize * 8; 182 183 // Prepare AEAD MESSAGE params. 184 CK_GCM_MESSAGE_PARAMS gcm_message_params; 185 gcm_message_params.pIv = iv.data(); 186 gcm_message_params.ulIvLen = iv.size(); 187 gcm_message_params.ulTagBits = kTagSize * 8; 188 gcm_message_params.ulIvFixedBits = ivFixedBits; 189 gcm_message_params.ivGenerator = ivGen; 190 if (separateTag) { 191 gcm_message_params.pTag = tag_message.data(); 192 } else { 193 gcm_message_params.pTag = cipher_message.data() + plainIn.size(); 194 } 195 196 // Prepare AEAD MESSAGE params for simulated case 197 CK_GCM_MESSAGE_PARAMS gcm_simulated_params; 198 gcm_simulated_params = gcm_message_params; 199 if (separateTag) { 200 // The simulated case, we have to allocate temp bufs for separate 201 // tags, make sure that works in both the encrypt and the decrypt 202 // cases. 203 gcm_simulated_params.pTag = tag_simulated.data(); 204 cipher_simulated_size = cipher_simulated.size() - kTagSize; 205 } else { 206 gcm_simulated_params.pTag = cipher_simulated.data() + plainIn.size(); 207 cipher_simulated_size = cipher_simulated.size(); 208 } 209 /* when we are using CKG_GENERATE_RANDOM, don't independently generate 210 * the IV in the simulated case. Since the IV's would be random, none of 211 * the generated results would be the same. Just use the IV we generated 212 * in message interface */ 213 if (ivGen == CKG_GENERATE_RANDOM) { 214 gcm_simulated_params.ivGenerator = CKG_NO_GENERATE; 215 } else { 216 gcm_simulated_params.pIv = iv_simulated.data(); 217 } 218 219 SECItem params = {siBuffer, reinterpret_cast<unsigned char*>(&gcm_params), 220 sizeof(gcm_params)}; 221 SECItem empty = {siBuffer, NULL, 0}; 222 223 // initialize our plain text, IV and aad. 224 EXPECT_EQ(PK11_GenerateRandom(plainIn.data(), plainIn.size()), SECSuccess); 225 EXPECT_EQ(PK11_GenerateRandom(aad.data(), aad.size()), SECSuccess); 226 EXPECT_EQ(PK11_GenerateRandom(iv_init.data(), iv_init.size()), SECSuccess); 227 iv_simulated = iv_init; // vector assignment actually copies data 228 iv = iv_init; 229 230 // Initialize message encrypt context 231 ScopedPK11Context encrypt_message_context(PK11_CreateContextBySymKey( 232 mech, CKA_NSS_MESSAGE | CKA_ENCRYPT, sym_key.get(), &empty)); 233 EXPECT_NE(nullptr, encrypt_message_context); 234 if (!encrypt_message_context) { 235 return SECFailure; 236 } 237 EXPECT_FALSE(_PK11_ContextGetAEADSimulation(encrypt_message_context.get())); 238 239 // Initialize simulated encrypt context 240 ScopedPK11Context encrypt_simulated_context(PK11_CreateContextBySymKey( 241 mech, CKA_NSS_MESSAGE | CKA_ENCRYPT, sym_key.get(), &empty)); 242 EXPECT_NE(nullptr, encrypt_simulated_context); 243 if (!encrypt_simulated_context) { 244 return SECFailure; 245 } 246 EXPECT_EQ(SECSuccess, 247 _PK11_ContextSetAEADSimulation(encrypt_simulated_context.get())); 248 249 // Initialize message decrypt context 250 ScopedPK11Context decrypt_message_context(PK11_CreateContextBySymKey( 251 mech, CKA_NSS_MESSAGE | CKA_DECRYPT, sym_key.get(), &empty)); 252 EXPECT_NE(nullptr, decrypt_message_context); 253 if (!decrypt_message_context) { 254 return SECFailure; 255 } 256 EXPECT_FALSE(_PK11_ContextGetAEADSimulation(decrypt_message_context.get())); 257 258 // Initialize simulated decrypt context 259 ScopedPK11Context decrypt_simulated_context(PK11_CreateContextBySymKey( 260 mech, CKA_NSS_MESSAGE | CKA_DECRYPT, sym_key.get(), &empty)); 261 EXPECT_NE(nullptr, decrypt_simulated_context); 262 if (!decrypt_simulated_context) { 263 return SECFailure; 264 } 265 EXPECT_EQ(SECSuccess, 266 _PK11_ContextSetAEADSimulation(decrypt_simulated_context.get())); 267 268 // Now walk down our iterations. Each method of calculating the operation 269 // should agree at each step. 270 for (int i = 0; i < iterations; i++) { 271 SECStatus rv; 272 /* recopy the initial vector each time */ 273 iv_simulated = iv_init; 274 iv = iv_init; 275 276 // First encrypt. We don't test the error code here, because 277 // we may be testing error conditions with this function (namely 278 // do we fail if we try to generate to many Random IV's). 279 rv = 280 PK11_AEADRawOp(encrypt_message_context.get(), &gcm_message_params, 281 sizeof(gcm_message_params), aad.data(), aad.size(), 282 cipher_message.data(), &output_len_message, 283 cipher_message.size(), plainIn.data(), plainIn.size()); 284 if (rv != SECSuccess) { 285 return rv; 286 } 287 rv = 288 PK11_AEADRawOp(encrypt_simulated_context.get(), &gcm_simulated_params, 289 sizeof(gcm_simulated_params), aad.data(), aad.size(), 290 cipher_simulated.data(), &output_len_simulated, 291 cipher_simulated_size, plainIn.data(), plainIn.size()); 292 if (rv != SECSuccess) { 293 return rv; 294 } 295 // make sure simulated and message is the same 296 EXPECT_EQ(output_len_message, output_len_simulated); 297 EXPECT_EQ(0, memcmp(cipher_message.data(), cipher_simulated.data(), 298 output_len_message)); 299 EXPECT_EQ(0, memcmp(gcm_message_params.pTag, gcm_simulated_params.pTag, 300 kTagSize)); 301 EXPECT_EQ(0, memcmp(iv.data(), gcm_simulated_params.pIv, iv.size())); 302 // make sure v2.40 is the same. it inherits the generated iv from 303 // encrypt_message_context. 304 EXPECT_EQ(SECSuccess, 305 PK11_Encrypt(sym_key.get(), mech, ¶ms, cipher_v24.data(), 306 &output_len_v24, cipher_v24.size(), plainIn.data(), 307 plainIn.size())); 308 EXPECT_EQ(output_len_message, (int)output_len_v24 - kTagSize); 309 EXPECT_EQ(0, memcmp(cipher_message.data(), cipher_v24.data(), 310 output_len_message)); 311 EXPECT_EQ(0, memcmp(gcm_message_params.pTag, 312 cipher_v24.data() + output_len_message, kTagSize)); 313 // now make sure we can decrypt 314 EXPECT_EQ(SECSuccess, 315 PK11_AEADRawOp(decrypt_message_context.get(), 316 &gcm_message_params, sizeof(gcm_message_params), 317 aad.data(), aad.size(), plainOut_message.data(), 318 &output_len_message, plainOut_message.size(), 319 cipher_message.data(), output_len_message)); 320 EXPECT_EQ(output_len_message, (int)plainIn.size()); 321 EXPECT_EQ( 322 0, memcmp(plainOut_message.data(), plainIn.data(), plainIn.size())); 323 EXPECT_EQ( 324 SECSuccess, 325 PK11_AEADRawOp(decrypt_simulated_context.get(), &gcm_simulated_params, 326 sizeof(gcm_simulated_params), aad.data(), aad.size(), 327 plainOut_simulated.data(), &output_len_simulated, 328 plainOut_simulated.size(), cipher_message.data(), 329 output_len_simulated)); 330 EXPECT_EQ(output_len_simulated, (int)plainIn.size()); 331 EXPECT_EQ( 332 0, memcmp(plainOut_simulated.data(), plainIn.data(), plainIn.size())); 333 if (separateTag) { 334 // in the separateTag case, we need to copy the tag back to the 335 // end of the cipher_message.data() before using the v2.4 interface 336 memcpy(cipher_message.data() + output_len_message, 337 gcm_message_params.pTag, kTagSize); 338 } 339 EXPECT_EQ(SECSuccess, 340 PK11_Decrypt(sym_key.get(), mech, ¶ms, plainOut_v24.data(), 341 &output_len_v24, plainOut_v24.size(), 342 cipher_message.data(), output_len_v24)); 343 EXPECT_EQ(output_len_v24, plainIn.size()); 344 EXPECT_EQ(0, memcmp(plainOut_v24.data(), plainIn.data(), plainIn.size())); 345 } 346 return SECSuccess; 347 } 348 349 const CK_MECHANISM_TYPE mech = CKM_AES_GCM; 350 }; 351 352 TEST_P(Pkcs11AesGcmTest, TestVectors) { RunTest(GetParam()); } 353 354 INSTANTIATE_TEST_SUITE_P(NISTTestVector, Pkcs11AesGcmTest, 355 ::testing::ValuesIn(kGcmKatValues)); 356 357 INSTANTIATE_TEST_SUITE_P(WycheproofTestVector, Pkcs11AesGcmTest, 358 ::testing::ValuesIn(kGcmWycheproofVectors)); 359 360 TEST_F(Pkcs11AesGcmTest, ZeroLengthIV) { 361 std::vector<uint8_t> iv(0); 362 EXPECT_EQ(SECFailure, EncryptWithIV(iv)); 363 } 364 365 TEST_F(Pkcs11AesGcmTest, AllZeroIV) { 366 std::vector<uint8_t> iv(16, 0); 367 EXPECT_EQ(SECSuccess, EncryptWithIV(iv)); 368 } 369 370 TEST_F(Pkcs11AesGcmTest, TwelveByteZeroIV) { 371 std::vector<uint8_t> iv(12, 0); 372 EXPECT_EQ(SECSuccess, EncryptWithIV(iv)); 373 } 374 375 // basic message interface it's the most common configuration 376 TEST_F(Pkcs11AesGcmTest, MessageInterfaceBasic) { 377 EXPECT_EQ(SECSuccess, 378 MessageInterfaceTest(16, 0, CKG_GENERATE_COUNTER, PR_FALSE)); 379 } 380 381 // basic interface, but return the tags in a separate buffer. This triggers 382 // different behaviour in the simulated case, which has to buffer the 383 // intermediate values in a separate buffer. 384 TEST_F(Pkcs11AesGcmTest, MessageInterfaceSeparateTags) { 385 EXPECT_EQ(SECSuccess, 386 MessageInterfaceTest(16, 0, CKG_GENERATE_COUNTER, PR_TRUE)); 387 } 388 389 // test the case where we are only allowing a portion of the iv to be generated 390 TEST_F(Pkcs11AesGcmTest, MessageInterfaceIVMask) { 391 EXPECT_EQ(SECSuccess, 392 MessageInterfaceTest(16, 124, CKG_GENERATE_COUNTER, PR_FALSE)); 393 } 394 395 // test the case where we using the tls1.3 iv generation 396 TEST_F(Pkcs11AesGcmTest, MessageInterfaceXorCounter) { 397 EXPECT_EQ(SECSuccess, 398 MessageInterfaceTest(16, 0, CKG_GENERATE_COUNTER_XOR, PR_FALSE)); 399 } 400 401 // test the case where we overflow the counter (requires restricted iv) 402 // 128-124 = 4 bits; 403 TEST_F(Pkcs11AesGcmTest, MessageInterfaceCounterOverflow) { 404 EXPECT_EQ(SECFailure, 405 MessageInterfaceTest(17, 124, CKG_GENERATE_COUNTER, PR_FALSE)); 406 } 407 408 // overflow the tla1.2 iv case 409 TEST_F(Pkcs11AesGcmTest, MessageInterfaceXorCounterOverflow) { 410 EXPECT_EQ(SECFailure, 411 MessageInterfaceTest(17, 124, CKG_GENERATE_COUNTER_XOR, PR_FALSE)); 412 } 413 414 // test random generation of the IV (uses an aligned restricted iv) 415 TEST_F(Pkcs11AesGcmTest, MessageInterfaceRandomIV) { 416 EXPECT_EQ(SECSuccess, 417 MessageInterfaceTest(16, 56, CKG_GENERATE_RANDOM, PR_FALSE)); 418 } 419 420 // test the case where we try to generate too many random IVs for the size of 421 // our our restricted IV (notice for counters, we can generate 16 IV with 422 // 4 bits, but for random we need at least 72 bits to generate 16 IVs). 423 // 128-56 = 72 bits 424 TEST_F(Pkcs11AesGcmTest, MessageInterfaceRandomOverflow) { 425 EXPECT_EQ(SECFailure, 426 MessageInterfaceTest(17, 56, CKG_GENERATE_RANDOM, PR_FALSE)); 427 } 428 } // namespace nss_test