diff options
Diffstat (limited to 'security/nss/gtests/pk11_gtest')
41 files changed, 9036 insertions, 0 deletions
diff --git a/security/nss/gtests/pk11_gtest/Makefile b/security/nss/gtests/pk11_gtest/Makefile new file mode 100644 index 0000000000..0d547e0803 --- /dev/null +++ b/security/nss/gtests/pk11_gtest/Makefile @@ -0,0 +1,43 @@ +#! gmake +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +####################################################################### +# (1) Include initial platform-independent assignments (MANDATORY). # +####################################################################### + +include manifest.mn + +####################################################################### +# (2) Include "global" configuration information. (OPTIONAL) # +####################################################################### + +include $(CORE_DEPTH)/coreconf/config.mk + +####################################################################### +# (3) Include "component" configuration information. (OPTIONAL) # +####################################################################### + + +####################################################################### +# (4) Include "local" platform-dependent assignments (OPTIONAL). # +####################################################################### + +include ../common/gtest.mk + +####################################################################### +# (5) Execute "global" rules. (OPTIONAL) # +####################################################################### + +include $(CORE_DEPTH)/coreconf/rules.mk + +####################################################################### +# (6) Execute "component" rules. (OPTIONAL) # +####################################################################### + + +####################################################################### +# (7) Execute "local" rules. (OPTIONAL). # +####################################################################### diff --git a/security/nss/gtests/pk11_gtest/manifest.mn b/security/nss/gtests/pk11_gtest/manifest.mn new file mode 100644 index 0000000000..80530675b3 --- /dev/null +++ b/security/nss/gtests/pk11_gtest/manifest.mn @@ -0,0 +1,57 @@ +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +CORE_DEPTH = ../.. +DEPTH = ../.. +MODULE = nss + +CPPSRCS = \ + pk11_aes_gcm_unittest.cc \ + pk11_aeskeywrap_unittest.cc \ + pk11_aeskeywrapkwp_unittest.cc \ + pk11_aeskeywrappad_unittest.cc \ + pk11_cbc_unittest.cc \ + pk11_chacha20poly1305_unittest.cc \ + pk11_curve25519_unittest.cc \ + pk11_der_private_key_import_unittest.cc \ + pk11_des_unittest.cc \ + pk11_dsa_unittest.cc \ + pk11_ecdsa_unittest.cc \ + pk11_ecdh_unittest.cc \ + pk11_encrypt_derive_unittest.cc \ + pk11_export_unittest.cc \ + pk11_find_certs_unittest.cc \ + pk11_hkdf_unittest.cc \ + pk11_hmac_unittest.cc \ + pk11_hpke_unittest.cc \ + pk11_ike_unittest.cc \ + pk11_import_unittest.cc \ + pk11_kbkdf.cc \ + pk11_keygen.cc \ + pk11_key_unittest.cc \ + pk11_module_unittest.cc \ + pk11_pbkdf2_unittest.cc \ + pk11_prf_unittest.cc \ + pk11_prng_unittest.cc \ + pk11_rsaencrypt_unittest.cc \ + pk11_rsaoaep_unittest.cc \ + pk11_rsapkcs1_unittest.cc \ + pk11_rsapss_unittest.cc \ + pk11_seed_cbc_unittest.cc \ + $(NULL) + +DEFINES += -DDLL_PREFIX=\"$(DLL_PREFIX)\" -DDLL_SUFFIX=\"$(DLL_SUFFIX)\" + +INCLUDES += -I$(CORE_DEPTH)/gtests/google_test/gtest/include \ + -I$(CORE_DEPTH)/gtests/common \ + -I$(CORE_DEPTH)/cpputil + +REQUIRES = nspr nss libdbm gtest cpputil + +PROGRAM = pk11_gtest + +EXTRA_LIBS = $(DIST)/lib/$(LIB_PREFIX)gtest.$(LIB_SUFFIX) \ + $(DIST)/lib/$(LIB_PREFIX)cpputil.$(LIB_SUFFIX) \ + $(DIST)/lib/$(LIB_PREFIX)gtestutil.$(LIB_SUFFIX) \ + $(NULL) diff --git a/security/nss/gtests/pk11_gtest/pk11_aes_cmac_unittest.cc b/security/nss/gtests/pk11_gtest/pk11_aes_cmac_unittest.cc new file mode 100644 index 0000000000..f960e58c37 --- /dev/null +++ b/security/nss/gtests/pk11_gtest/pk11_aes_cmac_unittest.cc @@ -0,0 +1,130 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include <memory> +#include "nss.h" +#include "pk11pub.h" +#include "secerr.h" +#include "sechash.h" + +#include "blapi.h" + +#include "gtest/gtest.h" +#include "nss_scoped_ptrs.h" +#include "testvectors/cmac-vectors.h" +#include "util.h" + +namespace nss_test { + +class Pkcs11AesCmacTest : public ::testing::TestWithParam<AesCmacTestVector> { + protected: + ScopedPK11SymKey ImportKey(CK_MECHANISM_TYPE mech, SECItem *key_item) { + ScopedPK11SlotInfo slot(PK11_GetInternalSlot()); + if (!slot) { + ADD_FAILURE() << "Can't get slot"; + return nullptr; + } + + ScopedPK11SymKey result(PK11_ImportSymKey( + slot.get(), mech, PK11_OriginUnwrap, CKA_SIGN, key_item, nullptr)); + + return result; + } + + void RunTest(uint8_t *key, unsigned int key_len, uint8_t *data, + unsigned int data_len, uint8_t *expected, + unsigned int expected_len, CK_ULONG mechanism) { + // Create SECItems for everything... + std::vector<uint8_t> output(expected_len); + SECItem key_item = {siBuffer, key, key_len}; + SECItem output_item = {siBuffer, output.data(), expected_len}; + SECItem data_item = {siBuffer, data, data_len}; + SECItem expected_item = {siBuffer, expected, expected_len}; + + // Do the PKCS #11 stuff... + ScopedPK11SymKey p11_key = ImportKey(mechanism, &key_item); + ASSERT_NE(nullptr, p11_key.get()); + + SECStatus ret = PK11_SignWithSymKey(p11_key.get(), CKM_AES_CMAC, NULL, + &output_item, &data_item); + + // Verify the result... + ASSERT_EQ(SECSuccess, ret); + ASSERT_EQ(0, SECITEM_CompareItem(&output_item, &expected_item)); + } + + void RunTestVector(const AesCmacTestVector vec) { + bool valid = !vec.invalid; + std::string err = "Test #" + std::to_string(vec.id) + " failed"; + std::vector<uint8_t> key = hex_string_to_bytes(vec.key); + std::vector<uint8_t> tag = hex_string_to_bytes(vec.tag); + std::vector<uint8_t> msg = hex_string_to_bytes(vec.msg); + + std::vector<uint8_t> output(AES_BLOCK_SIZE); + // Don't provide a null pointer, even if the input is empty. + uint8_t tmp; + SECItem key_item = {siBuffer, key.data() ? key.data() : &tmp, + static_cast<unsigned int>(key.size())}; + SECItem tag_item = {siBuffer, tag.data() ? tag.data() : &tmp, + static_cast<unsigned int>(tag.size())}; + SECItem msg_item = {siBuffer, msg.data() ? msg.data() : &tmp, + static_cast<unsigned int>(msg.size())}; + SECItem out_item = {siBuffer, output.data() ? output.data() : &tmp, + static_cast<unsigned int>(output.size())}; + + ScopedPK11SymKey p11_key = ImportKey(CKM_AES_CMAC_GENERAL, &key_item); + if (vec.comment == "invalid key size") { + ASSERT_EQ(nullptr, p11_key.get()) << err; + return; + } + + ASSERT_NE(nullptr, p11_key.get()) << err; + SECStatus rv = PK11_SignWithSymKey(p11_key.get(), CKM_AES_CMAC, NULL, + &out_item, &msg_item); + + EXPECT_EQ(SECSuccess, rv) << err; + EXPECT_EQ(valid, 0 == SECITEM_CompareItem(&out_item, &tag_item)) << err; + } +}; + +TEST_P(Pkcs11AesCmacTest, TestVectors) { RunTestVector(GetParam()); } + +INSTANTIATE_TEST_SUITE_P(WycheproofTestVector, Pkcs11AesCmacTest, + ::testing::ValuesIn(kCmacWycheproofVectors)); + +// Sanity check of the PKCS #11 API only. Extensive tests for correctness of +// underling CMAC implementation conducted in the following file: +// gtests/freebl_gtest/cmac_unittests.cc + +TEST_F(Pkcs11AesCmacTest, Aes128NistExample1) { + uint8_t key[AES_128_KEY_LENGTH] = {0x2B, 0x7E, 0x15, 0x16, 0x28, 0xAE, + 0xD2, 0xA6, 0xAB, 0xF7, 0x15, 0x88, + 0x09, 0xCF, 0x4F, 0x3C}; + uint8_t known[AES_BLOCK_SIZE] = {0xBB, 0x1D, 0x69, 0x29, 0xE9, 0x59, + 0x37, 0x28, 0x7F, 0xA3, 0x7D, 0x12, + 0x9B, 0x75, 0x67, 0x46}; + + RunTest(key, AES_128_KEY_LENGTH, NULL, 0, known, AES_BLOCK_SIZE, + CKM_AES_CMAC); +} + +TEST_F(Pkcs11AesCmacTest, General) { + uint8_t key[AES_128_KEY_LENGTH] = {0x2B, 0x7E, 0x15, 0x16, 0x28, 0xAE, + 0xD2, 0xA6, 0xAB, 0xF7, 0x15, 0x88, + 0x09, 0xCF, 0x4F, 0x3C}; + uint8_t known[4] = {0xBB, 0x1D, 0x69, 0x29}; + + RunTest(key, AES_128_KEY_LENGTH, NULL, 0, known, 4, CKM_AES_CMAC_GENERAL); +} + +TEST_F(Pkcs11AesCmacTest, InvalidKeySize) { + uint8_t key[4] = {0x00, 0x00, 0x00, 0x00}; + SECItem key_item = {siBuffer, key, 4}; + + ScopedPK11SymKey result = ImportKey(CKM_AES_CMAC, &key_item); + ASSERT_EQ(nullptr, result.get()); +} +} // namespace nss_test diff --git a/security/nss/gtests/pk11_gtest/pk11_aes_gcm_unittest.cc b/security/nss/gtests/pk11_gtest/pk11_aes_gcm_unittest.cc new file mode 100644 index 0000000000..211da288d6 --- /dev/null +++ b/security/nss/gtests/pk11_gtest/pk11_aes_gcm_unittest.cc @@ -0,0 +1,428 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include <memory> +#include "nss.h" +#include "pk11pub.h" +#include "pk11priv.h" +#include "secerr.h" +#include "sechash.h" + +#include "nss_scoped_ptrs.h" + +#include "testvectors/gcm-vectors.h" +#include "gtest/gtest.h" +#include "util.h" + +namespace nss_test { + +class Pkcs11AesGcmTest : public ::testing::TestWithParam<AesGcmKatValue> { + protected: + void RunTest(const AesGcmKatValue vec) { + std::vector<uint8_t> key = hex_string_to_bytes(vec.key); + std::vector<uint8_t> iv = hex_string_to_bytes(vec.iv); + std::vector<uint8_t> plaintext = hex_string_to_bytes(vec.plaintext); + std::vector<uint8_t> aad = hex_string_to_bytes(vec.additional_data); + std::vector<uint8_t> result = hex_string_to_bytes(vec.result); + bool invalid_ct = vec.invalid_ct; + bool invalid_iv = vec.invalid_iv; + std::string msg = "Test #" + std::to_string(vec.id) + " failed"; + // Ignore GHASH-only vectors. + if (key.empty()) { + return; + } + + // Prepare AEAD params. + CK_NSS_GCM_PARAMS gcm_params; + gcm_params.pIv = iv.data(); + gcm_params.ulIvLen = iv.size(); + gcm_params.pAAD = aad.data(); + gcm_params.ulAADLen = aad.size(); + gcm_params.ulTagBits = 128; + + SECItem params = {siBuffer, reinterpret_cast<unsigned char*>(&gcm_params), + sizeof(gcm_params)}; + + ScopedPK11SlotInfo slot(PK11_GetInternalSlot()); + SECItem key_item = {siBuffer, key.data(), + static_cast<unsigned int>(key.size())}; + + // Import key. + ScopedPK11SymKey sym_key(PK11_ImportSymKey( + slot.get(), mech, PK11_OriginUnwrap, CKA_ENCRYPT, &key_item, nullptr)); + ASSERT_TRUE(!!sym_key) << msg; + + // Encrypt with bogus parameters. + unsigned int output_len = 0; + std::vector<uint8_t> output(plaintext.size() + gcm_params.ulTagBits / 8); + // "maxout" must be at least "inlen + tagBytes", or, in this case: + // "output.size()" must be at least "plaintext.size() + tagBytes" + gcm_params.ulTagBits = 128; + SECStatus rv = + PK11_Encrypt(sym_key.get(), mech, ¶ms, output.data(), &output_len, + output.size() - 10, plaintext.data(), plaintext.size()); + EXPECT_EQ(SECFailure, rv); + EXPECT_EQ(0U, output_len); + + // The valid values for tag size in AES_GCM are: + // 32, 64, 96, 104, 112, 120 and 128. + gcm_params.ulTagBits = 110; + rv = PK11_Encrypt(sym_key.get(), mech, ¶ms, output.data(), &output_len, + output.size(), plaintext.data(), plaintext.size()); + EXPECT_EQ(SECFailure, rv); + EXPECT_EQ(0U, output_len); + + // Encrypt. + gcm_params.ulTagBits = 128; + rv = PK11_Encrypt(sym_key.get(), mech, ¶ms, output.data(), &output_len, + output.size(), plaintext.data(), plaintext.size()); + if (invalid_iv) { + EXPECT_EQ(SECFailure, rv) << msg; + EXPECT_EQ(0U, output_len); + return; + } + EXPECT_EQ(SECSuccess, rv) << msg; + + ASSERT_EQ(output_len, output.size()) << msg; + + // Check ciphertext and tag. + if (invalid_ct) { + EXPECT_NE(result, output) << msg; + } else { + EXPECT_EQ(result, output) << msg; + } + + // Decrypt. + unsigned int decrypted_len = 0; + // The PK11 AES API is stupid, it expects an explicit IV and thus wants + // a block more of available output memory. + std::vector<uint8_t> decrypted(output.size()); + rv = PK11_Decrypt(sym_key.get(), mech, ¶ms, decrypted.data(), + &decrypted_len, decrypted.size(), output.data(), + output_len); + EXPECT_EQ(SECSuccess, rv) << msg; + ASSERT_EQ(decrypted_len, plaintext.size()) << msg; + + // Check the plaintext. + EXPECT_EQ(plaintext, + std::vector<uint8_t>(decrypted.begin(), + decrypted.begin() + decrypted_len)) + << msg; + } + + SECStatus EncryptWithIV(std::vector<uint8_t>& iv) { + // Generate a random key. + ScopedPK11SlotInfo slot(PK11_GetInternalSlot()); + ScopedPK11SymKey sym_key( + PK11_KeyGen(slot.get(), mech, nullptr, 16, nullptr)); + EXPECT_TRUE(!!sym_key); + + std::vector<uint8_t> data(17); + std::vector<uint8_t> output(33); + std::vector<uint8_t> aad(0); + + // Prepare AEAD params. + CK_NSS_GCM_PARAMS gcm_params; + gcm_params.pIv = iv.data(); + gcm_params.ulIvLen = iv.size(); + gcm_params.pAAD = aad.data(); + gcm_params.ulAADLen = aad.size(); + gcm_params.ulTagBits = 128; + + SECItem params = {siBuffer, reinterpret_cast<unsigned char*>(&gcm_params), + sizeof(gcm_params)}; + + // Try to encrypt. + unsigned int output_len = 0; + return PK11_Encrypt(sym_key.get(), mech, ¶ms, output.data(), + &output_len, output.size(), data.data(), data.size()); + } + + SECStatus MessageInterfaceTest(int iterations, int ivFixedBits, + CK_GENERATOR_FUNCTION ivGen, + PRBool separateTag) { + // Generate a random key. + ScopedPK11SlotInfo slot(PK11_GetInternalSlot()); + EXPECT_NE(nullptr, slot); + ScopedPK11SymKey sym_key( + PK11_KeyGen(slot.get(), mech, nullptr, 16, nullptr)); + EXPECT_NE(nullptr, sym_key); + + const int kTagSize = 16; + int cipher_simulated_size; + int output_len_message = 0; + int output_len_simulated = 0; + unsigned int output_len_v24 = 0; + + std::vector<uint8_t> plainIn(17); + std::vector<uint8_t> plainOut_message(17); + std::vector<uint8_t> plainOut_simulated(17); + std::vector<uint8_t> plainOut_v24(17); + std::vector<uint8_t> iv(16); + std::vector<uint8_t> iv_init(16); + std::vector<uint8_t> iv_simulated(16); + std::vector<uint8_t> cipher_message(33); + std::vector<uint8_t> cipher_simulated(33); + std::vector<uint8_t> cipher_v24(33); + std::vector<uint8_t> aad(16); + std::vector<uint8_t> tag_message(16); + std::vector<uint8_t> tag_simulated(16); + + // Prepare AEAD v2.40 params. + CK_GCM_PARAMS_V3 gcm_params; + gcm_params.pIv = iv.data(); + gcm_params.ulIvLen = iv.size(); + gcm_params.ulIvBits = iv.size() * 8; + gcm_params.pAAD = aad.data(); + gcm_params.ulAADLen = aad.size(); + gcm_params.ulTagBits = kTagSize * 8; + + // Prepare AEAD MESSAGE params. + CK_GCM_MESSAGE_PARAMS gcm_message_params; + gcm_message_params.pIv = iv.data(); + gcm_message_params.ulIvLen = iv.size(); + gcm_message_params.ulTagBits = kTagSize * 8; + gcm_message_params.ulIvFixedBits = ivFixedBits; + gcm_message_params.ivGenerator = ivGen; + if (separateTag) { + gcm_message_params.pTag = tag_message.data(); + } else { + gcm_message_params.pTag = cipher_message.data() + plainIn.size(); + } + + // Prepare AEAD MESSAGE params for simulated case + CK_GCM_MESSAGE_PARAMS gcm_simulated_params; + gcm_simulated_params = gcm_message_params; + if (separateTag) { + // The simulated case, we have to allocate temp bufs for separate + // tags, make sure that works in both the encrypt and the decrypt + // cases. + gcm_simulated_params.pTag = tag_simulated.data(); + cipher_simulated_size = cipher_simulated.size() - kTagSize; + } else { + gcm_simulated_params.pTag = cipher_simulated.data() + plainIn.size(); + cipher_simulated_size = cipher_simulated.size(); + } + /* when we are using CKG_GENERATE_RANDOM, don't independently generate + * the IV in the simulated case. Since the IV's would be random, none of + * the generated results would be the same. Just use the IV we generated + * in message interface */ + if (ivGen == CKG_GENERATE_RANDOM) { + gcm_simulated_params.ivGenerator = CKG_NO_GENERATE; + } else { + gcm_simulated_params.pIv = iv_simulated.data(); + } + + SECItem params = {siBuffer, reinterpret_cast<unsigned char*>(&gcm_params), + sizeof(gcm_params)}; + SECItem empty = {siBuffer, NULL, 0}; + + // initialize our plain text, IV and aad. + EXPECT_EQ(PK11_GenerateRandom(plainIn.data(), plainIn.size()), SECSuccess); + EXPECT_EQ(PK11_GenerateRandom(aad.data(), aad.size()), SECSuccess); + EXPECT_EQ(PK11_GenerateRandom(iv_init.data(), iv_init.size()), SECSuccess); + iv_simulated = iv_init; // vector assignment actually copies data + iv = iv_init; + + // Initialize message encrypt context + ScopedPK11Context encrypt_message_context(PK11_CreateContextBySymKey( + mech, CKA_NSS_MESSAGE | CKA_ENCRYPT, sym_key.get(), &empty)); + EXPECT_NE(nullptr, encrypt_message_context); + if (!encrypt_message_context) { + return SECFailure; + } + EXPECT_FALSE(_PK11_ContextGetAEADSimulation(encrypt_message_context.get())); + + // Initialize simulated encrypt context + ScopedPK11Context encrypt_simulated_context(PK11_CreateContextBySymKey( + mech, CKA_NSS_MESSAGE | CKA_ENCRYPT, sym_key.get(), &empty)); + EXPECT_NE(nullptr, encrypt_simulated_context); + if (!encrypt_simulated_context) { + return SECFailure; + } + EXPECT_EQ(SECSuccess, + _PK11_ContextSetAEADSimulation(encrypt_simulated_context.get())); + + // Initialize message decrypt context + ScopedPK11Context decrypt_message_context(PK11_CreateContextBySymKey( + mech, CKA_NSS_MESSAGE | CKA_DECRYPT, sym_key.get(), &empty)); + EXPECT_NE(nullptr, decrypt_message_context); + if (!decrypt_message_context) { + return SECFailure; + } + EXPECT_FALSE(_PK11_ContextGetAEADSimulation(decrypt_message_context.get())); + + // Initialize simulated decrypt context + ScopedPK11Context decrypt_simulated_context(PK11_CreateContextBySymKey( + mech, CKA_NSS_MESSAGE | CKA_DECRYPT, sym_key.get(), &empty)); + EXPECT_NE(nullptr, decrypt_simulated_context); + if (!decrypt_simulated_context) { + return SECFailure; + } + EXPECT_EQ(SECSuccess, + _PK11_ContextSetAEADSimulation(decrypt_simulated_context.get())); + + // Now walk down our iterations. Each method of calculating the operation + // should agree at each step. + for (int i = 0; i < iterations; i++) { + SECStatus rv; + /* recopy the initial vector each time */ + iv_simulated = iv_init; + iv = iv_init; + + // First encrypt. We don't test the error code here, because + // we may be testing error conditions with this function (namely + // do we fail if we try to generate to many Random IV's). + rv = + PK11_AEADRawOp(encrypt_message_context.get(), &gcm_message_params, + sizeof(gcm_message_params), aad.data(), aad.size(), + cipher_message.data(), &output_len_message, + cipher_message.size(), plainIn.data(), plainIn.size()); + if (rv != SECSuccess) { + return rv; + } + rv = + PK11_AEADRawOp(encrypt_simulated_context.get(), &gcm_simulated_params, + sizeof(gcm_simulated_params), aad.data(), aad.size(), + cipher_simulated.data(), &output_len_simulated, + cipher_simulated_size, plainIn.data(), plainIn.size()); + if (rv != SECSuccess) { + return rv; + } + // make sure simulated and message is the same + EXPECT_EQ(output_len_message, output_len_simulated); + EXPECT_EQ(0, memcmp(cipher_message.data(), cipher_simulated.data(), + output_len_message)); + EXPECT_EQ(0, memcmp(gcm_message_params.pTag, gcm_simulated_params.pTag, + kTagSize)); + EXPECT_EQ(0, memcmp(iv.data(), gcm_simulated_params.pIv, iv.size())); + // make sure v2.40 is the same. it inherits the generated iv from + // encrypt_message_context. + EXPECT_EQ(SECSuccess, + PK11_Encrypt(sym_key.get(), mech, ¶ms, cipher_v24.data(), + &output_len_v24, cipher_v24.size(), plainIn.data(), + plainIn.size())); + EXPECT_EQ(output_len_message, (int)output_len_v24 - kTagSize); + EXPECT_EQ(0, memcmp(cipher_message.data(), cipher_v24.data(), + output_len_message)); + EXPECT_EQ(0, memcmp(gcm_message_params.pTag, + cipher_v24.data() + output_len_message, kTagSize)); + // now make sure we can decrypt + EXPECT_EQ(SECSuccess, + PK11_AEADRawOp(decrypt_message_context.get(), + &gcm_message_params, sizeof(gcm_message_params), + aad.data(), aad.size(), plainOut_message.data(), + &output_len_message, plainOut_message.size(), + cipher_message.data(), output_len_message)); + EXPECT_EQ(output_len_message, (int)plainIn.size()); + EXPECT_EQ( + 0, memcmp(plainOut_message.data(), plainIn.data(), plainIn.size())); + EXPECT_EQ( + SECSuccess, + PK11_AEADRawOp(decrypt_simulated_context.get(), &gcm_simulated_params, + sizeof(gcm_simulated_params), aad.data(), aad.size(), + plainOut_simulated.data(), &output_len_simulated, + plainOut_simulated.size(), cipher_message.data(), + output_len_simulated)); + EXPECT_EQ(output_len_simulated, (int)plainIn.size()); + EXPECT_EQ( + 0, memcmp(plainOut_simulated.data(), plainIn.data(), plainIn.size())); + if (separateTag) { + // in the separateTag case, we need to copy the tag back to the + // end of the cipher_message.data() before using the v2.4 interface + memcpy(cipher_message.data() + output_len_message, + gcm_message_params.pTag, kTagSize); + } + EXPECT_EQ(SECSuccess, + PK11_Decrypt(sym_key.get(), mech, ¶ms, plainOut_v24.data(), + &output_len_v24, plainOut_v24.size(), + cipher_message.data(), output_len_v24)); + EXPECT_EQ(output_len_v24, plainIn.size()); + EXPECT_EQ(0, memcmp(plainOut_v24.data(), plainIn.data(), plainIn.size())); + } + return SECSuccess; + } + + const CK_MECHANISM_TYPE mech = CKM_AES_GCM; +}; + +TEST_P(Pkcs11AesGcmTest, TestVectors) { RunTest(GetParam()); } + +INSTANTIATE_TEST_SUITE_P(NISTTestVector, Pkcs11AesGcmTest, + ::testing::ValuesIn(kGcmKatValues)); + +INSTANTIATE_TEST_SUITE_P(WycheproofTestVector, Pkcs11AesGcmTest, + ::testing::ValuesIn(kGcmWycheproofVectors)); + +TEST_F(Pkcs11AesGcmTest, ZeroLengthIV) { + std::vector<uint8_t> iv(0); + EXPECT_EQ(SECFailure, EncryptWithIV(iv)); +} + +TEST_F(Pkcs11AesGcmTest, AllZeroIV) { + std::vector<uint8_t> iv(16, 0); + EXPECT_EQ(SECSuccess, EncryptWithIV(iv)); +} + +TEST_F(Pkcs11AesGcmTest, TwelveByteZeroIV) { + std::vector<uint8_t> iv(12, 0); + EXPECT_EQ(SECSuccess, EncryptWithIV(iv)); +} + +// basic message interface it's the most common configuration +TEST_F(Pkcs11AesGcmTest, MessageInterfaceBasic) { + EXPECT_EQ(SECSuccess, + MessageInterfaceTest(16, 0, CKG_GENERATE_COUNTER, PR_FALSE)); +} + +// basic interface, but return the tags in a separate buffer. This triggers +// different behaviour in the simulated case, which has to buffer the +// intermediate values in a separate buffer. +TEST_F(Pkcs11AesGcmTest, MessageInterfaceSeparateTags) { + EXPECT_EQ(SECSuccess, + MessageInterfaceTest(16, 0, CKG_GENERATE_COUNTER, PR_TRUE)); +} + +// test the case where we are only allowing a portion of the iv to be generated +TEST_F(Pkcs11AesGcmTest, MessageInterfaceIVMask) { + EXPECT_EQ(SECSuccess, + MessageInterfaceTest(16, 124, CKG_GENERATE_COUNTER, PR_FALSE)); +} + +// test the case where we using the tls1.3 iv generation +TEST_F(Pkcs11AesGcmTest, MessageInterfaceXorCounter) { + EXPECT_EQ(SECSuccess, + MessageInterfaceTest(16, 0, CKG_GENERATE_COUNTER_XOR, PR_FALSE)); +} + +// test the case where we overflow the counter (requires restricted iv) +// 128-124 = 4 bits; +TEST_F(Pkcs11AesGcmTest, MessageInterfaceCounterOverflow) { + EXPECT_EQ(SECFailure, + MessageInterfaceTest(17, 124, CKG_GENERATE_COUNTER, PR_FALSE)); +} + +// overflow the tla1.2 iv case +TEST_F(Pkcs11AesGcmTest, MessageInterfaceXorCounterOverflow) { + EXPECT_EQ(SECFailure, + MessageInterfaceTest(17, 124, CKG_GENERATE_COUNTER_XOR, PR_FALSE)); +} + +// test random generation of the IV (uses an aligned restricted iv) +TEST_F(Pkcs11AesGcmTest, MessageInterfaceRandomIV) { + EXPECT_EQ(SECSuccess, + MessageInterfaceTest(16, 56, CKG_GENERATE_RANDOM, PR_FALSE)); +} + +// test the case where we try to generate too many random IVs for the size of +// our our restricted IV (notice for counters, we can generate 16 IV with +// 4 bits, but for random we need at least 72 bits to generate 16 IVs). +// 128-56 = 72 bits +TEST_F(Pkcs11AesGcmTest, MessageInterfaceRandomOverflow) { + EXPECT_EQ(SECFailure, + MessageInterfaceTest(17, 56, CKG_GENERATE_RANDOM, PR_FALSE)); +} +} // namespace nss_test diff --git a/security/nss/gtests/pk11_gtest/pk11_aeskeywrap_unittest.cc b/security/nss/gtests/pk11_gtest/pk11_aeskeywrap_unittest.cc new file mode 100644 index 0000000000..ebd762ca65 --- /dev/null +++ b/security/nss/gtests/pk11_gtest/pk11_aeskeywrap_unittest.cc @@ -0,0 +1,122 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include <memory> +#include "nss.h" +#include "pk11pub.h" + +#include "testvectors/kw-vectors.h" +#include "gtest/gtest.h" +#include "nss_scoped_ptrs.h" + +namespace nss_test { + +class Pkcs11AESKeyWrapTest : public ::testing::TestWithParam<keywrap_vector> { + protected: + CK_MECHANISM_TYPE mechanism = CKM_NSS_AES_KEY_WRAP; + + void WrapUnwrap(unsigned char* kek_data, unsigned int kek_len, + unsigned char* key_data, unsigned int key_data_len, + unsigned char* expected_ciphertext, + unsigned int expected_ciphertext_len, + std::map<Action, Result> tests, uint32_t test_id) { + std::vector<unsigned char> wrapped_key(PR_MAX(1U, expected_ciphertext_len)); + std::vector<unsigned char> unwrapped_key(PR_MAX(1U, key_data_len)); + std::vector<unsigned char> zeros(PR_MAX(1U, expected_ciphertext_len)); + std::fill(zeros.begin(), zeros.end(), 0); + unsigned int wrapped_key_len = 0; + unsigned int unwrapped_key_len = 0; + SECStatus rv; + + std::stringstream s; + s << "Test with original ID #" << test_id << " failed." << std::endl; + std::string msg = s.str(); + + ScopedPK11SlotInfo slot(PK11_GetInternalSlot()); + ASSERT_NE(nullptr, slot) << msg; + + // Import encryption key. + SECItem kek_item = {siBuffer, kek_data, kek_len}; + ScopedPK11SymKey kek(PK11_ImportSymKey(slot.get(), CKM_NSS_AES_KEY_WRAP, + PK11_OriginUnwrap, CKA_ENCRYPT, + &kek_item, nullptr)); + EXPECT_TRUE(!!kek) << msg; + + // Wrap key + Action test = WRAP; + if (tests.count(test)) { + rv = PK11_Encrypt(kek.get(), mechanism, nullptr /* param */, + wrapped_key.data(), &wrapped_key_len, + wrapped_key.size(), key_data, key_data_len); + ASSERT_EQ(rv, tests[test].expect_rv) << msg; + + // If we failed, check that output was not produced. + if (rv == SECFailure) { + EXPECT_TRUE(wrapped_key_len == 0); + EXPECT_TRUE(!memcmp(wrapped_key.data(), zeros.data(), wrapped_key_len)); + } + + if (tests[test].output_match) { + EXPECT_EQ(expected_ciphertext_len, wrapped_key_len) << msg; + EXPECT_TRUE(!memcmp(expected_ciphertext, wrapped_key.data(), + expected_ciphertext_len)) + << msg; + } else { + // If we produced output, verify that it doesn't match the vector + if (wrapped_key_len) { + EXPECT_FALSE(wrapped_key_len == expected_ciphertext_len && + !memcmp(wrapped_key.data(), expected_ciphertext, + expected_ciphertext_len)) + << msg; + } + } + } + + // Unwrap key + test = UNWRAP; + if (tests.count(test)) { + rv = PK11_Decrypt(kek.get(), mechanism, nullptr /* param */, + unwrapped_key.data(), &unwrapped_key_len, + unwrapped_key.size(), expected_ciphertext, + expected_ciphertext_len); + ASSERT_EQ(rv, tests[test].expect_rv) << msg; + + // If we failed, check that output was not produced. + if (rv == SECFailure) { + EXPECT_TRUE(unwrapped_key_len == 0); + EXPECT_TRUE( + !memcmp(unwrapped_key.data(), zeros.data(), unwrapped_key_len)); + } + + if (tests[test].output_match) { + EXPECT_EQ(unwrapped_key_len, key_data_len) << msg; + EXPECT_TRUE(!memcmp(key_data, unwrapped_key.data(), key_data_len)) + << msg; + } else { + // If we produced output, verify that it doesn't match the vector + if (unwrapped_key_len) { + EXPECT_FALSE( + unwrapped_key_len == expected_ciphertext_len && + !memcmp(unwrapped_key.data(), key_data, unwrapped_key_len)) + << msg; + } + } + } + } + + void WrapUnwrap(keywrap_vector testvector) { + WrapUnwrap(testvector.key.data(), testvector.key.size(), + testvector.msg.data(), testvector.msg.size(), + testvector.ct.data(), testvector.ct.size(), testvector.tests, + testvector.test_id); + } +}; + +TEST_P(Pkcs11AESKeyWrapTest, TestVectors) { WrapUnwrap(GetParam()); } + +INSTANTIATE_TEST_SUITE_P(Pkcs11WycheproofAESKWTest, Pkcs11AESKeyWrapTest, + ::testing::ValuesIn(kWycheproofAesKWVectors)); +} /* nss_test */ diff --git a/security/nss/gtests/pk11_gtest/pk11_aeskeywrapkwp_unittest.cc b/security/nss/gtests/pk11_gtest/pk11_aeskeywrapkwp_unittest.cc new file mode 100644 index 0000000000..c7e27a75c9 --- /dev/null +++ b/security/nss/gtests/pk11_gtest/pk11_aeskeywrapkwp_unittest.cc @@ -0,0 +1,123 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include <memory> +#include "nss.h" +#include "pk11pub.h" + +#include "testvectors/kw-vectors.h" +#include "testvectors/kwp-vectors.h" +#include "gtest/gtest.h" +#include "nss_scoped_ptrs.h" + +namespace nss_test { + +class Pkcs11AESKeyWrapKwpTest + : public ::testing::TestWithParam<keywrap_vector> { + protected: + CK_MECHANISM_TYPE mechanism = CKM_AES_KEY_WRAP_KWP; + + void WrapUnwrap(unsigned char* kek_data, unsigned int kek_len, + unsigned char* key_data, unsigned int key_data_len, + unsigned char* expected_ciphertext, + unsigned int expected_ciphertext_len, + std::map<Action, Result> tests, uint32_t test_id) { + std::vector<unsigned char> wrapped_key(PR_MAX(1U, expected_ciphertext_len)); + std::vector<unsigned char> unwrapped_key(PR_MAX(1U, key_data_len)); + std::vector<unsigned char> zeros(PR_MAX(1U, expected_ciphertext_len), 0); + unsigned int wrapped_key_len = 0; + unsigned int unwrapped_key_len = 0; + SECStatus rv; + + std::stringstream s; + s << "Test with original ID #" << test_id << " failed." << std::endl; + std::string msg = s.str(); + + ScopedPK11SlotInfo slot(PK11_GetInternalSlot()); + ASSERT_NE(nullptr, slot) << msg; + + // Import encryption key. + SECItem kek_item = {siBuffer, kek_data, kek_len}; + ScopedPK11SymKey kek(PK11_ImportSymKeyWithFlags( + slot.get(), mechanism, PK11_OriginUnwrap, CKA_ENCRYPT, &kek_item, + CKF_DECRYPT, PR_FALSE, nullptr)); + EXPECT_TRUE(!!kek) << msg; + + // Wrap key + Action test = WRAP; + if (tests.count(test)) { + rv = PK11_Encrypt(kek.get(), mechanism, nullptr /* param */, + wrapped_key.data(), &wrapped_key_len, + wrapped_key.size(), key_data, key_data_len); + ASSERT_EQ(rv, tests[test].expect_rv) << msg; + + // If we failed, check that output was not produced. + if (rv == SECFailure) { + EXPECT_TRUE(wrapped_key_len == 0); + EXPECT_TRUE(!memcmp(wrapped_key.data(), zeros.data(), wrapped_key_len)); + } + + if (tests[test].output_match) { + EXPECT_EQ(expected_ciphertext_len, wrapped_key_len) << msg; + EXPECT_TRUE(!memcmp(expected_ciphertext, wrapped_key.data(), + expected_ciphertext_len)) + << msg; + } else { + // If we produced output, verify that it doesn't match the vector + if (wrapped_key_len) { + EXPECT_FALSE(wrapped_key_len == expected_ciphertext_len && + !memcmp(wrapped_key.data(), expected_ciphertext, + expected_ciphertext_len)) + << msg; + } + } + } + + // Unwrap key + test = UNWRAP; + if (tests.count(test)) { + rv = PK11_Decrypt(kek.get(), mechanism, nullptr /* param */, + unwrapped_key.data(), &unwrapped_key_len, + unwrapped_key.size(), expected_ciphertext, + expected_ciphertext_len); + ASSERT_EQ(rv, tests[test].expect_rv) << msg; + + // If we failed, check that output was not produced. + if (rv == SECFailure) { + EXPECT_TRUE(unwrapped_key_len == 0); + EXPECT_TRUE( + !memcmp(unwrapped_key.data(), zeros.data(), unwrapped_key_len)); + } + + if (tests[test].output_match) { + EXPECT_EQ(unwrapped_key_len, key_data_len) << msg; + EXPECT_TRUE(!memcmp(key_data, unwrapped_key.data(), key_data_len)) + << msg; + } else { + // If we produced output, verify that it doesn't match the vector + if (unwrapped_key_len) { + EXPECT_FALSE( + unwrapped_key_len == expected_ciphertext_len && + !memcmp(unwrapped_key.data(), key_data, unwrapped_key_len)) + << msg; + } + } + } + } + + void WrapUnwrap(keywrap_vector testvector) { + WrapUnwrap(testvector.key.data(), testvector.key.size(), + testvector.msg.data(), testvector.msg.size(), + testvector.ct.data(), testvector.ct.size(), testvector.tests, + testvector.test_id); + } +}; + +TEST_P(Pkcs11AESKeyWrapKwpTest, TestVectors) { WrapUnwrap(GetParam()); } + +INSTANTIATE_TEST_SUITE_P(Pkcs11NistAESKWPTest, Pkcs11AESKeyWrapKwpTest, + ::testing::ValuesIn(kNistAesKWPVectors)); +} /* nss_test */ diff --git a/security/nss/gtests/pk11_gtest/pk11_aeskeywrappad_unittest.cc b/security/nss/gtests/pk11_gtest/pk11_aeskeywrappad_unittest.cc new file mode 100644 index 0000000000..ef78f7b0e2 --- /dev/null +++ b/security/nss/gtests/pk11_gtest/pk11_aeskeywrappad_unittest.cc @@ -0,0 +1,423 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include <memory> +#include "gtest/gtest.h" +#include "nss.h" +#include "nss_scoped_ptrs.h" +#include "pk11pub.h" + +namespace nss_test { + +class Pkcs11AESKeyWrapPadTest : public ::testing::Test {}; + +// Encrypt an ephemeral EC key (U2F use case) +TEST_F(Pkcs11AESKeyWrapPadTest, WrapUnwrapECKey) { + const uint32_t kwrappedBufLen = 256; + const uint32_t kPublicKeyLen = 65; + const uint32_t kOidLen = 65; + unsigned char param_buf[kOidLen]; + unsigned char unwrap_buf[kPublicKeyLen]; + + ScopedPK11SlotInfo slot(PK11_GetInternalSlot()); + ASSERT_NE(nullptr, slot); + + SECItem ecdsa_params = {siBuffer, param_buf, sizeof(param_buf)}; + SECOidData* oid_data = SECOID_FindOIDByTag(SEC_OID_SECG_EC_SECP256R1); + ASSERT_NE(oid_data, nullptr); + ecdsa_params.data[0] = SEC_ASN1_OBJECT_ID; + ecdsa_params.data[1] = oid_data->oid.len; + memcpy(ecdsa_params.data + 2, oid_data->oid.data, oid_data->oid.len); + ecdsa_params.len = oid_data->oid.len + 2; + + SECKEYPublicKey* pub_tmp; + ScopedSECKEYPublicKey pub_key; + ScopedSECKEYPrivateKey priv_key( + PK11_GenerateKeyPair(slot.get(), CKM_EC_KEY_PAIR_GEN, &ecdsa_params, + &pub_tmp, PR_FALSE, PR_TRUE, nullptr)); + ASSERT_NE(nullptr, priv_key); + ASSERT_NE(nullptr, pub_tmp); + pub_key.reset(pub_tmp); + + // Generate a KEK. + ScopedPK11SymKey kek( + PK11_KeyGen(slot.get(), CKM_AES_CBC, nullptr, 16, nullptr)); + ASSERT_NE(nullptr, kek); + + // Wrap the key + ScopedSECItem wrapped(::SECITEM_AllocItem(nullptr, nullptr, kwrappedBufLen)); + ScopedSECItem param(PK11_ParamFromIV(CKM_NSS_AES_KEY_WRAP_PAD, nullptr)); + + SECStatus rv = PK11_WrapPrivKey(slot.get(), kek.get(), priv_key.get(), + CKM_NSS_AES_KEY_WRAP_PAD, param.get(), + wrapped.get(), nullptr); + ASSERT_EQ(rv, SECSuccess); + + SECItem pubKey = {siBuffer, unwrap_buf, kPublicKeyLen}; + CK_ATTRIBUTE_TYPE usages[] = {CKA_SIGN}; + int usageCount = 1; + + ScopedSECKEYPrivateKey unwrapped( + PK11_UnwrapPrivKey(slot.get(), kek.get(), CKM_NSS_AES_KEY_WRAP_PAD, + param.get(), wrapped.get(), nullptr, &pubKey, false, + true, CKK_EC, usages, usageCount, nullptr)); + ASSERT_EQ(0, PORT_GetError()); + ASSERT_TRUE(!!unwrapped); + + // Try it with internal params allocation. + SECKEYPrivateKey* tmp = PK11_UnwrapPrivKey( + slot.get(), kek.get(), CKM_NSS_AES_KEY_WRAP_PAD, nullptr, wrapped.get(), + nullptr, &pubKey, false, true, CKK_EC, usages, usageCount, nullptr); + ASSERT_EQ(0, PORT_GetError()); + ASSERT_NE(nullptr, tmp); + unwrapped.reset(tmp); +} + +// Encrypt an ephemeral RSA key +TEST_F(Pkcs11AESKeyWrapPadTest, WrapUnwrapRsaKey) { + const uint32_t kwrappedBufLen = 648; + unsigned char unwrap_buf[kwrappedBufLen]; + + ScopedPK11SlotInfo slot(PK11_GetInternalSlot()); + ASSERT_NE(nullptr, slot); + + PK11RSAGenParams rsa_param; + rsa_param.keySizeInBits = 1024; + rsa_param.pe = 65537L; + + SECKEYPublicKey* pub_tmp; + ScopedSECKEYPublicKey pub_key; + ScopedSECKEYPrivateKey priv_key( + PK11_GenerateKeyPair(slot.get(), CKM_RSA_PKCS_KEY_PAIR_GEN, &rsa_param, + &pub_tmp, PR_FALSE, PR_FALSE, nullptr)); + ASSERT_NE(nullptr, priv_key); + ASSERT_NE(nullptr, pub_tmp); + pub_key.reset(pub_tmp); + + // Generate a KEK. + ScopedPK11SymKey kek( + PK11_KeyGen(slot.get(), CKM_AES_CBC, nullptr, 16, nullptr)); + ASSERT_NE(nullptr, kek); + + // Wrap the key + ScopedSECItem wrapped(::SECITEM_AllocItem(nullptr, nullptr, kwrappedBufLen)); + ScopedSECItem param(PK11_ParamFromIV(CKM_NSS_AES_KEY_WRAP_PAD, nullptr)); + + SECStatus rv = PK11_WrapPrivKey(slot.get(), kek.get(), priv_key.get(), + CKM_NSS_AES_KEY_WRAP_PAD, param.get(), + wrapped.get(), nullptr); + ASSERT_EQ(rv, SECSuccess); + + SECItem pubKey = {siBuffer, unwrap_buf, kwrappedBufLen}; + CK_ATTRIBUTE_TYPE usages[] = {CKA_SIGN}; + int usageCount = 1; + + ScopedSECKEYPrivateKey unwrapped( + PK11_UnwrapPrivKey(slot.get(), kek.get(), CKM_NSS_AES_KEY_WRAP_PAD, + param.get(), wrapped.get(), nullptr, &pubKey, false, + false, CKK_EC, usages, usageCount, nullptr)); + ASSERT_EQ(0, PORT_GetError()); + ASSERT_TRUE(!!unwrapped); + + ScopedSECItem priv_key_data( + PK11_ExportDERPrivateKeyInfo(priv_key.get(), nullptr)); + ScopedSECItem unwrapped_data( + PK11_ExportDERPrivateKeyInfo(unwrapped.get(), nullptr)); + EXPECT_TRUE(!!priv_key_data); + EXPECT_TRUE(!!unwrapped_data); + ASSERT_EQ(priv_key_data->len, unwrapped_data->len); + ASSERT_EQ( + 0, memcmp(priv_key_data->data, unwrapped_data->data, priv_key_data->len)); +} + +// Wrap a random that's a multiple of the block size, and compare the unwrap +// result. +TEST_F(Pkcs11AESKeyWrapPadTest, WrapUnwrapRandom_EvenBlock) { + const uint32_t kInputKeyLen = 128; + uint32_t out_len = 0; + std::vector<unsigned char> input_key(kInputKeyLen); + std::vector<unsigned char> wrapped_key( + kInputKeyLen + AES_BLOCK_SIZE); // One block of padding + std::vector<unsigned char> unwrapped_key( + kInputKeyLen + AES_BLOCK_SIZE); // One block of padding + + // Generate input key material + SECStatus rv = PK11_GenerateRandom(input_key.data(), input_key.size()); + EXPECT_EQ(SECSuccess, rv); + + // Generate a KEK. + ScopedPK11SlotInfo slot(PK11_GetInternalSlot()); + ASSERT_NE(nullptr, slot); + ScopedPK11SymKey kek( + PK11_KeyGen(slot.get(), CKM_AES_CBC, nullptr, 16, nullptr)); + ASSERT_NE(nullptr, kek); + + // Wrap the key + rv = PK11_Encrypt(kek.get(), CKM_NSS_AES_KEY_WRAP_PAD, /* param */ nullptr, + wrapped_key.data(), &out_len, + static_cast<unsigned int>(wrapped_key.size()), + input_key.data(), + static_cast<unsigned int>(input_key.size())); + ASSERT_EQ(SECSuccess, rv); + + rv = PK11_Decrypt(kek.get(), CKM_NSS_AES_KEY_WRAP_PAD, /* param */ nullptr, + unwrapped_key.data(), &out_len, + static_cast<unsigned int>(unwrapped_key.size()), + wrapped_key.data(), out_len); + ASSERT_EQ(SECSuccess, rv); + ASSERT_EQ(input_key.size(), out_len); + ASSERT_EQ(0, memcmp(input_key.data(), unwrapped_key.data(), out_len)); +} + +// Wrap a random that's NOT a multiple of the block size, and compare the unwrap +// result. +TEST_F(Pkcs11AESKeyWrapPadTest, WrapUnwrapRandom_OddBlock1) { + const uint32_t kInputKeyLen = 65; + uint32_t out_len = 0; + std::vector<unsigned char> input_key(kInputKeyLen); + std::vector<unsigned char> wrapped_key( + kInputKeyLen + AES_BLOCK_SIZE); // One block of padding + std::vector<unsigned char> unwrapped_key( + kInputKeyLen + AES_BLOCK_SIZE); // One block of padding + + // Generate input key material + SECStatus rv = PK11_GenerateRandom(input_key.data(), input_key.size()); + EXPECT_EQ(SECSuccess, rv); + + // Generate a KEK. + ScopedPK11SlotInfo slot(PK11_GetInternalSlot()); + ASSERT_NE(nullptr, slot); + ScopedPK11SymKey kek( + PK11_KeyGen(slot.get(), CKM_AES_CBC, nullptr, 16, nullptr)); + ASSERT_NE(nullptr, kek); + + // Wrap the key + rv = PK11_Encrypt(kek.get(), CKM_NSS_AES_KEY_WRAP_PAD, /* param */ nullptr, + wrapped_key.data(), &out_len, + static_cast<unsigned int>(wrapped_key.size()), + input_key.data(), + static_cast<unsigned int>(input_key.size())); + ASSERT_EQ(SECSuccess, rv); + + rv = PK11_Decrypt(kek.get(), CKM_NSS_AES_KEY_WRAP_PAD, /* param */ nullptr, + unwrapped_key.data(), &out_len, + static_cast<unsigned int>(unwrapped_key.size()), + wrapped_key.data(), out_len); + ASSERT_EQ(SECSuccess, rv); + ASSERT_EQ(input_key.size(), out_len); + ASSERT_EQ(0, memcmp(input_key.data(), unwrapped_key.data(), out_len)); +} + +// Wrap a random that's NOT a multiple of the block size, and compare the unwrap +// result. +TEST_F(Pkcs11AESKeyWrapPadTest, WrapUnwrapRandom_OddBlock2) { + const uint32_t kInputKeyLen = 63; + uint32_t out_len = 0; + std::vector<unsigned char> input_key(kInputKeyLen); + std::vector<unsigned char> wrapped_key( + kInputKeyLen + AES_BLOCK_SIZE); // One block of padding + std::vector<unsigned char> unwrapped_key( + kInputKeyLen + AES_BLOCK_SIZE); // One block of padding + + // Generate input key material + SECStatus rv = PK11_GenerateRandom(input_key.data(), input_key.size()); + EXPECT_EQ(SECSuccess, rv); + + // Generate a KEK. + ScopedPK11SlotInfo slot(PK11_GetInternalSlot()); + ASSERT_NE(nullptr, slot); + ScopedPK11SymKey kek( + PK11_KeyGen(slot.get(), CKM_AES_CBC, nullptr, 16, nullptr)); + ASSERT_NE(nullptr, kek); + + // Wrap the key + rv = PK11_Encrypt(kek.get(), CKM_NSS_AES_KEY_WRAP_PAD, /* param */ nullptr, + wrapped_key.data(), &out_len, wrapped_key.size(), + input_key.data(), input_key.size()); + ASSERT_EQ(SECSuccess, rv); + + rv = PK11_Decrypt(kek.get(), CKM_NSS_AES_KEY_WRAP_PAD, /* param */ nullptr, + unwrapped_key.data(), &out_len, + static_cast<unsigned int>(unwrapped_key.size()), + wrapped_key.data(), out_len); + ASSERT_EQ(SECSuccess, rv); + ASSERT_EQ(input_key.size(), out_len); + ASSERT_EQ(0, memcmp(input_key.data(), unwrapped_key.data(), out_len)); +} + +// Invalid long padding (over the block size, but otherwise valid) +TEST_F(Pkcs11AESKeyWrapPadTest, WrapUnwrapRandom_PaddingTooLong) { + const uint32_t kInputKeyLen = 32; + uint32_t out_len = 0; + + // Apply our own padding + const unsigned char buf[32] = { + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20}; + std::vector<unsigned char> wrapped_key(kInputKeyLen + AES_BLOCK_SIZE); + std::vector<unsigned char> unwrapped_key(kInputKeyLen + AES_BLOCK_SIZE); + + // Generate a KEK. + ScopedPK11SlotInfo slot(PK11_GetInternalSlot()); + ASSERT_NE(nullptr, slot); + ScopedPK11SymKey kek( + PK11_KeyGen(slot.get(), CKM_AES_CBC, nullptr, 16, nullptr)); + ASSERT_NE(nullptr, kek); + + // Wrap the key + SECStatus rv = + PK11_Encrypt(kek.get(), CKM_NSS_AES_KEY_WRAP, // Don't apply more padding + /* param */ nullptr, wrapped_key.data(), &out_len, + wrapped_key.size(), buf, sizeof(buf)); + ASSERT_EQ(SECSuccess, rv); + + rv = PK11_Decrypt(kek.get(), CKM_NSS_AES_KEY_WRAP_PAD, /* param */ nullptr, + unwrapped_key.data(), &out_len, + static_cast<unsigned int>(unwrapped_key.size()), + wrapped_key.data(), out_len); + ASSERT_EQ(SECFailure, rv); +} + +// Invalid 0-length padding (there should be a full block if the message doesn't +// need to be padded) +TEST_F(Pkcs11AESKeyWrapPadTest, WrapUnwrapRandom_NoPadding) { + const uint32_t kInputKeyLen = 32; + uint32_t out_len = 0; + + // Apply our own padding + const unsigned char buf[32] = {0}; + std::vector<unsigned char> wrapped_key(kInputKeyLen + AES_BLOCK_SIZE); + std::vector<unsigned char> unwrapped_key(kInputKeyLen + AES_BLOCK_SIZE); + + // Generate a KEK. + ScopedPK11SlotInfo slot(PK11_GetInternalSlot()); + ASSERT_NE(nullptr, slot); + ScopedPK11SymKey kek( + PK11_KeyGen(slot.get(), CKM_AES_CBC, nullptr, 16, nullptr)); + ASSERT_NE(nullptr, kek); + + // Wrap the key + SECStatus rv = + PK11_Encrypt(kek.get(), CKM_NSS_AES_KEY_WRAP, // Don't apply more padding + /* param */ nullptr, wrapped_key.data(), &out_len, + wrapped_key.size(), buf, sizeof(buf)); + ASSERT_EQ(SECSuccess, rv); + + rv = PK11_Decrypt(kek.get(), CKM_NSS_AES_KEY_WRAP_PAD, /* param */ nullptr, + unwrapped_key.data(), &out_len, + static_cast<unsigned int>(unwrapped_key.size()), + wrapped_key.data(), out_len); + ASSERT_EQ(SECFailure, rv); +} + +// Invalid padding +TEST_F(Pkcs11AESKeyWrapPadTest, WrapUnwrapRandom_BadPadding1) { + const uint32_t kInputKeyLen = 32; + uint32_t out_len = 0; + + // Apply our own padding + const unsigned char buf[32] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08}; // Check all 8 bytes + std::vector<unsigned char> wrapped_key(kInputKeyLen + AES_BLOCK_SIZE); + std::vector<unsigned char> unwrapped_key(kInputKeyLen + AES_BLOCK_SIZE); + + // Generate a KEK. + ScopedPK11SlotInfo slot(PK11_GetInternalSlot()); + ASSERT_NE(nullptr, slot); + ScopedPK11SymKey kek( + PK11_KeyGen(slot.get(), CKM_AES_CBC, nullptr, 16, nullptr)); + ASSERT_NE(nullptr, kek); + + // Wrap the key + SECStatus rv = + PK11_Encrypt(kek.get(), CKM_NSS_AES_KEY_WRAP, // Don't apply more padding + /* param */ nullptr, wrapped_key.data(), &out_len, + wrapped_key.size(), buf, sizeof(buf)); + ASSERT_EQ(SECSuccess, rv); + + rv = PK11_Decrypt(kek.get(), CKM_NSS_AES_KEY_WRAP_PAD, /* param */ nullptr, + unwrapped_key.data(), &out_len, + static_cast<unsigned int>(unwrapped_key.size()), + wrapped_key.data(), out_len); + ASSERT_EQ(SECFailure, rv); +} + +// Invalid padding +TEST_F(Pkcs11AESKeyWrapPadTest, WrapUnwrapRandom_BadPadding2) { + const uint32_t kInputKeyLen = 32; + uint32_t out_len = 0; + + // Apply our own padding + const unsigned char + buf[32] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x01, 0x02}; // Check first loop repeat + std::vector<unsigned char> wrapped_key(kInputKeyLen + AES_BLOCK_SIZE); + std::vector<unsigned char> unwrapped_key(kInputKeyLen + AES_BLOCK_SIZE); + + // Generate a KEK. + ScopedPK11SlotInfo slot(PK11_GetInternalSlot()); + ASSERT_NE(nullptr, slot); + ScopedPK11SymKey kek( + PK11_KeyGen(slot.get(), CKM_AES_CBC, nullptr, 16, nullptr)); + ASSERT_NE(nullptr, kek); + + // Wrap the key + SECStatus rv = + PK11_Encrypt(kek.get(), CKM_NSS_AES_KEY_WRAP, // Don't apply more padding + /* param */ nullptr, wrapped_key.data(), &out_len, + wrapped_key.size(), buf, sizeof(buf)); + ASSERT_EQ(SECSuccess, rv); + + rv = PK11_Decrypt(kek.get(), CKM_NSS_AES_KEY_WRAP_PAD, /* param */ nullptr, + unwrapped_key.data(), &out_len, + static_cast<unsigned int>(unwrapped_key.size()), + wrapped_key.data(), out_len); + ASSERT_EQ(SECFailure, rv); +} + +// Minimum valid padding +TEST_F(Pkcs11AESKeyWrapPadTest, WrapUnwrapRandom_ShortValidPadding) { + const uint32_t kInputKeyLen = 32; + uint32_t out_len = 0; + + // Apply our own padding + const unsigned char buf[kInputKeyLen] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01}; // Minimum + std::vector<unsigned char> wrapped_key(kInputKeyLen + AES_BLOCK_SIZE); + std::vector<unsigned char> unwrapped_key(kInputKeyLen + AES_BLOCK_SIZE); + + // Generate a KEK. + ScopedPK11SlotInfo slot(PK11_GetInternalSlot()); + ASSERT_NE(nullptr, slot); + ScopedPK11SymKey kek( + PK11_KeyGen(slot.get(), CKM_AES_CBC, nullptr, 16, nullptr)); + ASSERT_NE(nullptr, kek); + + // Wrap the key + SECStatus rv = + PK11_Encrypt(kek.get(), CKM_NSS_AES_KEY_WRAP, // Don't apply more padding + /* param */ nullptr, wrapped_key.data(), &out_len, + wrapped_key.size(), buf, sizeof(buf)); + ASSERT_EQ(SECSuccess, rv); + + rv = PK11_Decrypt(kek.get(), CKM_NSS_AES_KEY_WRAP_PAD, /* param */ nullptr, + unwrapped_key.data(), &out_len, + static_cast<unsigned int>(unwrapped_key.size()), + wrapped_key.data(), out_len); + ASSERT_EQ(SECSuccess, rv); + ASSERT_EQ(kInputKeyLen - 1, out_len); + ASSERT_EQ(0, memcmp(buf, unwrapped_key.data(), out_len)); +} + +} /* nss_test */ diff --git a/security/nss/gtests/pk11_gtest/pk11_cbc_unittest.cc b/security/nss/gtests/pk11_gtest/pk11_cbc_unittest.cc new file mode 100644 index 0000000000..58bc614f42 --- /dev/null +++ b/security/nss/gtests/pk11_gtest/pk11_cbc_unittest.cc @@ -0,0 +1,608 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include <memory> +#include "nss.h" +#include "pk11pub.h" +#include "secerr.h" + +#include "gtest/gtest.h" +#include "nss_scoped_ptrs.h" +#include "testvectors/cbc-vectors.h" +#include "util.h" + +namespace nss_test { + +static const uint8_t kInput[99] = {1, 2, 3}; +static const uint8_t kKeyData[24] = {'K', 'E', 'Y'}; + +static SECItem* GetIv() { + static const uint8_t kIvData[16] = {'I', 'V'}; + static const SECItem kIv = {siBuffer, const_cast<uint8_t*>(kIvData), + static_cast<unsigned int>(sizeof(kIvData))}; + return const_cast<SECItem*>(&kIv); +} + +class Pkcs11CbcPadTest : public ::testing::TestWithParam<CK_MECHANISM_TYPE> { + protected: + bool is_padded() const { + switch (GetParam()) { + case CKM_AES_CBC_PAD: + case CKM_DES3_CBC_PAD: + return true; + + case CKM_AES_CBC: + case CKM_DES3_CBC: + return false; + + default: + ADD_FAILURE() << "Unknown mechanism " << GetParam(); + } + return false; + } + + uint32_t GetUnpaddedMechanism() const { + switch (GetParam()) { + case CKM_AES_CBC_PAD: + return CKM_AES_CBC; + case CKM_DES3_CBC_PAD: + return CKM_DES3_CBC; + default: + ADD_FAILURE() << "Unknown padded mechanism " << GetParam(); + } + return 0; + } + + size_t block_size() const { + return static_cast<size_t>(PK11_GetBlockSize(GetParam(), nullptr)); + } + + size_t GetInputLen(CK_ATTRIBUTE_TYPE op) const { + if (is_padded() && op == CKA_ENCRYPT) { + // Anything goes for encryption when padded. + return sizeof(kInput); + } + + // Otherwise, use a strict multiple of the block size. + size_t block_count = sizeof(kInput) / block_size(); + EXPECT_LT(1U, block_count) << "need 2 blocks for tests"; + return block_count * block_size(); + } + + ScopedPK11SymKey MakeKey(CK_ATTRIBUTE_TYPE op) { + ScopedPK11SlotInfo slot(PK11_GetInternalSlot()); + EXPECT_NE(nullptr, slot); + if (!slot) { + return nullptr; + } + + unsigned int key_len = 0; + switch (GetParam()) { + case CKM_AES_CBC_PAD: + case CKM_AES_CBC: + key_len = 16; // This doesn't do AES-256 to keep it simple. + break; + + case CKM_DES3_CBC_PAD: + case CKM_DES3_CBC: + key_len = 24; + break; + + default: + ADD_FAILURE() << "Unknown mechanism " << GetParam(); + return nullptr; + } + + SECItem key_item = {siBuffer, const_cast<uint8_t*>(kKeyData), key_len}; + PK11SymKey* p = PK11_ImportSymKey(slot.get(), GetParam(), PK11_OriginUnwrap, + op, &key_item, nullptr); + EXPECT_NE(nullptr, p); + return ScopedPK11SymKey(p); + } + + ScopedPK11Context MakeContext(CK_ATTRIBUTE_TYPE op) { + ScopedPK11SymKey k = MakeKey(op); + PK11Context* ctx = + PK11_CreateContextBySymKey(GetParam(), op, k.get(), GetIv()); + EXPECT_NE(nullptr, ctx); + return ScopedPK11Context(ctx); + } +}; + +TEST_P(Pkcs11CbcPadTest, EncryptDecrypt) { + uint8_t encrypted[sizeof(kInput) + 64]; // Allow for padding and expansion. + size_t input_len = GetInputLen(CKA_ENCRYPT); + + ScopedPK11SymKey ek = MakeKey(CKA_ENCRYPT); + unsigned int encrypted_len = 0; + SECStatus rv = + PK11_Encrypt(ek.get(), GetParam(), GetIv(), encrypted, &encrypted_len, + sizeof(encrypted), kInput, input_len); + ASSERT_EQ(SECSuccess, rv); + EXPECT_LE(input_len, static_cast<size_t>(encrypted_len)); + + // Though the decrypted result can't be larger than the input we provided, + // NSS needs extra space to put the padding in. + uint8_t decrypted[sizeof(kInput) + 64]; + unsigned int decrypted_len = 0; + ScopedPK11SymKey dk = MakeKey(CKA_DECRYPT); + rv = PK11_Decrypt(dk.get(), GetParam(), GetIv(), decrypted, &decrypted_len, + sizeof(decrypted), encrypted, encrypted_len); + ASSERT_EQ(SECSuccess, rv); + EXPECT_EQ(input_len, static_cast<size_t>(decrypted_len)); + EXPECT_EQ(0, memcmp(kInput, decrypted, input_len)); +} + +TEST_P(Pkcs11CbcPadTest, ContextEncryptDecrypt) { + uint8_t encrypted[sizeof(kInput) + 64]; // Allow for padding and expansion. + size_t input_len = GetInputLen(CKA_ENCRYPT); + + ScopedPK11Context ectx = MakeContext(CKA_ENCRYPT); + int encrypted_len = 0; + SECStatus rv = PK11_CipherOp(ectx.get(), encrypted, &encrypted_len, + sizeof(encrypted), kInput, input_len); + ASSERT_EQ(SECSuccess, rv); + EXPECT_LE(0, encrypted_len); // Stupid signed parameters. + + unsigned int final_len = 0; + rv = PK11_CipherFinal(ectx.get(), encrypted + encrypted_len, &final_len, + sizeof(encrypted) - encrypted_len); + ASSERT_EQ(SECSuccess, rv); + encrypted_len += final_len; + EXPECT_LE(input_len, static_cast<size_t>(encrypted_len)); + + uint8_t decrypted[sizeof(kInput) + 64]; + int decrypted_len = 0; + ScopedPK11Context dctx = MakeContext(CKA_DECRYPT); + rv = PK11_CipherOp(dctx.get(), decrypted, &decrypted_len, sizeof(decrypted), + encrypted, encrypted_len); + ASSERT_EQ(SECSuccess, rv); + EXPECT_LE(0, decrypted_len); + + rv = PK11_CipherFinal(dctx.get(), decrypted + decrypted_len, &final_len, + sizeof(decrypted) - decrypted_len); + ASSERT_EQ(SECSuccess, rv); + decrypted_len += final_len; + EXPECT_EQ(input_len, static_cast<size_t>(decrypted_len)); + EXPECT_EQ(0, memcmp(kInput, decrypted, input_len)); +} + +TEST_P(Pkcs11CbcPadTest, ContextEncryptDecryptTwoParts) { + uint8_t encrypted[sizeof(kInput) + 64]; + size_t input_len = GetInputLen(CKA_ENCRYPT); + + ScopedPK11Context ectx = MakeContext(CKA_ENCRYPT); + int first_len = 0; + SECStatus rv = PK11_CipherOp(ectx.get(), encrypted, &first_len, + sizeof(encrypted), kInput, block_size()); + ASSERT_EQ(SECSuccess, rv); + ASSERT_LE(0, first_len); + + int second_len = 0; + rv = PK11_CipherOp(ectx.get(), encrypted + first_len, &second_len, + sizeof(encrypted) - first_len, kInput + block_size(), + input_len - block_size()); + ASSERT_EQ(SECSuccess, rv); + ASSERT_LE(0, second_len); + + unsigned int final_len = 0; + rv = PK11_CipherFinal(ectx.get(), encrypted + first_len + second_len, + &final_len, sizeof(encrypted) - first_len - second_len); + ASSERT_EQ(SECSuccess, rv); + unsigned int encrypted_len = first_len + second_len + final_len; + ASSERT_LE(input_len, static_cast<size_t>(encrypted_len)); + + // Now decrypt this in a similar fashion. + uint8_t decrypted[sizeof(kInput) + 64]; + ScopedPK11Context dctx = MakeContext(CKA_DECRYPT); + rv = PK11_CipherOp(dctx.get(), decrypted, &first_len, sizeof(decrypted), + encrypted, block_size()); + ASSERT_EQ(SECSuccess, rv); + EXPECT_LE(0, first_len); + + rv = PK11_CipherOp(dctx.get(), decrypted + first_len, &second_len, + sizeof(decrypted) - first_len, encrypted + block_size(), + encrypted_len - block_size()); + ASSERT_EQ(SECSuccess, rv); + EXPECT_LE(0, second_len); + + unsigned int decrypted_len = 0; + rv = PK11_CipherFinal(dctx.get(), decrypted + first_len + second_len, + &decrypted_len, + sizeof(decrypted) - first_len - second_len); + ASSERT_EQ(SECSuccess, rv); + decrypted_len += first_len + second_len; + EXPECT_EQ(input_len, static_cast<size_t>(decrypted_len)); + EXPECT_EQ(0, memcmp(kInput, decrypted, input_len)); +} + +TEST_P(Pkcs11CbcPadTest, FailDecryptSimple) { + ScopedPK11SymKey dk = MakeKey(CKA_DECRYPT); + uint8_t output[sizeof(kInput) + 64]; + unsigned int output_len = 999; + SECStatus rv = + PK11_Decrypt(dk.get(), GetParam(), GetIv(), output, &output_len, + sizeof(output), kInput, GetInputLen(CKA_DECRYPT)); + if (is_padded()) { + EXPECT_EQ(SECFailure, rv); + EXPECT_EQ(999U, output_len); + } else { + // Unpadded decryption can't really fail. + EXPECT_EQ(SECSuccess, rv); + } +} + +TEST_P(Pkcs11CbcPadTest, FailEncryptSimple) { + ScopedPK11SymKey ek = MakeKey(CKA_ENCRYPT); + uint8_t output[3]; // Too small for anything. + unsigned int output_len = 333; + + SECStatus rv = + PK11_Encrypt(ek.get(), GetParam(), GetIv(), output, &output_len, + sizeof(output), kInput, GetInputLen(CKA_ENCRYPT)); + EXPECT_EQ(SECFailure, rv); + EXPECT_EQ(333U, output_len); +} + +// It's a bit of a lie to put this in pk11_cbc_unittest, since we +// also test bounds checking in other modes. There doesn't seem +// to be an appropriately-generic place elsewhere. +TEST_F(Pkcs11CbcPadTest, FailEncryptShortParam) { + SECStatus rv = SECFailure; + uint8_t encrypted[sizeof(kInput)]; + unsigned int encrypted_len = 0; + size_t input_len = AES_BLOCK_SIZE; + + // CK_NSS_GCM_PARAMS is the largest param struct used across AES modes + uint8_t param_buf[sizeof(CK_NSS_GCM_PARAMS)]; + SECItem param = {siBuffer, param_buf, sizeof(param_buf)}; + SECItem key_item = {siBuffer, const_cast<uint8_t*>(kKeyData), 16}; + + // Setup (we use the ECB key for other modes) + ScopedPK11SlotInfo slot(PK11_GetInternalSlot()); + ASSERT_NE(nullptr, slot); + ScopedPK11SymKey key(PK11_ImportSymKey(slot.get(), CKM_AES_ECB, + PK11_OriginUnwrap, CKA_ENCRYPT, + &key_item, nullptr)); + ASSERT_TRUE(key.get()); + + // CTR should have a CK_AES_CTR_PARAMS + param.len = sizeof(CK_AES_CTR_PARAMS) - 1; + rv = PK11_Encrypt(key.get(), CKM_AES_CTR, ¶m, encrypted, &encrypted_len, + sizeof(encrypted), kInput, input_len); + EXPECT_EQ(SECFailure, rv); + + param.len++; + reinterpret_cast<CK_AES_CTR_PARAMS*>(param.data)->ulCounterBits = 32; + rv = PK11_Encrypt(key.get(), CKM_AES_CTR, ¶m, encrypted, &encrypted_len, + sizeof(encrypted), kInput, input_len); + EXPECT_EQ(SECSuccess, rv); + + // GCM should have a CK_NSS_GCM_PARAMS + param.len = sizeof(CK_NSS_GCM_PARAMS) - 1; + rv = PK11_Encrypt(key.get(), CKM_AES_GCM, ¶m, encrypted, &encrypted_len, + sizeof(encrypted), kInput, input_len); + EXPECT_EQ(SECFailure, rv); + + param.len++; + reinterpret_cast<CK_NSS_GCM_PARAMS*>(param.data)->pIv = param_buf; + reinterpret_cast<CK_NSS_GCM_PARAMS*>(param.data)->ulIvLen = 12; + reinterpret_cast<CK_NSS_GCM_PARAMS*>(param.data)->pAAD = nullptr; + reinterpret_cast<CK_NSS_GCM_PARAMS*>(param.data)->ulAADLen = 0; + reinterpret_cast<CK_NSS_GCM_PARAMS*>(param.data)->ulTagBits = 128; + rv = PK11_Encrypt(key.get(), CKM_AES_GCM, ¶m, encrypted, &encrypted_len, + sizeof(encrypted), kInput, input_len); + EXPECT_EQ(SECSuccess, rv); + + // CBC should have a 16B IV + param.len = AES_BLOCK_SIZE - 1; + rv = PK11_Encrypt(key.get(), CKM_AES_CBC, ¶m, encrypted, &encrypted_len, + sizeof(encrypted), kInput, input_len); + EXPECT_EQ(SECFailure, rv); + + param.len++; + rv = PK11_Encrypt(key.get(), CKM_AES_CBC, ¶m, encrypted, &encrypted_len, + sizeof(encrypted), kInput, input_len); + EXPECT_EQ(SECSuccess, rv); + + // CTS + param.len = AES_BLOCK_SIZE - 1; + rv = PK11_Encrypt(key.get(), CKM_AES_CTS, ¶m, encrypted, &encrypted_len, + sizeof(encrypted), kInput, input_len); + EXPECT_EQ(SECFailure, rv); + + param.len++; + rv = PK11_Encrypt(key.get(), CKM_AES_CTS, ¶m, encrypted, &encrypted_len, + sizeof(encrypted), kInput, input_len); + EXPECT_EQ(SECSuccess, rv); +} + +TEST_P(Pkcs11CbcPadTest, ContextFailDecryptSimple) { + ScopedPK11Context dctx = MakeContext(CKA_DECRYPT); + uint8_t output[sizeof(kInput) + 64]; + int output_len = 77; + + SECStatus rv = PK11_CipherOp(dctx.get(), output, &output_len, sizeof(output), + kInput, GetInputLen(CKA_DECRYPT)); + EXPECT_EQ(SECSuccess, rv); + EXPECT_LE(0, output_len) << "this is not an AEAD, so content leaks"; + + unsigned int final_len = 88; + rv = PK11_CipherFinal(dctx.get(), output, &final_len, sizeof(output)); + if (is_padded()) { + EXPECT_EQ(SECFailure, rv); + ASSERT_EQ(88U, final_len) << "final_len should be untouched"; + } else { + // Unpadded decryption can't really fail. + EXPECT_EQ(SECSuccess, rv); + } +} + +TEST_P(Pkcs11CbcPadTest, ContextFailDecryptInvalidBlockSize) { + ScopedPK11Context dctx = MakeContext(CKA_DECRYPT); + uint8_t output[sizeof(kInput) + 64]; + int output_len = 888; + + SECStatus rv = PK11_CipherOp(dctx.get(), output, &output_len, sizeof(output), + kInput, GetInputLen(CKA_DECRYPT) - 1); + EXPECT_EQ(SECFailure, rv); + // Because PK11_CipherOp is partial, it can return data on failure. + // This means that it needs to reset its output length to 0 when it starts. + EXPECT_EQ(0, output_len) << "output_len is reset"; +} + +TEST_P(Pkcs11CbcPadTest, EncryptDecrypt_PaddingTooLong) { + if (!is_padded()) { + return; + } + + // Padding that's over the block size + const std::vector<uint8_t> input = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20}; + std::vector<uint8_t> encrypted(input.size()); + uint32_t encrypted_len = 0; + + ScopedPK11SymKey ek = MakeKey(CKA_ENCRYPT); + SECStatus rv = PK11_Encrypt(ek.get(), GetUnpaddedMechanism(), GetIv(), + encrypted.data(), &encrypted_len, + encrypted.size(), input.data(), input.size()); + ASSERT_EQ(SECSuccess, rv); + EXPECT_EQ(input.size(), encrypted_len); + + std::vector<uint8_t> decrypted(input.size()); + uint32_t decrypted_len = 0; + ScopedPK11SymKey dk = MakeKey(CKA_DECRYPT); + rv = PK11_Decrypt(dk.get(), GetParam(), GetIv(), decrypted.data(), + &decrypted_len, decrypted.size(), encrypted.data(), + encrypted_len); + EXPECT_EQ(SECFailure, rv); + EXPECT_EQ(0U, decrypted_len); +} + +TEST_P(Pkcs11CbcPadTest, EncryptDecrypt_ShortPadding1) { + if (!is_padded()) { + return; + } + + // Padding that's one byte short + const std::vector<uint8_t> input = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08}; + std::vector<uint8_t> encrypted(input.size()); + uint32_t encrypted_len = 0; + + ScopedPK11SymKey ek = MakeKey(CKA_ENCRYPT); + SECStatus rv = PK11_Encrypt(ek.get(), GetUnpaddedMechanism(), GetIv(), + encrypted.data(), &encrypted_len, + encrypted.size(), input.data(), input.size()); + ASSERT_EQ(SECSuccess, rv); + EXPECT_EQ(input.size(), encrypted_len); + + std::vector<uint8_t> decrypted(input.size()); + uint32_t decrypted_len = 0; + ScopedPK11SymKey dk = MakeKey(CKA_DECRYPT); + rv = PK11_Decrypt(dk.get(), GetParam(), GetIv(), decrypted.data(), + &decrypted_len, decrypted.size(), encrypted.data(), + encrypted_len); + EXPECT_EQ(SECFailure, rv); + EXPECT_EQ(0U, decrypted_len); +} + +TEST_P(Pkcs11CbcPadTest, EncryptDecrypt_ShortPadding2) { + if (!is_padded()) { + return; + } + + // Padding that's one byte short + const std::vector<uint8_t> input = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02}; + std::vector<uint8_t> encrypted(input.size()); + uint32_t encrypted_len = 0; + + ScopedPK11SymKey ek = MakeKey(CKA_ENCRYPT); + SECStatus rv = PK11_Encrypt(ek.get(), GetUnpaddedMechanism(), GetIv(), + encrypted.data(), &encrypted_len, + encrypted.size(), input.data(), input.size()); + ASSERT_EQ(SECSuccess, rv); + EXPECT_EQ(input.size(), encrypted_len); + + std::vector<uint8_t> decrypted(input.size()); + uint32_t decrypted_len = 0; + ScopedPK11SymKey dk = MakeKey(CKA_DECRYPT); + rv = PK11_Decrypt(dk.get(), GetParam(), GetIv(), decrypted.data(), + &decrypted_len, decrypted.size(), encrypted.data(), + encrypted_len); + EXPECT_EQ(SECFailure, rv); + EXPECT_EQ(0U, decrypted_len); +} + +TEST_P(Pkcs11CbcPadTest, EncryptDecrypt_ZeroLengthPadding) { + if (!is_padded()) { + return; + } + + // Padding of length zero + const std::vector<uint8_t> input = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + std::vector<uint8_t> encrypted(input.size()); + uint32_t encrypted_len = 0; + + ScopedPK11SymKey ek = MakeKey(CKA_ENCRYPT); + SECStatus rv = PK11_Encrypt(ek.get(), GetUnpaddedMechanism(), GetIv(), + encrypted.data(), &encrypted_len, + encrypted.size(), input.data(), input.size()); + ASSERT_EQ(SECSuccess, rv); + EXPECT_EQ(input.size(), encrypted_len); + + std::vector<uint8_t> decrypted(input.size()); + uint32_t decrypted_len = 0; + ScopedPK11SymKey dk = MakeKey(CKA_DECRYPT); + rv = PK11_Decrypt(dk.get(), GetParam(), GetIv(), decrypted.data(), + &decrypted_len, decrypted.size(), encrypted.data(), + encrypted_len); + EXPECT_EQ(SECFailure, rv); + EXPECT_EQ(0U, decrypted_len); +} + +TEST_P(Pkcs11CbcPadTest, EncryptDecrypt_OverflowPadding) { + if (!is_padded()) { + return; + } + + // Padding that's much longer than block size + const std::vector<uint8_t> input = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; + std::vector<uint8_t> encrypted(input.size()); + uint32_t encrypted_len = 0; + + ScopedPK11SymKey ek = MakeKey(CKA_ENCRYPT); + SECStatus rv = PK11_Encrypt(ek.get(), GetUnpaddedMechanism(), GetIv(), + encrypted.data(), &encrypted_len, + encrypted.size(), input.data(), input.size()); + ASSERT_EQ(SECSuccess, rv); + EXPECT_EQ(input.size(), encrypted_len); + + std::vector<uint8_t> decrypted(input.size()); + uint32_t decrypted_len = 0; + ScopedPK11SymKey dk = MakeKey(CKA_DECRYPT); + rv = PK11_Decrypt(dk.get(), GetParam(), GetIv(), decrypted.data(), + &decrypted_len, decrypted.size(), encrypted.data(), + encrypted_len); + EXPECT_EQ(SECFailure, rv); + EXPECT_EQ(0U, decrypted_len); +} + +TEST_P(Pkcs11CbcPadTest, EncryptDecrypt_ShortValidPadding) { + if (!is_padded()) { + return; + } + + // Minimal valid padding + const std::vector<uint8_t> input = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01}; + std::vector<uint8_t> encrypted(input.size()); + uint32_t encrypted_len = 0; + + ScopedPK11SymKey ek = MakeKey(CKA_ENCRYPT); + SECStatus rv = PK11_Encrypt(ek.get(), GetUnpaddedMechanism(), GetIv(), + encrypted.data(), &encrypted_len, + encrypted.size(), input.data(), input.size()); + ASSERT_EQ(SECSuccess, rv); + EXPECT_EQ(input.size(), encrypted_len); + + std::vector<uint8_t> decrypted(input.size()); + uint32_t decrypted_len = 0; + ScopedPK11SymKey dk = MakeKey(CKA_DECRYPT); + rv = PK11_Decrypt(dk.get(), GetParam(), GetIv(), decrypted.data(), + &decrypted_len, decrypted.size(), encrypted.data(), + encrypted_len); + EXPECT_EQ(SECSuccess, rv); + EXPECT_EQ(input.size() - 1, decrypted_len); + EXPECT_EQ(0, memcmp(decrypted.data(), input.data(), decrypted_len)); +} + +INSTANTIATE_TEST_SUITE_P(EncryptDecrypt, Pkcs11CbcPadTest, + ::testing::Values(CKM_AES_CBC_PAD, CKM_AES_CBC, + CKM_DES3_CBC_PAD, CKM_DES3_CBC)); + +class Pkcs11AesCbcWycheproofTest + : public ::testing::TestWithParam<AesCbcTestVector> { + protected: + void RunTest(const AesCbcTestVector vec) { + bool valid = vec.valid; + std::string err = "Test #" + std::to_string(vec.id) + " failed"; + std::vector<uint8_t> key = hex_string_to_bytes(vec.key); + std::vector<uint8_t> iv = hex_string_to_bytes(vec.iv); + std::vector<uint8_t> ciphertext = hex_string_to_bytes(vec.ciphertext); + std::vector<uint8_t> msg = hex_string_to_bytes(vec.msg); + std::vector<uint8_t> decrypted(vec.ciphertext.size()); + unsigned int decrypted_len = 0; + + ScopedPK11SlotInfo slot(PK11_GetInternalSlot()); + ASSERT_NE(nullptr, slot); + + // Don't provide a null pointer, even if the length is 0. We don't want to + // fail on trivial checks. + uint8_t tmp; + SECItem iv_item = {siBuffer, iv.data() ? iv.data() : &tmp, + static_cast<unsigned int>(iv.size())}; + SECItem key_item = {siBuffer, key.data() ? key.data() : &tmp, + static_cast<unsigned int>(key.size())}; + + PK11SymKey* pKey = PK11_ImportSymKey(slot.get(), kMech, PK11_OriginUnwrap, + CKA_ENCRYPT, &key_item, nullptr); + ASSERT_NE(nullptr, pKey); + ScopedPK11SymKey spKey = ScopedPK11SymKey(pKey); + + SECStatus rv = PK11_Decrypt(spKey.get(), kMech, &iv_item, decrypted.data(), + &decrypted_len, decrypted.size(), + ciphertext.data(), ciphertext.size()); + + ASSERT_EQ(valid ? SECSuccess : SECFailure, rv) << err; + if (valid) { + EXPECT_EQ(msg.size(), static_cast<size_t>(decrypted_len)) << err; + EXPECT_EQ(0, memcmp(msg.data(), decrypted.data(), decrypted_len)) << err; + } + } + + const CK_MECHANISM_TYPE kMech = CKM_AES_CBC_PAD; +}; + +TEST_P(Pkcs11AesCbcWycheproofTest, TestVectors) { RunTest(GetParam()); } + +INSTANTIATE_TEST_SUITE_P(WycheproofTestVector, Pkcs11AesCbcWycheproofTest, + ::testing::ValuesIn(kCbcWycheproofVectors)); + +} // namespace nss_test diff --git a/security/nss/gtests/pk11_gtest/pk11_chacha20poly1305_unittest.cc b/security/nss/gtests/pk11_gtest/pk11_chacha20poly1305_unittest.cc new file mode 100644 index 0000000000..7c1dca26b3 --- /dev/null +++ b/security/nss/gtests/pk11_gtest/pk11_chacha20poly1305_unittest.cc @@ -0,0 +1,491 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include <memory> +#include "nss.h" +#include "pk11pub.h" +#include "pk11priv.h" +#include "sechash.h" +#include "secerr.h" + +#include "cpputil.h" +#include "nss_scoped_ptrs.h" + +#include "testvectors/chachapoly-vectors.h" +#include "gtest/gtest.h" + +namespace nss_test { + +static const CK_MECHANISM_TYPE kMech = CKM_NSS_CHACHA20_POLY1305; +static const CK_MECHANISM_TYPE kMechXor = CKM_NSS_CHACHA20_CTR; +// Some test data for simple tests. +static const uint8_t kKeyData[32] = {'k'}; +static const uint8_t kCtrNonce[16] = {'c', 0, 0, 0, 'n'}; +static const uint8_t kData[16] = {'d'}; + +class Pkcs11ChaCha20Poly1305Test + : public ::testing::TestWithParam<ChaChaTestVector> { + public: + void EncryptDecrypt(const ScopedPK11SymKey& key, const bool invalid_iv, + const bool invalid_tag, const uint8_t* data, + size_t data_len, const uint8_t* aad, size_t aad_len, + const uint8_t* iv, size_t iv_len, + const uint8_t* ct = nullptr, size_t ct_len = 0) { + // Prepare AEAD params. + CK_NSS_AEAD_PARAMS aead_params; + aead_params.pNonce = toUcharPtr(iv); + aead_params.ulNonceLen = iv_len; + aead_params.pAAD = toUcharPtr(aad); + aead_params.ulAADLen = aad_len; + aead_params.ulTagLen = 16; + + SECItem params = {siBuffer, reinterpret_cast<unsigned char*>(&aead_params), + sizeof(aead_params)}; + + // Encrypt with bad parameters (TagLen is too long). + unsigned int encrypted_len = 0; + std::vector<uint8_t> encrypted(data_len + aead_params.ulTagLen); + aead_params.ulTagLen = 158072; + SECStatus rv = + PK11_Encrypt(key.get(), kMech, ¶ms, encrypted.data(), + &encrypted_len, encrypted.size(), data, data_len); + EXPECT_EQ(SECFailure, rv); + EXPECT_EQ(0U, encrypted_len); + + // Encrypt with bad parameters (TagLen is too short). + aead_params.ulTagLen = 2; + rv = PK11_Encrypt(key.get(), kMech, ¶ms, encrypted.data(), + &encrypted_len, encrypted.size(), data, data_len); + EXPECT_EQ(SECFailure, rv); + EXPECT_EQ(0U, encrypted_len); + + // Encrypt. + aead_params.ulTagLen = 16; + rv = PK11_Encrypt(key.get(), kMech, ¶ms, encrypted.data(), + &encrypted_len, encrypted.size(), data, data_len); + + // Return if encryption failure was expected due to invalid IV. + // Without valid ciphertext, all further tests can be skipped. + if (invalid_iv) { + EXPECT_EQ(rv, SECFailure); + EXPECT_EQ(0U, encrypted_len) + << "encrypted_len is unmodified after failure"; + return; + } + + EXPECT_EQ(rv, SECSuccess); + EXPECT_EQ(encrypted.size(), static_cast<size_t>(encrypted_len)); + + // Check ciphertext and tag. + if (ct) { + ASSERT_EQ(ct_len, encrypted_len); + EXPECT_TRUE(!memcmp(ct, encrypted.data(), encrypted.size() - 16)); + EXPECT_TRUE(!memcmp(ct, encrypted.data(), encrypted.size()) != + invalid_tag); + } + + // Get the *estimated* plaintext length. This value should + // never be zero as it could lead to a NULL outPtr being + // passed to a subsequent decryption call (for AEAD we + // must authenticate even when the pt is zero-length). + unsigned int decrypt_bytes_needed = 0; + rv = PK11_Decrypt(key.get(), kMech, ¶ms, nullptr, &decrypt_bytes_needed, + 0, encrypted.data(), encrypted_len); + EXPECT_EQ(rv, SECSuccess); + EXPECT_GT(decrypt_bytes_needed, data_len); + + // Now decrypt it + std::vector<uint8_t> decrypted(decrypt_bytes_needed); + unsigned int decrypted_len = 0; + rv = PK11_Decrypt(key.get(), kMech, ¶ms, decrypted.data(), + &decrypted_len, decrypted.size(), encrypted.data(), + encrypted.size()); + EXPECT_EQ(rv, SECSuccess); + + // Check the plaintext. + ASSERT_EQ(data_len, decrypted_len); + EXPECT_TRUE(!memcmp(data, decrypted.data(), decrypted_len)); + + // Decrypt with bogus data. + // Skip if there's no data to modify. + if (encrypted_len > 0) { + decrypted_len = 0; + std::vector<uint8_t> bogus_ciphertext(encrypted); + bogus_ciphertext[0] ^= 0xff; + rv = PK11_Decrypt(key.get(), kMech, ¶ms, decrypted.data(), + &decrypted_len, decrypted.size(), + bogus_ciphertext.data(), encrypted_len); + EXPECT_EQ(rv, SECFailure); + EXPECT_EQ(0U, decrypted_len); + } + + // Decrypt with bogus tag. + // Skip if there's no tag to modify. + if (encrypted_len > 0) { + decrypted_len = 0; + std::vector<uint8_t> bogus_tag(encrypted); + bogus_tag[encrypted_len - 1] ^= 0xff; + rv = PK11_Decrypt(key.get(), kMech, ¶ms, decrypted.data(), + &decrypted_len, decrypted.size(), bogus_tag.data(), + encrypted_len); + EXPECT_EQ(rv, SECFailure); + EXPECT_EQ(0U, decrypted_len); + } + + // Decrypt with bogus IV. + // iv_len == 0 is invalid and should be caught earlier. + // Still skip, if there's no IV to modify. + if (iv_len != 0) { + decrypted_len = 0; + SECItem bogus_params(params); + CK_NSS_AEAD_PARAMS bogusAeadParams(aead_params); + bogus_params.data = reinterpret_cast<unsigned char*>(&bogusAeadParams); + + std::vector<uint8_t> bogusIV(iv, iv + iv_len); + bogusAeadParams.pNonce = toUcharPtr(bogusIV.data()); + bogusIV[0] ^= 0xff; + + rv = PK11_Decrypt(key.get(), kMech, &bogus_params, decrypted.data(), + &decrypted_len, data_len, encrypted.data(), + encrypted.size()); + EXPECT_EQ(rv, SECFailure); + EXPECT_EQ(0U, decrypted_len); + } + + // Decrypt with bogus additional data. + // Skip when AAD was empty and can't be modified. + // Alternatively we could generate random aad. + if (aad_len != 0) { + decrypted_len = 0; + SECItem bogus_params(params); + CK_NSS_AEAD_PARAMS bogus_aead_params(aead_params); + bogus_params.data = reinterpret_cast<unsigned char*>(&bogus_aead_params); + + std::vector<uint8_t> bogus_aad(aad, aad + aad_len); + bogus_aead_params.pAAD = toUcharPtr(bogus_aad.data()); + bogus_aad[0] ^= 0xff; + + rv = PK11_Decrypt(key.get(), kMech, &bogus_params, decrypted.data(), + &decrypted_len, data_len, encrypted.data(), + encrypted.size()); + EXPECT_EQ(rv, SECFailure); + EXPECT_EQ(0U, decrypted_len); + } + } + + void EncryptDecrypt(const ChaChaTestVector testvector) { + ScopedPK11SlotInfo slot(PK11_GetInternalSlot()); + SECItem keyItem = {siBuffer, toUcharPtr(testvector.key.data()), + static_cast<unsigned int>(testvector.key.size())}; + + // Import key. + ScopedPK11SymKey key(PK11_ImportSymKey(slot.get(), kMech, PK11_OriginUnwrap, + CKA_ENCRYPT, &keyItem, nullptr)); + EXPECT_TRUE(!!key); + + // Check. + EncryptDecrypt(key, testvector.invalid_iv, testvector.invalid_tag, + testvector.plaintext.data(), testvector.plaintext.size(), + testvector.aad.data(), testvector.aad.size(), + testvector.iv.data(), testvector.iv.size(), + testvector.ciphertext.data(), testvector.ciphertext.size()); + } + + void MessageInterfaceTest(CK_MECHANISM_TYPE mech, int iterations, + PRBool separateTag) { + // Generate a random key. + ScopedPK11SlotInfo slot(PK11_GetInternalSlot()); + ASSERT_NE(nullptr, slot); + ScopedPK11SymKey sym_key( + PK11_KeyGen(slot.get(), mech, nullptr, 32, nullptr)); + ASSERT_NE(nullptr, sym_key); + + int tagSize = 16; + int cipher_simulated_size; + int output_len_message = 0; + int output_len_simulated = 0; + unsigned int output_len_v24 = 0; + + std::vector<uint8_t> plainIn(17); + std::vector<uint8_t> plainOut_message(17); + std::vector<uint8_t> plainOut_simulated(17); + std::vector<uint8_t> plainOut_v24(17); + std::vector<uint8_t> nonce(12); + std::vector<uint8_t> cipher_message(33); + std::vector<uint8_t> cipher_simulated(33); + std::vector<uint8_t> cipher_v24(33); + std::vector<uint8_t> aad(16); + std::vector<uint8_t> tag_message(16); + std::vector<uint8_t> tag_simulated(16); + + // Prepare AEAD v2.40 params. + CK_SALSA20_CHACHA20_POLY1305_PARAMS chacha_params; + chacha_params.pNonce = nonce.data(); + chacha_params.ulNonceLen = nonce.size(); + chacha_params.pAAD = aad.data(); + chacha_params.ulAADLen = aad.size(); + + // Prepare AEAD MESSAGE params. + CK_SALSA20_CHACHA20_POLY1305_MSG_PARAMS chacha_message_params; + chacha_message_params.pNonce = nonce.data(); + chacha_message_params.ulNonceLen = nonce.size(); + if (separateTag) { + chacha_message_params.pTag = tag_message.data(); + } else { + chacha_message_params.pTag = cipher_message.data() + plainIn.size(); + } + + // Prepare AEAD MESSAGE params for simulated case + CK_SALSA20_CHACHA20_POLY1305_MSG_PARAMS chacha_simulated_params; + chacha_simulated_params = chacha_message_params; + if (separateTag) { + // The simulated case, we have to allocate temp bufs for separate + // tags, make sure that works in both the encrypt and the decrypt + // cases. + chacha_simulated_params.pTag = tag_simulated.data(); + cipher_simulated_size = cipher_simulated.size() - tagSize; + } else { + chacha_simulated_params.pTag = cipher_simulated.data() + plainIn.size(); + cipher_simulated_size = cipher_simulated.size(); + } + SECItem params = {siBuffer, + reinterpret_cast<unsigned char*>(&chacha_params), + sizeof(chacha_params)}; + SECItem empty = {siBuffer, NULL, 0}; + + // initialize our plain text, IV and aad. + ASSERT_EQ(PK11_GenerateRandom(plainIn.data(), plainIn.size()), SECSuccess); + ASSERT_EQ(PK11_GenerateRandom(aad.data(), aad.size()), SECSuccess); + + // Initialize message encrypt context + ScopedPK11Context encrypt_message_context(PK11_CreateContextBySymKey( + mech, CKA_NSS_MESSAGE | CKA_ENCRYPT, sym_key.get(), &empty)); + ASSERT_NE(nullptr, encrypt_message_context); + ASSERT_FALSE(_PK11_ContextGetAEADSimulation(encrypt_message_context.get())); + + // Initialize simulated encrypt context + ScopedPK11Context encrypt_simulated_context(PK11_CreateContextBySymKey( + mech, CKA_NSS_MESSAGE | CKA_ENCRYPT, sym_key.get(), &empty)); + ASSERT_NE(nullptr, encrypt_simulated_context); + ASSERT_EQ(SECSuccess, + _PK11_ContextSetAEADSimulation(encrypt_simulated_context.get())); + + // Initialize message decrypt context + ScopedPK11Context decrypt_message_context(PK11_CreateContextBySymKey( + mech, CKA_NSS_MESSAGE | CKA_DECRYPT, sym_key.get(), &empty)); + ASSERT_NE(nullptr, decrypt_message_context); + ASSERT_FALSE(_PK11_ContextGetAEADSimulation(decrypt_message_context.get())); + + // Initialize simulated decrypt context + ScopedPK11Context decrypt_simulated_context(PK11_CreateContextBySymKey( + mech, CKA_NSS_MESSAGE | CKA_DECRYPT, sym_key.get(), &empty)); + ASSERT_NE(nullptr, decrypt_simulated_context); + EXPECT_EQ(SECSuccess, + _PK11_ContextSetAEADSimulation(decrypt_simulated_context.get())); + + // Now walk down our iterations. Each method of calculating the operation + // should agree at each step. + for (int i = 0; i < iterations; i++) { + // get a unique nonce for each iteration + EXPECT_EQ(PK11_GenerateRandom(nonce.data(), nonce.size()), SECSuccess); + EXPECT_EQ(SECSuccess, + PK11_AEADRawOp( + encrypt_message_context.get(), &chacha_message_params, + sizeof(chacha_message_params), aad.data(), aad.size(), + cipher_message.data(), &output_len_message, + cipher_message.size(), plainIn.data(), plainIn.size())); + EXPECT_EQ(SECSuccess, + PK11_AEADRawOp( + encrypt_simulated_context.get(), &chacha_simulated_params, + sizeof(chacha_simulated_params), aad.data(), aad.size(), + cipher_simulated.data(), &output_len_simulated, + cipher_simulated_size, plainIn.data(), plainIn.size())); + // make sure simulated and message is the same + EXPECT_EQ(output_len_message, output_len_simulated); + EXPECT_EQ(0, memcmp(cipher_message.data(), cipher_simulated.data(), + output_len_message)); + EXPECT_EQ(0, memcmp(chacha_message_params.pTag, + chacha_simulated_params.pTag, tagSize)); + // make sure v2.40 is the same. + EXPECT_EQ(SECSuccess, + PK11_Encrypt(sym_key.get(), mech, ¶ms, cipher_v24.data(), + &output_len_v24, cipher_v24.size(), plainIn.data(), + plainIn.size())); + EXPECT_EQ(output_len_message, (int)output_len_v24 - tagSize); + EXPECT_EQ(0, memcmp(cipher_message.data(), cipher_v24.data(), + output_len_message)); + EXPECT_EQ(0, memcmp(chacha_message_params.pTag, + cipher_v24.data() + output_len_message, tagSize)); + // now make sure we can decrypt + EXPECT_EQ( + SECSuccess, + PK11_AEADRawOp(decrypt_message_context.get(), &chacha_message_params, + sizeof(chacha_message_params), aad.data(), aad.size(), + plainOut_message.data(), &output_len_message, + plainOut_message.size(), cipher_message.data(), + output_len_message)); + EXPECT_EQ(output_len_message, (int)plainIn.size()); + EXPECT_EQ( + 0, memcmp(plainOut_message.data(), plainIn.data(), plainIn.size())); + EXPECT_EQ(SECSuccess, + PK11_AEADRawOp(decrypt_simulated_context.get(), + &chacha_simulated_params, + sizeof(chacha_simulated_params), aad.data(), + aad.size(), plainOut_simulated.data(), + &output_len_simulated, plainOut_simulated.size(), + cipher_message.data(), output_len_simulated)); + EXPECT_EQ(output_len_simulated, (int)plainIn.size()); + EXPECT_EQ( + 0, memcmp(plainOut_simulated.data(), plainIn.data(), plainIn.size())); + if (separateTag) { + // in the separateTag case, we need to copy the tag back to the + // end of the cipher_message.data() before using the v2.4 interface + memcpy(cipher_message.data() + output_len_message, + chacha_message_params.pTag, tagSize); + } + EXPECT_EQ(SECSuccess, + PK11_Decrypt(sym_key.get(), mech, ¶ms, plainOut_v24.data(), + &output_len_v24, plainOut_v24.size(), + cipher_message.data(), output_len_v24)); + EXPECT_EQ(output_len_v24, plainIn.size()); + EXPECT_EQ(0, memcmp(plainOut_v24.data(), plainIn.data(), plainIn.size())); + } + return; + } + + protected: +}; + +TEST_F(Pkcs11ChaCha20Poly1305Test, GenerateEncryptDecrypt) { + // Generate a random key. + ScopedPK11SlotInfo slot(PK11_GetInternalSlot()); + ScopedPK11SymKey key(PK11_KeyGen(slot.get(), kMech, nullptr, 32, nullptr)); + EXPECT_TRUE(!!key); + + // Generate random data. + std::vector<uint8_t> input(512); + SECStatus rv = + PK11_GenerateRandomOnSlot(slot.get(), input.data(), input.size()); + EXPECT_EQ(rv, SECSuccess); + + // Generate random AAD. + std::vector<uint8_t> aad(16); + rv = PK11_GenerateRandomOnSlot(slot.get(), aad.data(), aad.size()); + EXPECT_EQ(rv, SECSuccess); + + // Generate random IV. + std::vector<uint8_t> iv(12); + rv = PK11_GenerateRandomOnSlot(slot.get(), iv.data(), iv.size()); + EXPECT_EQ(rv, SECSuccess); + + // Check. + EncryptDecrypt(key, false, false, input.data(), input.size(), aad.data(), + aad.size(), iv.data(), iv.size()); +} + +TEST_F(Pkcs11ChaCha20Poly1305Test, Xor) { + static const uint8_t kExpected[sizeof(kData)] = { + 0xd8, 0x15, 0xd3, 0xb3, 0xe9, 0x34, 0x3b, 0x7a, + 0x24, 0xf6, 0x5f, 0xd7, 0x95, 0x3d, 0xd3, 0x51}; + + ScopedPK11SlotInfo slot(PK11_GetInternalSlot()); + SECItem keyItem = {siBuffer, toUcharPtr(kKeyData), + static_cast<unsigned int>(sizeof(kKeyData))}; + ScopedPK11SymKey key(PK11_ImportSymKey( + slot.get(), kMechXor, PK11_OriginUnwrap, CKA_ENCRYPT, &keyItem, nullptr)); + EXPECT_TRUE(!!key); + + SECItem ctrNonceItem = {siBuffer, toUcharPtr(kCtrNonce), + static_cast<unsigned int>(sizeof(kCtrNonce))}; + uint8_t encrypted[sizeof(kData)]; + unsigned int encrypted_len = 88; // This should be overwritten. + SECStatus rv = + PK11_Encrypt(key.get(), kMechXor, &ctrNonceItem, encrypted, + &encrypted_len, sizeof(encrypted), kData, sizeof(kData)); + ASSERT_EQ(SECSuccess, rv); + ASSERT_EQ(sizeof(kExpected), static_cast<size_t>(encrypted_len)); + EXPECT_EQ(0, memcmp(kExpected, encrypted, sizeof(kExpected))); + + // Decrypting has the same effect. + rv = PK11_Decrypt(key.get(), kMechXor, &ctrNonceItem, encrypted, + &encrypted_len, sizeof(encrypted), kData, sizeof(kData)); + ASSERT_EQ(SECSuccess, rv); + ASSERT_EQ(sizeof(kData), static_cast<size_t>(encrypted_len)); + EXPECT_EQ(0, memcmp(kExpected, encrypted, sizeof(kExpected))); + + // Operating in reverse too. + rv = PK11_Encrypt(key.get(), kMechXor, &ctrNonceItem, encrypted, + &encrypted_len, sizeof(encrypted), kExpected, + sizeof(kExpected)); + ASSERT_EQ(SECSuccess, rv); + ASSERT_EQ(sizeof(kExpected), static_cast<size_t>(encrypted_len)); + EXPECT_EQ(0, memcmp(kData, encrypted, sizeof(kData))); +} + +// This test just ensures that a key can be generated for use with the XOR +// function. The result is random and therefore cannot be checked. +TEST_F(Pkcs11ChaCha20Poly1305Test, GenerateXor) { + ScopedPK11SlotInfo slot(PK11_GetInternalSlot()); + ScopedPK11SymKey key(PK11_KeyGen(slot.get(), kMech, nullptr, 32, nullptr)); + EXPECT_TRUE(!!key); + + std::vector<uint8_t> iv(16); + SECStatus rv = PK11_GenerateRandomOnSlot(slot.get(), iv.data(), iv.size()); + EXPECT_EQ(SECSuccess, rv); + + SECItem ctrNonceItem = {siBuffer, toUcharPtr(iv.data()), + static_cast<unsigned int>(iv.size())}; + uint8_t encrypted[sizeof(kData)]; + unsigned int encrypted_len = 88; // This should be overwritten. + rv = PK11_Encrypt(key.get(), kMechXor, &ctrNonceItem, encrypted, + &encrypted_len, sizeof(encrypted), kData, sizeof(kData)); + ASSERT_EQ(SECSuccess, rv); + ASSERT_EQ(sizeof(kData), static_cast<size_t>(encrypted_len)); +} + +TEST_F(Pkcs11ChaCha20Poly1305Test, XorInvalidParams) { + ScopedPK11SlotInfo slot(PK11_GetInternalSlot()); + ScopedPK11SymKey key(PK11_KeyGen(slot.get(), kMech, nullptr, 32, nullptr)); + EXPECT_TRUE(!!key); + + SECItem ctrNonceItem = {siBuffer, toUcharPtr(kCtrNonce), + static_cast<unsigned int>(sizeof(kCtrNonce)) - 1}; + uint8_t encrypted[sizeof(kData)]; + unsigned int encrypted_len = 88; + SECStatus rv = + PK11_Encrypt(key.get(), kMechXor, &ctrNonceItem, encrypted, + &encrypted_len, sizeof(encrypted), kData, sizeof(kData)); + EXPECT_EQ(SECFailure, rv); + + ctrNonceItem.data = nullptr; + rv = PK11_Encrypt(key.get(), kMechXor, &ctrNonceItem, encrypted, + &encrypted_len, sizeof(encrypted), kData, sizeof(kData)); + EXPECT_EQ(SECFailure, rv); + EXPECT_EQ(SEC_ERROR_BAD_DATA, PORT_GetError()); +} + +TEST_P(Pkcs11ChaCha20Poly1305Test, TestVectors) { EncryptDecrypt(GetParam()); } + +INSTANTIATE_TEST_SUITE_P(NSSTestVector, Pkcs11ChaCha20Poly1305Test, + ::testing::ValuesIn(kChaCha20Vectors)); + +INSTANTIATE_TEST_SUITE_P(WycheproofTestVector, Pkcs11ChaCha20Poly1305Test, + ::testing::ValuesIn(kChaCha20WycheproofVectors)); + +// basic message interface it's the most common configuration +TEST_F(Pkcs11ChaCha20Poly1305Test, ChaCha201305MessageInterfaceBasic) { + MessageInterfaceTest(CKM_CHACHA20_POLY1305, 16, PR_FALSE); +} + +// basic interface, but return the tags in a separate buffer. This triggers +// different behaviour in the simulated case, which has to buffer the +// intermediate values in a separate buffer. +TEST_F(Pkcs11ChaCha20Poly1305Test, + ChaCha20Poly1305MessageInterfaceSeparateTags) { + MessageInterfaceTest(CKM_CHACHA20_POLY1305, 16, PR_TRUE); +} + +} // namespace nss_test diff --git a/security/nss/gtests/pk11_gtest/pk11_cipherop_unittest.cc b/security/nss/gtests/pk11_gtest/pk11_cipherop_unittest.cc new file mode 100644 index 0000000000..700750cc90 --- /dev/null +++ b/security/nss/gtests/pk11_gtest/pk11_cipherop_unittest.cc @@ -0,0 +1,129 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this file, +// You can obtain one at http://mozilla.org/MPL/2.0/. + +#include "gtest/gtest.h" + +#include <assert.h> +#include <limits.h> +#include <prinit.h> +#include <nss.h> +#include <pk11pub.h> + +static const size_t kKeyLen = 128 / 8; + +namespace nss_test { + +// +// The ciper tests using the bltest command cover a great deal of testing. +// However, Bug 1489691 revealed a corner case which is covered here. +// This test will make multiple calls to PK11_CipherOp using the same +// cipher context with data that is not cipher block aligned. +// + +static SECStatus GetBytes(PK11Context* ctx, uint8_t* bytes, size_t len) { + std::vector<uint8_t> in(len, 0); + + int outlen; + SECStatus rv = PK11_CipherOp(ctx, bytes, &outlen, len, &in[0], len); + if (static_cast<size_t>(outlen) != len) { + return SECFailure; + } + return rv; +} + +TEST(Pkcs11CipherOp, SingleCtxMultipleUnalignedCipherOps) { + PK11SlotInfo* slot; + PK11SymKey* key; + PK11Context* ctx; + + NSSInitContext* globalctx = + NSS_InitContext("", "", "", "", NULL, + NSS_INIT_READONLY | NSS_INIT_NOCERTDB | NSS_INIT_NOMODDB | + NSS_INIT_FORCEOPEN | NSS_INIT_NOROOTINIT); + + const CK_MECHANISM_TYPE cipher = CKM_AES_CTR; + + slot = PK11_GetInternalSlot(); + ASSERT_TRUE(slot); + + // Use arbitrary bytes for the AES key + uint8_t key_bytes[kKeyLen]; + for (size_t i = 0; i < kKeyLen; i++) { + key_bytes[i] = i; + } + + SECItem keyItem = {siBuffer, key_bytes, kKeyLen}; + + // The IV can be all zeros since we only encrypt once with + // each AES key. + CK_AES_CTR_PARAMS param = {128, {}}; + SECItem paramItem = {siBuffer, reinterpret_cast<unsigned char*>(¶m), + sizeof(CK_AES_CTR_PARAMS)}; + + key = PK11_ImportSymKey(slot, cipher, PK11_OriginUnwrap, CKA_ENCRYPT, + &keyItem, NULL); + ctx = PK11_CreateContextBySymKey(cipher, CKA_ENCRYPT, key, ¶mItem); + ASSERT_TRUE(key); + ASSERT_TRUE(ctx); + + uint8_t outbuf[128]; + ASSERT_EQ(GetBytes(ctx, outbuf, 7), SECSuccess); + ASSERT_EQ(GetBytes(ctx, outbuf, 17), SECSuccess); + + PK11_FreeSymKey(key); + PK11_FreeSlot(slot); + PK11_DestroyContext(ctx, PR_TRUE); + NSS_ShutdownContext(globalctx); +} + +TEST(Pkcs11CipherOp, SingleCtxMultipleUnalignedCipherOpsChaCha20) { + PK11SlotInfo* slot; + PK11SymKey* key; + PK11Context* ctx; + + NSSInitContext* globalctx = + NSS_InitContext("", "", "", "", NULL, + NSS_INIT_READONLY | NSS_INIT_NOCERTDB | NSS_INIT_NOMODDB | + NSS_INIT_FORCEOPEN | NSS_INIT_NOROOTINIT); + + const CK_MECHANISM_TYPE cipher = CKM_NSS_CHACHA20_CTR; + + slot = PK11_GetInternalSlot(); + ASSERT_TRUE(slot); + + // Use arbitrary bytes for the ChaCha20 key and IV + uint8_t key_bytes[32]; + for (size_t i = 0; i < 32; i++) { + key_bytes[i] = i; + } + SECItem keyItem = {siBuffer, key_bytes, 32}; + + uint8_t iv_bytes[16]; + for (size_t i = 0; i < 16; i++) { + key_bytes[i] = i; + } + SECItem ivItem = {siBuffer, iv_bytes, 16}; + + SECItem* param = PK11_ParamFromIV(cipher, &ivItem); + + key = PK11_ImportSymKey(slot, cipher, PK11_OriginUnwrap, CKA_ENCRYPT, + &keyItem, NULL); + ctx = PK11_CreateContextBySymKey(cipher, CKA_ENCRYPT, key, param); + ASSERT_TRUE(key); + ASSERT_TRUE(ctx); + + uint8_t outbuf[128]; + // This is supposed to fail for Chacha20. This is because the underlying + // PK11_CipherOp operation is calling the C_EncryptUpdate function for + // which multi-part is disabled for ChaCha20 in counter mode. + ASSERT_EQ(GetBytes(ctx, outbuf, 7), SECFailure); + + PK11_FreeSymKey(key); + PK11_FreeSlot(slot); + SECITEM_FreeItem(param, PR_TRUE); + PK11_DestroyContext(ctx, PR_TRUE); + NSS_ShutdownContext(globalctx); +} + +} // namespace nss_test diff --git a/security/nss/gtests/pk11_gtest/pk11_curve25519_unittest.cc b/security/nss/gtests/pk11_gtest/pk11_curve25519_unittest.cc new file mode 100644 index 0000000000..d3f3c37c43 --- /dev/null +++ b/security/nss/gtests/pk11_gtest/pk11_curve25519_unittest.cc @@ -0,0 +1,126 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include <memory> +#include "nss.h" +#include "pk11pub.h" +#include "prerror.h" +#include "cpputil.h" +#include "nss_scoped_ptrs.h" + +#include "testvectors/curve25519-vectors.h" +#include "gtest/gtest.h" + +namespace nss_test { + +class Pkcs11Curve25519Test + : public ::testing::TestWithParam<EcdhTestVectorStr> { + protected: + void Derive(const uint8_t* pkcs8, size_t pkcs8_len, const uint8_t* spki, + size_t spki_len, const uint8_t* secret, size_t secret_len, + bool expect_success) { + ScopedPK11SlotInfo slot(PK11_GetInternalKeySlot()); + ASSERT_TRUE(slot); + + SECItem pkcs8_item = {siBuffer, toUcharPtr(pkcs8), + static_cast<unsigned int>(pkcs8_len)}; + + SECKEYPrivateKey* key = nullptr; + SECStatus rv = PK11_ImportDERPrivateKeyInfoAndReturnKey( + slot.get(), &pkcs8_item, nullptr, nullptr, false, false, KU_ALL, &key, + nullptr); + EXPECT_EQ(SECSuccess, rv); + + ScopedSECKEYPrivateKey priv_key_sess(key); + ASSERT_TRUE(priv_key_sess); + + SECItem spki_item = {siBuffer, toUcharPtr(spki), + static_cast<unsigned int>(spki_len)}; + + ScopedCERTSubjectPublicKeyInfo cert_spki( + SECKEY_DecodeDERSubjectPublicKeyInfo(&spki_item)); + if (!expect_success && !cert_spki) { + return; + } + ASSERT_TRUE(cert_spki); + + ScopedSECKEYPublicKey pub_key_remote( + SECKEY_ExtractPublicKey(cert_spki.get())); + ASSERT_TRUE(pub_key_remote); + + // sym_key_sess = ECDH(session_import(private_test), public_test) + ScopedPK11SymKey sym_key_sess(PK11_PubDeriveWithKDF( + priv_key_sess.get(), pub_key_remote.get(), false, nullptr, nullptr, + CKM_ECDH1_DERIVE, CKM_SHA512_HMAC, CKA_DERIVE, 0, CKD_NULL, nullptr, + nullptr)); + ASSERT_EQ(expect_success, !!sym_key_sess); + + if (expect_success) { + rv = PK11_ExtractKeyValue(sym_key_sess.get()); + EXPECT_EQ(SECSuccess, rv); + + SECItem* key_data = PK11_GetKeyData(sym_key_sess.get()); + EXPECT_EQ(secret_len, key_data->len); + EXPECT_EQ(memcmp(key_data->data, secret, secret_len), 0); + + // Perform wrapped export on the imported private, import it as + // permanent, and verify we derive the same shared secret + static const uint8_t pw[] = "pw"; + SECItem pwItem = {siBuffer, toUcharPtr(pw), sizeof(pw)}; + ScopedSECKEYEncryptedPrivateKeyInfo epki(PK11_ExportEncryptedPrivKeyInfo( + slot.get(), SEC_OID_AES_256_CBC, &pwItem, priv_key_sess.get(), 1, + nullptr)); + ASSERT_NE(nullptr, epki) << "PK11_ExportEncryptedPrivKeyInfo failed: " + << PORT_ErrorToName(PORT_GetError()); + + ScopedSECKEYPublicKey pub_key_local( + SECKEY_ConvertToPublicKey(priv_key_sess.get())); + + SECKEYPrivateKey* priv_key_tok = nullptr; + rv = PK11_ImportEncryptedPrivateKeyInfoAndReturnKey( + slot.get(), epki.get(), &pwItem, nullptr, + &pub_key_local->u.ec.publicValue, PR_TRUE, PR_TRUE, ecKey, 0, + &priv_key_tok, nullptr); + ASSERT_EQ(SECSuccess, rv) << "PK11_ImportEncryptedPrivateKeyInfo failed " + << PORT_ErrorToName(PORT_GetError()); + ASSERT_TRUE(priv_key_tok); + + // sym_key_tok = ECDH(token_import(export(private_test)), + // public_test) + ScopedPK11SymKey sym_key_tok(PK11_PubDeriveWithKDF( + priv_key_tok, pub_key_remote.get(), false, nullptr, nullptr, + CKM_ECDH1_DERIVE, CKM_SHA512_HMAC, CKA_DERIVE, 0, CKD_NULL, nullptr, + nullptr)); + EXPECT_TRUE(sym_key_tok); + + if (sym_key_tok) { + rv = PK11_ExtractKeyValue(sym_key_tok.get()); + EXPECT_EQ(SECSuccess, rv); + + key_data = PK11_GetKeyData(sym_key_tok.get()); + EXPECT_EQ(secret_len, key_data->len); + EXPECT_EQ(memcmp(key_data->data, secret, secret_len), 0); + } + rv = PK11_DeleteTokenPrivateKey(priv_key_tok, true); + EXPECT_EQ(SECSuccess, rv); + } + }; + + void Derive(const EcdhTestVectorStr testvector) { + Derive(testvector.private_key.data(), testvector.private_key.size(), + testvector.public_key.data(), testvector.public_key.size(), + testvector.secret.data(), testvector.secret.size(), + testvector.valid); + }; +}; + +TEST_P(Pkcs11Curve25519Test, TestVectors) { Derive(GetParam()); } + +INSTANTIATE_TEST_SUITE_P(NSSTestVector, Pkcs11Curve25519Test, + ::testing::ValuesIn(kCurve25519Vectors)); + +INSTANTIATE_TEST_SUITE_P(WycheproofTestVector, Pkcs11Curve25519Test, + ::testing::ValuesIn(kCurve25519WycheproofVectors)); + +} // namespace nss_test diff --git a/security/nss/gtests/pk11_gtest/pk11_der_private_key_import_unittest.cc b/security/nss/gtests/pk11_gtest/pk11_der_private_key_import_unittest.cc new file mode 100644 index 0000000000..449e7728b2 --- /dev/null +++ b/security/nss/gtests/pk11_gtest/pk11_der_private_key_import_unittest.cc @@ -0,0 +1,162 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include <climits> +#include <memory> +#include "nss.h" +#include "pk11pub.h" +#include "secutil.h" + +#include "gtest/gtest.h" +#include "nss_scoped_ptrs.h" + +namespace nss_test { + +const std::vector<uint8_t> kValidP256Key = { + 0x30, 0x81, 0x87, 0x02, 0x01, 0x00, 0x30, 0x13, 0x06, 0x07, 0x2a, 0x86, + 0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, + 0x03, 0x01, 0x07, 0x04, 0x6d, 0x30, 0x6b, 0x02, 0x01, 0x01, 0x04, 0x20, + 0xc9, 0xaf, 0xa9, 0xd8, 0x45, 0xba, 0x75, 0x16, 0x6b, 0x5c, 0x21, 0x57, + 0x67, 0xb1, 0xd6, 0x93, 0x4e, 0x50, 0xc3, 0xdb, 0x36, 0xe8, 0x9b, 0x12, + 0x7b, 0x8a, 0x62, 0x2b, 0x12, 0x0f, 0x67, 0x21, 0xa1, 0x44, 0x03, 0x42, + 0x00, 0x04, 0x60, 0xfe, 0xd4, 0xba, 0x25, 0x5a, 0x9d, 0x31, 0xc9, 0x61, + 0xeb, 0x74, 0xc6, 0x35, 0x6d, 0x68, 0xc0, 0x49, 0xb8, 0x92, 0x3b, 0x61, + 0xfa, 0x6c, 0xe6, 0x69, 0x62, 0x2e, 0x60, 0xf2, 0x9f, 0xb6, 0x79, 0x03, + 0xfe, 0x10, 0x08, 0xb8, 0xbc, 0x99, 0xa4, 0x1a, 0xe9, 0xe9, 0x56, 0x28, + 0xbc, 0x64, 0xf2, 0xf1, 0xb2, 0x0c, 0x2d, 0x7e, 0x9f, 0x51, 0x77, 0xa3, + 0xc2, 0x94, 0xd4, 0x46, 0x22, 0x99}; + +const std::vector<uint8_t> kValidRSAKey = { + // 512-bit RSA private key (PKCS#8) + 0x30, 0x82, 0x01, 0x54, 0x02, 0x01, 0x00, 0x30, 0x0d, 0x06, 0x09, 0x2a, + 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x04, 0x82, + 0x01, 0x3e, 0x30, 0x82, 0x01, 0x3a, 0x02, 0x01, 0x00, 0x02, 0x41, 0x00, + 0xa2, 0x40, 0xce, 0xb5, 0x4e, 0x70, 0xdc, 0x14, 0x82, 0x5b, 0x58, 0x7d, + 0x2f, 0x5d, 0xfd, 0x46, 0x3c, 0x4b, 0x82, 0x50, 0xb6, 0x96, 0x00, 0x4a, + 0x1a, 0xca, 0xaf, 0xe4, 0x9b, 0xcf, 0x38, 0x4a, 0x46, 0xaa, 0x9f, 0xb4, + 0xd9, 0xc7, 0xee, 0x88, 0xe9, 0xef, 0x0a, 0x31, 0x5f, 0x53, 0x86, 0x8f, + 0x63, 0x68, 0x0b, 0x58, 0x34, 0x72, 0x49, 0xba, 0xed, 0xd9, 0x34, 0x15, + 0x16, 0xc4, 0xca, 0xb7, 0x02, 0x03, 0x01, 0x00, 0x01, 0x02, 0x40, 0x34, + 0xe6, 0xdc, 0x7e, 0xd0, 0xec, 0x8b, 0x55, 0x44, 0x8b, 0x73, 0xf6, 0x9d, + 0x13, 0x10, 0x19, 0x6e, 0x5f, 0x50, 0x45, 0xf0, 0xc2, 0x47, 0xa5, 0xe1, + 0xc6, 0x64, 0x43, 0x2d, 0x6a, 0x0a, 0xf7, 0xe7, 0xda, 0x40, 0xb8, 0x3a, + 0xf0, 0x47, 0xdd, 0x01, 0xf5, 0xe0, 0xa9, 0x0e, 0x47, 0xc2, 0x24, 0xd7, + 0xb5, 0x13, 0x3a, 0x35, 0x4d, 0x11, 0xaa, 0x50, 0x03, 0xb3, 0xe8, 0x54, + 0x6c, 0x99, 0x01, 0x02, 0x21, 0x00, 0xcd, 0xb2, 0xd7, 0xa7, 0x43, 0x5b, + 0xcb, 0x45, 0xe5, 0x0e, 0x86, 0xf6, 0xc1, 0x4e, 0x97, 0xed, 0x78, 0x1f, + 0x09, 0x56, 0xcd, 0x26, 0xe6, 0xf7, 0x5e, 0xd9, 0xfc, 0x88, 0x12, 0x5f, + 0x84, 0x07, 0x02, 0x21, 0x00, 0xc9, 0xee, 0x30, 0xaf, 0x6c, 0xb9, 0x5a, + 0xc9, 0xc1, 0x14, 0x9e, 0xd8, 0x4b, 0x33, 0x38, 0x48, 0x17, 0x41, 0x35, + 0x94, 0x09, 0xf3, 0x69, 0xc4, 0x97, 0xbe, 0x17, 0x7d, 0x95, 0x0f, 0xb7, + 0xd1, 0x02, 0x21, 0x00, 0x8b, 0x0e, 0xf9, 0x8d, 0x61, 0x13, 0x20, 0x63, + 0x9b, 0x0b, 0x6c, 0x20, 0x4a, 0xe4, 0xa7, 0xfe, 0xe8, 0xf3, 0x0a, 0x6c, + 0x3c, 0xfa, 0xac, 0xaf, 0xd4, 0xd6, 0xc7, 0x4a, 0xf2, 0x28, 0xd2, 0x67, + 0x02, 0x20, 0x6b, 0x0e, 0x1d, 0xbf, 0x93, 0x5b, 0xbd, 0x77, 0x43, 0x27, + 0x24, 0x83, 0xb5, 0x72, 0xa5, 0x3f, 0x0b, 0x1d, 0x26, 0x43, 0xa2, 0xf6, + 0xea, 0xb7, 0x30, 0x5f, 0xb6, 0x62, 0x7c, 0xf9, 0x85, 0x51, 0x02, 0x20, + 0x3d, 0x22, 0x63, 0x15, 0x6b, 0x32, 0x41, 0x46, 0x44, 0x78, 0xb7, 0x13, + 0xeb, 0x85, 0x4c, 0x4f, 0x6b, 0x3e, 0xf0, 0x52, 0xf0, 0x46, 0x3b, 0x65, + 0xd8, 0x21, 0x7d, 0xae, 0xc0, 0x09, 0x98, 0x34}; + +const std::vector<uint8_t> kInvalidLengthKey = { + 0x30, 0x1b, // SEQUENCE(len=27) + 0x02, 0x01, 0x00, // INT(len=1) = 0 + 0x30, 0x13, // SEQUENCE(len=19) + 0x06, 0x07, // OID(len=7) + // dhPublicKey (1.2.840.10046.2.1) + 0x2a, 0x86, 0x48, 0xce, 0x3e, 0x02, 0x01, 0x06, 0x08, // OID(len=8) + // prime256v1 (1.2.840.10045.3.1.7) */ + 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07, 0x04, + 0x00 // OCTET STRING(len=0) +}; + +const std::vector<uint8_t> kInvalidZeroLengthKey = { + 0x30, 0x1a, // SEQUENCE(len=26) + 0x02, 0x01, 0x00, // INT(len=1) = 0 + 0x30, 0x13, // SEQUENCE(len=19) + 0x06, 0x07, // OID(len=7) + // dhPublicKey (1.2.840.10046.2.1) + 0x2a, 0x86, 0x48, 0xce, 0x3e, 0x02, 0x01, 0x06, 0x08, // OID(len=8) + // prime256v1 (1.2.840.10045.3.1.7) */ + 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07, 0x04, + 0x00 // OCTET STRING(len=0) +}; + +class DERPrivateKeyImportTest : public ::testing::Test { + public: + bool ParsePrivateKey(const std::vector<uint8_t>& data, bool expect_success) { + SECKEYPrivateKey* key = nullptr; + SECStatus rv = SECFailure; + std::string nick_str = + ::testing::UnitTest::GetInstance()->current_test_info()->name() + + std::to_string(rand()); + SECItem item = {siBuffer, const_cast<unsigned char*>(data.data()), + static_cast<unsigned int>(data.size())}; + SECItem nick = {siBuffer, reinterpret_cast<unsigned char*>( + const_cast<char*>(nick_str.data())), + static_cast<unsigned int>(nick_str.length())}; + + ScopedPK11SlotInfo slot(PK11_GetInternalKeySlot()); + EXPECT_TRUE(slot); + if (!slot) { + return false; + } + + if (PK11_NeedUserInit(slot.get())) { + if (PK11_InitPin(slot.get(), nullptr, nullptr) != SECSuccess) { + EXPECT_EQ(rv, SECSuccess) << "PK11_InitPin failed"; + } + } + rv = PK11_Authenticate(slot.get(), PR_TRUE, nullptr); + EXPECT_EQ(rv, SECSuccess); + + rv = PK11_ImportDERPrivateKeyInfoAndReturnKey( + slot.get(), &item, &nick, nullptr, true, false, KU_ALL, &key, nullptr); + EXPECT_EQ(rv == SECSuccess, key != nullptr); + + if (expect_success) { + // Try to find the key via its label + ScopedSECKEYPrivateKeyList list(PK11_ListPrivKeysInSlot( + slot.get(), const_cast<char*>(nick_str.c_str()), nullptr)); + EXPECT_FALSE(!list); + } + + if (key) { + rv = PK11_DeleteTokenPrivateKey(key, true); + EXPECT_EQ(SECSuccess, rv); + + // PK11_DeleteTokenPrivateKey leaves an errorCode set when there's + // no cert. This is expected, so clear it. + if (PORT_GetError() == SSL_ERROR_NO_CERTIFICATE) { + PORT_SetError(0); + } + } + + return rv == SECSuccess; + } +}; + +TEST_F(DERPrivateKeyImportTest, ImportPrivateRSAKey) { + EXPECT_TRUE(ParsePrivateKey(kValidRSAKey, true)); + EXPECT_FALSE(PORT_GetError()) << PORT_GetError(); +} + +TEST_F(DERPrivateKeyImportTest, ImportEcdsaKey) { + EXPECT_TRUE(ParsePrivateKey(kValidP256Key, true)); + EXPECT_FALSE(PORT_GetError()) << PORT_GetError(); +} + +TEST_F(DERPrivateKeyImportTest, ImportInvalidPrivateKey) { + EXPECT_FALSE(ParsePrivateKey(kInvalidLengthKey, false)); + EXPECT_EQ(PORT_GetError(), SEC_ERROR_BAD_DER) << PORT_GetError(); +} + +TEST_F(DERPrivateKeyImportTest, ImportZeroLengthPrivateKey) { + EXPECT_FALSE(ParsePrivateKey(kInvalidZeroLengthKey, false)); + EXPECT_EQ(PORT_GetError(), SEC_ERROR_BAD_KEY) << PORT_GetError(); +} + +} // namespace nss_test diff --git a/security/nss/gtests/pk11_gtest/pk11_des_unittest.cc b/security/nss/gtests/pk11_gtest/pk11_des_unittest.cc new file mode 100644 index 0000000000..30f1afb8d9 --- /dev/null +++ b/security/nss/gtests/pk11_gtest/pk11_des_unittest.cc @@ -0,0 +1,65 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include <memory> +#include "nss.h" +#include "pk11pub.h" + +#include "nss_scoped_ptrs.h" + +#include "gtest/gtest.h" + +namespace nss_test { + +class Pkcs11DesTest : public ::testing::Test { + protected: + SECStatus EncryptWithIV(std::vector<uint8_t>& iv, + const CK_MECHANISM_TYPE mech) { + // Generate a random key. + ScopedPK11SlotInfo slot(PK11_GetInternalSlot()); + ScopedPK11SymKey sym_key( + PK11_KeyGen(slot.get(), mech, nullptr, 8, nullptr)); + EXPECT_TRUE(!!sym_key); + + std::vector<uint8_t> data(16); + std::vector<uint8_t> output(16); + + SECItem params = {siBuffer, iv.data(), + static_cast<unsigned int>(iv.size())}; + + // Try to encrypt. + unsigned int output_len = 0; + return PK11_Encrypt(sym_key.get(), mech, ¶ms, output.data(), + &output_len, output.size(), data.data(), data.size()); + } +}; + +TEST_F(Pkcs11DesTest, ZeroLengthIV) { + std::vector<uint8_t> iv(0); + EXPECT_EQ(SECFailure, EncryptWithIV(iv, CKM_DES_CBC)); + EXPECT_EQ(SECFailure, EncryptWithIV(iv, CKM_DES3_CBC)); +} + +TEST_F(Pkcs11DesTest, IVTooShort) { + std::vector<uint8_t> iv(7); + EXPECT_EQ(SECFailure, EncryptWithIV(iv, CKM_DES_CBC)); + EXPECT_EQ(SECFailure, EncryptWithIV(iv, CKM_DES3_CBC)); +} + +TEST_F(Pkcs11DesTest, WrongLengthIV) { + // We tolerate IVs > 8 + std::vector<uint8_t> iv(15, 0); + EXPECT_EQ(SECSuccess, EncryptWithIV(iv, CKM_DES_CBC)); + EXPECT_EQ(SECSuccess, EncryptWithIV(iv, CKM_DES3_CBC)); +} + +TEST_F(Pkcs11DesTest, AllGood) { + std::vector<uint8_t> iv(8, 0); + EXPECT_EQ(SECSuccess, EncryptWithIV(iv, CKM_DES_CBC)); + EXPECT_EQ(SECSuccess, EncryptWithIV(iv, CKM_DES3_CBC)); +} + +} // namespace nss_test diff --git a/security/nss/gtests/pk11_gtest/pk11_dsa_unittest.cc b/security/nss/gtests/pk11_gtest/pk11_dsa_unittest.cc new file mode 100644 index 0000000000..0c776c9f1d --- /dev/null +++ b/security/nss/gtests/pk11_gtest/pk11_dsa_unittest.cc @@ -0,0 +1,79 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include <memory> +#include "nss.h" +#include "pk11pub.h" +#include "sechash.h" +#include "cryptohi.h" + +#include "cpputil.h" +#include "databuffer.h" + +#include "gtest/gtest.h" +#include "nss_scoped_ptrs.h" + +#include "testvectors/dsa-vectors.h" + +namespace nss_test { + +class Pkcs11DsaTest : public ::testing::TestWithParam<DsaTestVector> { + protected: + void Derive(const uint8_t* sig, size_t sig_len, const uint8_t* spki, + size_t spki_len, const uint8_t* data, size_t data_len, + bool expect_success, const uint32_t test_id, + const SECOidTag hash_oid) { + std::stringstream s; + s << "Test with original ID #" << test_id << " failed.\n"; + s << "Expected Success: " << expect_success << "\n"; + std::string msg = s.str(); + + SECItem spki_item = {siBuffer, toUcharPtr(spki), + static_cast<unsigned int>(spki_len)}; + + ScopedCERTSubjectPublicKeyInfo cert_spki( + SECKEY_DecodeDERSubjectPublicKeyInfo(&spki_item)); + ASSERT_TRUE(cert_spki) << msg; + + ScopedSECKEYPublicKey pub_key(SECKEY_ExtractPublicKey(cert_spki.get())); + ASSERT_TRUE(pub_key) << msg; + + SECItem sig_item = {siBuffer, toUcharPtr(sig), + static_cast<unsigned int>(sig_len)}; + ScopedSECItem decoded_sig_item( + DSAU_DecodeDerSigToLen(&sig_item, SECKEY_SignatureLen(pub_key.get()))); + if (!decoded_sig_item) { + ASSERT_FALSE(expect_success) << msg; + return; + } + + DataBuffer hash; + hash.Allocate(static_cast<size_t>(HASH_ResultLenByOidTag(hash_oid))); + SECStatus rv = PK11_HashBuf(hash_oid, toUcharPtr(hash.data()), + toUcharPtr(data), data_len); + ASSERT_EQ(SECSuccess, rv) << msg; + + // Verify. + SECItem hash_item = {siBuffer, toUcharPtr(hash.data()), + static_cast<unsigned int>(hash.len())}; + rv = PK11_VerifyWithMechanism(pub_key.get(), CKM_DSA, nullptr, + decoded_sig_item.get(), &hash_item, nullptr); + EXPECT_EQ(expect_success ? SECSuccess : SECFailure, rv); + }; + + void Derive(const DsaTestVector vector) { + Derive(vector.sig.data(), vector.sig.size(), vector.public_key.data(), + vector.public_key.size(), vector.msg.data(), vector.msg.size(), + vector.valid, vector.id, vector.hash_oid); + }; +}; + +TEST_P(Pkcs11DsaTest, WycheproofVectors) { Derive(GetParam()); } + +INSTANTIATE_TEST_SUITE_P(DsaTest, Pkcs11DsaTest, + ::testing::ValuesIn(kDsaWycheproofVectors)); + +} // namespace nss_test diff --git a/security/nss/gtests/pk11_gtest/pk11_ecdh_unittest.cc b/security/nss/gtests/pk11_gtest/pk11_ecdh_unittest.cc new file mode 100644 index 0000000000..6ca1752bb3 --- /dev/null +++ b/security/nss/gtests/pk11_gtest/pk11_ecdh_unittest.cc @@ -0,0 +1,86 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include <memory> +#include "nss.h" +#include "pk11pub.h" + +#include "cpputil.h" +#include "nss_scoped_ptrs.h" + +#include "testvectors/p256ecdh-vectors.h" +#include "testvectors/p384ecdh-vectors.h" +#include "testvectors/p521ecdh-vectors.h" +#include "gtest/gtest.h" + +namespace nss_test { + +class Pkcs11EcdhTest : public ::testing::TestWithParam<EcdhTestVector> { + protected: + void Derive(const EcdhTestVector vec) { + std::string err = "Test #" + std::to_string(vec.id) + " failed"; + + SECItem expect_item = {siBuffer, toUcharPtr(vec.secret.data()), + static_cast<unsigned int>(vec.secret.size())}; + + ScopedPK11SlotInfo slot(PK11_GetInternalSlot()); + ASSERT_TRUE(slot); + + SECItem priv_item = {siBuffer, toUcharPtr(vec.private_key.data()), + static_cast<unsigned int>(vec.private_key.size())}; + SECKEYPrivateKey* key = nullptr; + SECStatus rv = PK11_ImportDERPrivateKeyInfoAndReturnKey( + slot.get(), &priv_item, nullptr, nullptr, false, false, KU_ALL, &key, + nullptr); + EXPECT_EQ(SECSuccess, rv) << err; + + ScopedSECKEYPrivateKey priv_key(key); + ASSERT_TRUE(priv_key) << err; + + SECItem spki_item = {siBuffer, toUcharPtr(vec.public_key.data()), + static_cast<unsigned int>(vec.public_key.size())}; + + ScopedCERTSubjectPublicKeyInfo cert_spki( + SECKEY_DecodeDERSubjectPublicKeyInfo(&spki_item)); + if (vec.valid) { + ASSERT_TRUE(!!cert_spki) << err; + } else if (!cert_spki) { + ASSERT_TRUE(vec.invalid_asn) << err; + return; + } + + ScopedSECKEYPublicKey pub_key(SECKEY_ExtractPublicKey(cert_spki.get())); + if (vec.valid) { + ASSERT_TRUE(!!pub_key) << err; + } else if (!pub_key) { + ASSERT_FALSE(vec.valid) << err; + return; + } + + ScopedPK11SymKey sym_key( + PK11_PubDeriveWithKDF(priv_key.get(), pub_key.get(), false, nullptr, + nullptr, CKM_ECDH1_DERIVE, CKM_SHA512_HMAC, + CKA_DERIVE, 0, CKD_NULL, nullptr, nullptr)); + ASSERT_EQ(vec.valid, !!sym_key) << err; + + if (vec.valid) { + rv = PK11_ExtractKeyValue(sym_key.get()); + EXPECT_EQ(SECSuccess, rv) << err; + + SECItem* derived_key = PK11_GetKeyData(sym_key.get()); + EXPECT_EQ(0, SECITEM_CompareItem(derived_key, &expect_item)) << err; + } + }; +}; + +TEST_P(Pkcs11EcdhTest, TestVectors) { Derive(GetParam()); } + +INSTANTIATE_TEST_SUITE_P(WycheproofP256EcdhTest, Pkcs11EcdhTest, + ::testing::ValuesIn(kP256EcdhWycheproofVectors)); +INSTANTIATE_TEST_SUITE_P(WycheproofP384EcdhTest, Pkcs11EcdhTest, + ::testing::ValuesIn(kP384EcdhWycheproofVectors)); +INSTANTIATE_TEST_SUITE_P(WycheproofP521EcdhTest, Pkcs11EcdhTest, + ::testing::ValuesIn(kP521EcdhWycheproofVectors)); + +} // namespace nss_test diff --git a/security/nss/gtests/pk11_gtest/pk11_ecdsa_unittest.cc b/security/nss/gtests/pk11_gtest/pk11_ecdsa_unittest.cc new file mode 100644 index 0000000000..c127004c8f --- /dev/null +++ b/security/nss/gtests/pk11_gtest/pk11_ecdsa_unittest.cc @@ -0,0 +1,223 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include <memory> +#include "nss.h" +#include "pk11pub.h" +#include "sechash.h" +#include "cryptohi.h" + +#include "gtest/gtest.h" +#include "nss_scoped_ptrs.h" + +#include "pk11_ecdsa_vectors.h" +#include "pk11_signature_test.h" +#include "testvectors/p256ecdsa-sha256-vectors.h" +#include "testvectors/p384ecdsa-sha384-vectors.h" +#include "testvectors/p521ecdsa-sha512-vectors.h" + +namespace nss_test { + +class Pkcs11EcdsaTestBase : public Pk11SignatureTest { + protected: + Pkcs11EcdsaTestBase(SECOidTag hash_oid) + : Pk11SignatureTest(CKM_ECDSA, hash_oid) {} +}; + +struct Pkcs11EcdsaTestParams { + SECOidTag hash_oid_; + Pkcs11SignatureTestParams sig_params_; +}; + +class Pkcs11EcdsaTest + : public Pkcs11EcdsaTestBase, + public ::testing::WithParamInterface<Pkcs11EcdsaTestParams> { + public: + Pkcs11EcdsaTest() : Pkcs11EcdsaTestBase(GetParam().hash_oid_) {} +}; + +TEST_P(Pkcs11EcdsaTest, Verify) { Verify(GetParam().sig_params_); } + +TEST_P(Pkcs11EcdsaTest, SignAndVerify) { + SignAndVerify(GetParam().sig_params_); +} + +static const Pkcs11EcdsaTestParams kEcdsaVectors[] = { + {SEC_OID_SHA256, + {DataBuffer(kP256Pkcs8, sizeof(kP256Pkcs8)), + DataBuffer(kP256Spki, sizeof(kP256Spki)), + DataBuffer(kP256Data, sizeof(kP256Data)), + DataBuffer(kP256Signature, sizeof(kP256Signature))}}, + {SEC_OID_SHA256, + {DataBuffer(kP256Pkcs8ZeroPad, sizeof(kP256Pkcs8ZeroPad)), + DataBuffer(kP256SpkiZeroPad, sizeof(kP256SpkiZeroPad)), + DataBuffer(kP256DataZeroPad, sizeof(kP256DataZeroPad)), + DataBuffer(kP256SignatureZeroPad, sizeof(kP256SignatureZeroPad))}}, + {SEC_OID_SHA384, + {DataBuffer(kP384Pkcs8, sizeof(kP384Pkcs8)), + DataBuffer(kP384Spki, sizeof(kP384Spki)), + DataBuffer(kP384Data, sizeof(kP384Data)), + DataBuffer(kP384Signature, sizeof(kP384Signature))}}, + {SEC_OID_SHA512, + {DataBuffer(kP521Pkcs8, sizeof(kP521Pkcs8)), + DataBuffer(kP521Spki, sizeof(kP521Spki)), + DataBuffer(kP521Data, sizeof(kP521Data)), + DataBuffer(kP521Signature, sizeof(kP521Signature))}}}; + +INSTANTIATE_TEST_SUITE_P(EcdsaSignVerify, Pkcs11EcdsaTest, + ::testing::ValuesIn(kEcdsaVectors)); + +class Pkcs11EcdsaSha256Test : public Pkcs11EcdsaTestBase { + public: + Pkcs11EcdsaSha256Test() : Pkcs11EcdsaTestBase(SEC_OID_SHA256) {} +}; + +// Importing a private key in PKCS#8 format must fail when the outer AlgID +// struct contains neither id-ecPublicKey nor a namedCurve parameter. +TEST_F(Pkcs11EcdsaSha256Test, ImportNoCurveOIDOrAlgorithmParams) { + DataBuffer k(kP256Pkcs8NoCurveOIDOrAlgorithmParams, + sizeof(kP256Pkcs8NoCurveOIDOrAlgorithmParams)); + EXPECT_FALSE(ImportPrivateKey(k)); +}; + +// Importing a private key in PKCS#8 format must succeed when only the outer +// AlgID struct contains the namedCurve parameters. +TEST_F(Pkcs11EcdsaSha256Test, ImportOnlyAlgorithmParams) { + DataBuffer k(kP256Pkcs8OnlyAlgorithmParams, + sizeof(kP256Pkcs8OnlyAlgorithmParams)); + DataBuffer data(kP256Data, sizeof(kP256Data)); + DataBuffer sig; + EXPECT_TRUE(ImportPrivateKeyAndSignHashedData(k, data, &sig)); +}; + +// Importing a private key in PKCS#8 format must succeed when the outer AlgID +// struct and the inner ECPrivateKey contain the same namedCurve parameters. +// The inner curveOID is always ignored, so only the outer one will be used. +TEST_F(Pkcs11EcdsaSha256Test, ImportMatchingCurveOIDAndAlgorithmParams) { + DataBuffer k(kP256Pkcs8MatchingCurveOIDAndAlgorithmParams, + sizeof(kP256Pkcs8MatchingCurveOIDAndAlgorithmParams)); + DataBuffer data(kP256Data, sizeof(kP256Data)); + DataBuffer sig; + EXPECT_TRUE(ImportPrivateKeyAndSignHashedData(k, data, &sig)); +}; + +// Importing a private key in PKCS#8 format must succeed when the outer AlgID +// struct and the inner ECPrivateKey contain dissimilar namedCurve parameters. +// The inner curveOID is always ignored, so only the outer one will be used. +TEST_F(Pkcs11EcdsaSha256Test, ImportDissimilarCurveOIDAndAlgorithmParams) { + DataBuffer k(kP256Pkcs8DissimilarCurveOIDAndAlgorithmParams, + sizeof(kP256Pkcs8DissimilarCurveOIDAndAlgorithmParams)); + DataBuffer data(kP256Data, sizeof(kP256Data)); + DataBuffer sig; + EXPECT_TRUE(ImportPrivateKeyAndSignHashedData(k, data, &sig)); +}; + +// Importing a private key in PKCS#8 format must fail when the outer ASN.1 +// AlgorithmID struct contains only id-ecPublicKey but no namedCurve parameter. +TEST_F(Pkcs11EcdsaSha256Test, ImportNoAlgorithmParams) { + DataBuffer k(kP256Pkcs8NoAlgorithmParams, + sizeof(kP256Pkcs8NoAlgorithmParams)); + EXPECT_FALSE(ImportPrivateKey(k)); +}; + +// Importing a private key in PKCS#8 format must fail when id-ecPublicKey is +// given (so we know it's an EC key) but the namedCurve parameter is unknown. +TEST_F(Pkcs11EcdsaSha256Test, ImportInvalidAlgorithmParams) { + DataBuffer k(kP256Pkcs8InvalidAlgorithmParams, + sizeof(kP256Pkcs8InvalidAlgorithmParams)); + EXPECT_FALSE(ImportPrivateKey(k)); +}; + +// Importing a private key in PKCS#8 format with a point not on the curve will +// succeed. Using the contained public key however will fail when trying to +// import it before using it for any operation. +TEST_F(Pkcs11EcdsaSha256Test, ImportPointNotOnCurve) { + DataBuffer k(kP256Pkcs8PointNotOnCurve, sizeof(kP256Pkcs8PointNotOnCurve)); + ScopedSECKEYPrivateKey privKey(ImportPrivateKey(k)); + ASSERT_TRUE(privKey); + + ScopedSECKEYPublicKey pubKey(SECKEY_ConvertToPublicKey(privKey.get())); + ASSERT_TRUE(pubKey); + + ScopedPK11SlotInfo slot(PK11_GetInternalSlot()); + ASSERT_TRUE(slot); + + auto handle = PK11_ImportPublicKey(slot.get(), pubKey.get(), false); + EXPECT_EQ(handle, static_cast<decltype(handle)>(CK_INVALID_HANDLE)); +}; + +// Importing a private key in PKCS#8 format must fail when no point is given. +// PK11 currently offers no APIs to derive raw public keys from private values. +TEST_F(Pkcs11EcdsaSha256Test, ImportNoPublicKey) { + DataBuffer k(kP256Pkcs8NoPublicKey, sizeof(kP256Pkcs8NoPublicKey)); + EXPECT_FALSE(ImportPrivateKey(k)); +}; + +// Importing a public key in SPKI format must fail when id-ecPublicKey is +// given (so we know it's an EC key) but the namedCurve parameter is missing. +TEST_F(Pkcs11EcdsaSha256Test, ImportSpkiNoAlgorithmParams) { + DataBuffer k(kP256SpkiNoAlgorithmParams, sizeof(kP256SpkiNoAlgorithmParams)); + EXPECT_FALSE(ImportPublicKey(k)); +} + +// Importing a public key in SPKI format with a point not on the curve will +// succeed. Using the public key however will fail when trying to import +// it before using it for any operation. +TEST_F(Pkcs11EcdsaSha256Test, ImportSpkiPointNotOnCurve) { + DataBuffer k(kP256SpkiPointNotOnCurve, sizeof(kP256SpkiPointNotOnCurve)); + ScopedSECKEYPublicKey pubKey(ImportPublicKey(k)); + ASSERT_TRUE(pubKey); + + ScopedPK11SlotInfo slot(PK11_GetInternalSlot()); + ASSERT_TRUE(slot); + + auto handle = PK11_ImportPublicKey(slot.get(), pubKey.get(), false); + EXPECT_EQ(handle, static_cast<decltype(handle)>(CK_INVALID_HANDLE)); +} + +class Pkcs11EcdsaWycheproofTest + : public ::testing::TestWithParam<EcdsaTestVector> { + protected: + void Derive(const EcdsaTestVector vec) { + SECItem spki_item = {siBuffer, toUcharPtr(vec.public_key.data()), + static_cast<unsigned int>(vec.public_key.size())}; + SECItem sig_item = {siBuffer, toUcharPtr(vec.sig.data()), + static_cast<unsigned int>(vec.sig.size())}; + + DataBuffer hash; + hash.Allocate(static_cast<size_t>(HASH_ResultLenByOidTag(vec.hash_oid))); + SECStatus rv = PK11_HashBuf(vec.hash_oid, toUcharPtr(hash.data()), + toUcharPtr(vec.msg.data()), vec.msg.size()); + ASSERT_EQ(rv, SECSuccess); + SECItem hash_item = {siBuffer, toUcharPtr(hash.data()), + static_cast<unsigned int>(hash.len())}; + + ScopedCERTSubjectPublicKeyInfo cert_spki( + SECKEY_DecodeDERSubjectPublicKeyInfo(&spki_item)); + ASSERT_TRUE(cert_spki); + ScopedSECKEYPublicKey pub_key(SECKEY_ExtractPublicKey(cert_spki.get())); + ASSERT_TRUE(pub_key); + + rv = VFY_VerifyDigestDirect(&hash_item, pub_key.get(), &sig_item, + SEC_OID_ANSIX962_EC_PUBLIC_KEY, vec.hash_oid, + nullptr); + EXPECT_EQ(rv, vec.valid ? SECSuccess : SECFailure); + }; +}; + +TEST_P(Pkcs11EcdsaWycheproofTest, Verify) { Derive(GetParam()); } + +INSTANTIATE_TEST_SUITE_P(WycheproofP256SignatureSha256Test, + Pkcs11EcdsaWycheproofTest, + ::testing::ValuesIn(kP256EcdsaSha256Vectors)); + +INSTANTIATE_TEST_SUITE_P(WycheproofP384SignatureSha384Test, + Pkcs11EcdsaWycheproofTest, + ::testing::ValuesIn(kP384EcdsaSha384Vectors)); + +INSTANTIATE_TEST_SUITE_P(WycheproofP521SignatureSha512Test, + Pkcs11EcdsaWycheproofTest, + ::testing::ValuesIn(kP521EcdsaSha512Vectors)); + +} // namespace nss_test diff --git a/security/nss/gtests/pk11_gtest/pk11_ecdsa_vectors.h b/security/nss/gtests/pk11_gtest/pk11_ecdsa_vectors.h new file mode 100644 index 0000000000..9f625dd081 --- /dev/null +++ b/security/nss/gtests/pk11_gtest/pk11_ecdsa_vectors.h @@ -0,0 +1,283 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +namespace nss_test { + +// ECDSA test vector, A.2.5. ECDSA, 256 Bits (Prime Field), SHA-256 +// <https://tools.ietf.org/html/rfc6979#appendix-A.2.5> +const uint8_t kP256Pkcs8[] = { + 0x30, 0x81, 0x87, 0x02, 0x01, 0x00, 0x30, 0x13, 0x06, 0x07, 0x2a, 0x86, + 0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, + 0x03, 0x01, 0x07, 0x04, 0x6d, 0x30, 0x6b, 0x02, 0x01, 0x01, 0x04, 0x20, + 0xc9, 0xaf, 0xa9, 0xd8, 0x45, 0xba, 0x75, 0x16, 0x6b, 0x5c, 0x21, 0x57, + 0x67, 0xb1, 0xd6, 0x93, 0x4e, 0x50, 0xc3, 0xdb, 0x36, 0xe8, 0x9b, 0x12, + 0x7b, 0x8a, 0x62, 0x2b, 0x12, 0x0f, 0x67, 0x21, 0xa1, 0x44, 0x03, 0x42, + 0x00, 0x04, 0x60, 0xfe, 0xd4, 0xba, 0x25, 0x5a, 0x9d, 0x31, 0xc9, 0x61, + 0xeb, 0x74, 0xc6, 0x35, 0x6d, 0x68, 0xc0, 0x49, 0xb8, 0x92, 0x3b, 0x61, + 0xfa, 0x6c, 0xe6, 0x69, 0x62, 0x2e, 0x60, 0xf2, 0x9f, 0xb6, 0x79, 0x03, + 0xfe, 0x10, 0x08, 0xb8, 0xbc, 0x99, 0xa4, 0x1a, 0xe9, 0xe9, 0x56, 0x28, + 0xbc, 0x64, 0xf2, 0xf1, 0xb2, 0x0c, 0x2d, 0x7e, 0x9f, 0x51, 0x77, 0xa3, + 0xc2, 0x94, 0xd4, 0x46, 0x22, 0x99}; +const uint8_t kP256Spki[] = { + 0x30, 0x59, 0x30, 0x13, 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, + 0x01, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07, 0x03, + 0x42, 0x00, 0x04, 0x60, 0xfe, 0xd4, 0xba, 0x25, 0x5a, 0x9d, 0x31, 0xc9, + 0x61, 0xeb, 0x74, 0xc6, 0x35, 0x6d, 0x68, 0xc0, 0x49, 0xb8, 0x92, 0x3b, + 0x61, 0xfa, 0x6c, 0xe6, 0x69, 0x62, 0x2e, 0x60, 0xf2, 0x9f, 0xb6, 0x79, + 0x03, 0xfe, 0x10, 0x08, 0xb8, 0xbc, 0x99, 0xa4, 0x1a, 0xe9, 0xe9, 0x56, + 0x28, 0xbc, 0x64, 0xf2, 0xf1, 0xb2, 0x0c, 0x2d, 0x7e, 0x9f, 0x51, 0x77, + 0xa3, 0xc2, 0x94, 0xd4, 0x46, 0x22, 0x99}; +const uint8_t kP256Data[] = {'s', 'a', 'm', 'p', 'l', 'e'}; +const uint8_t kP256Signature[] = { + 0xef, 0xd4, 0x8b, 0x2a, 0xac, 0xb6, 0xa8, 0xfd, 0x11, 0x40, 0xdd, + 0x9c, 0xd4, 0x5e, 0x81, 0xd6, 0x9d, 0x2c, 0x87, 0x7b, 0x56, 0xaa, + 0xf9, 0x91, 0xc3, 0x4d, 0x0e, 0xa8, 0x4e, 0xaf, 0x37, 0x16, 0xf7, + 0xcb, 0x1c, 0x94, 0x2d, 0x65, 0x7c, 0x41, 0xd4, 0x36, 0xc7, 0xa1, + 0xb6, 0xe2, 0x9f, 0x65, 0xf3, 0xe9, 0x00, 0xdb, 0xb9, 0xaf, 0xf4, + 0x06, 0x4d, 0xc4, 0xab, 0x2f, 0x84, 0x3a, 0xcd, 0xa8}; + +// ECDSA test vector, A.2.6. ECDSA, 384 Bits (Prime Field), SHA-384 +// <https://tools.ietf.org/html/rfc6979#appendix-A.2.6> +const uint8_t kP384Pkcs8[] = { + 0x30, 0x81, 0xb6, 0x02, 0x01, 0x00, 0x30, 0x10, 0x06, 0x07, 0x2a, 0x86, + 0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x05, 0x2b, 0x81, 0x04, 0x00, 0x22, + 0x04, 0x81, 0x9e, 0x30, 0x81, 0x9b, 0x02, 0x01, 0x01, 0x04, 0x30, 0x6b, + 0x9d, 0x3d, 0xad, 0x2e, 0x1b, 0x8c, 0x1c, 0x05, 0xb1, 0x98, 0x75, 0xb6, + 0x65, 0x9f, 0x4d, 0xe2, 0x3c, 0x3b, 0x66, 0x7b, 0xf2, 0x97, 0xba, 0x9a, + 0xa4, 0x77, 0x40, 0x78, 0x71, 0x37, 0xd8, 0x96, 0xd5, 0x72, 0x4e, 0x4c, + 0x70, 0xa8, 0x25, 0xf8, 0x72, 0xc9, 0xea, 0x60, 0xd2, 0xed, 0xf5, 0xa1, + 0x64, 0x03, 0x62, 0x00, 0x04, 0xec, 0x3a, 0x4e, 0x41, 0x5b, 0x4e, 0x19, + 0xa4, 0x56, 0x86, 0x18, 0x02, 0x9f, 0x42, 0x7f, 0xa5, 0xda, 0x9a, 0x8b, + 0xc4, 0xae, 0x92, 0xe0, 0x2e, 0x06, 0xaa, 0xe5, 0x28, 0x6b, 0x30, 0x0c, + 0x64, 0xde, 0xf8, 0xf0, 0xea, 0x90, 0x55, 0x86, 0x60, 0x64, 0xa2, 0x54, + 0x51, 0x54, 0x80, 0xbc, 0x13, 0x80, 0x15, 0xd9, 0xb7, 0x2d, 0x7d, 0x57, + 0x24, 0x4e, 0xa8, 0xef, 0x9a, 0xc0, 0xc6, 0x21, 0x89, 0x67, 0x08, 0xa5, + 0x93, 0x67, 0xf9, 0xdf, 0xb9, 0xf5, 0x4c, 0xa8, 0x4b, 0x3f, 0x1c, 0x9d, + 0xb1, 0x28, 0x8b, 0x23, 0x1c, 0x3a, 0xe0, 0xd4, 0xfe, 0x73, 0x44, 0xfd, + 0x25, 0x33, 0x26, 0x47, 0x20}; +const uint8_t kP384Spki[] = { + 0x30, 0x76, 0x30, 0x10, 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, + 0x01, 0x06, 0x05, 0x2b, 0x81, 0x04, 0x00, 0x22, 0x03, 0x62, 0x00, 0x04, + 0xec, 0x3a, 0x4e, 0x41, 0x5b, 0x4e, 0x19, 0xa4, 0x56, 0x86, 0x18, 0x02, + 0x9f, 0x42, 0x7f, 0xa5, 0xda, 0x9a, 0x8b, 0xc4, 0xae, 0x92, 0xe0, 0x2e, + 0x06, 0xaa, 0xe5, 0x28, 0x6b, 0x30, 0x0c, 0x64, 0xde, 0xf8, 0xf0, 0xea, + 0x90, 0x55, 0x86, 0x60, 0x64, 0xa2, 0x54, 0x51, 0x54, 0x80, 0xbc, 0x13, + 0x80, 0x15, 0xd9, 0xb7, 0x2d, 0x7d, 0x57, 0x24, 0x4e, 0xa8, 0xef, 0x9a, + 0xc0, 0xc6, 0x21, 0x89, 0x67, 0x08, 0xa5, 0x93, 0x67, 0xf9, 0xdf, 0xb9, + 0xf5, 0x4c, 0xa8, 0x4b, 0x3f, 0x1c, 0x9d, 0xb1, 0x28, 0x8b, 0x23, 0x1c, + 0x3a, 0xe0, 0xd4, 0xfe, 0x73, 0x44, 0xfd, 0x25, 0x33, 0x26, 0x47, 0x20}; +const uint8_t kP384Data[] = {'s', 'a', 'm', 'p', 'l', 'e'}; +const uint8_t kP384Signature[] = { + 0x94, 0xed, 0xbb, 0x92, 0xa5, 0xec, 0xb8, 0xaa, 0xd4, 0x73, 0x6e, 0x56, + 0xc6, 0x91, 0x91, 0x6b, 0x3f, 0x88, 0x14, 0x06, 0x66, 0xce, 0x9f, 0xa7, + 0x3d, 0x64, 0xc4, 0xea, 0x95, 0xad, 0x13, 0x3c, 0x81, 0xa6, 0x48, 0x15, + 0x2e, 0x44, 0xac, 0xf9, 0x6e, 0x36, 0xdd, 0x1e, 0x80, 0xfa, 0xbe, 0x46, + 0x99, 0xef, 0x4a, 0xeb, 0x15, 0xf1, 0x78, 0xce, 0xa1, 0xfe, 0x40, 0xdb, + 0x26, 0x03, 0x13, 0x8f, 0x13, 0x0e, 0x74, 0x0a, 0x19, 0x62, 0x45, 0x26, + 0x20, 0x3b, 0x63, 0x51, 0xd0, 0xa3, 0xa9, 0x4f, 0xa3, 0x29, 0xc1, 0x45, + 0x78, 0x6e, 0x67, 0x9e, 0x7b, 0x82, 0xc7, 0x1a, 0x38, 0x62, 0x8a, 0xc8}; + +// ECDSA test vector, A.2.7. ECDSA, 521 Bits (Prime Field), SHA-512 +// <https://tools.ietf.org/html/rfc6979#appendix-A.2.7> +const uint8_t kP521Pkcs8[] = { + 0x30, 0x81, 0xed, 0x02, 0x01, 0x00, 0x30, 0x10, 0x06, 0x07, 0x2a, 0x86, + 0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x05, 0x2b, 0x81, 0x04, 0x00, 0x23, + 0x04, 0x81, 0xd5, 0x30, 0x81, 0xd2, 0x02, 0x01, 0x01, 0x04, 0x42, 0x00, + 0xfa, 0xd0, 0x6d, 0xaa, 0x62, 0xba, 0x3b, 0x25, 0xd2, 0xfb, 0x40, 0x13, + 0x3d, 0xa7, 0x57, 0x20, 0x5d, 0xe6, 0x7f, 0x5b, 0xb0, 0x01, 0x8f, 0xee, + 0x8c, 0x86, 0xe1, 0xb6, 0x8c, 0x7e, 0x75, 0xca, 0xa8, 0x96, 0xeb, 0x32, + 0xf1, 0xf4, 0x7c, 0x70, 0x85, 0x58, 0x36, 0xa6, 0xd1, 0x6f, 0xcc, 0x14, + 0x66, 0xf6, 0xd8, 0xfb, 0xec, 0x67, 0xdb, 0x89, 0xec, 0x0c, 0x08, 0xb0, + 0xe9, 0x96, 0xb8, 0x35, 0x38, 0xa1, 0x81, 0x88, 0x03, 0x81, 0x85, 0x00, + 0x04, 0x18, 0x94, 0x55, 0x0d, 0x07, 0x85, 0x93, 0x2e, 0x00, 0xea, 0xa2, + 0x3b, 0x69, 0x4f, 0x21, 0x3f, 0x8c, 0x31, 0x21, 0xf8, 0x6d, 0xc9, 0x7a, + 0x04, 0xe5, 0xa7, 0x16, 0x7d, 0xb4, 0xe5, 0xbc, 0xd3, 0x71, 0x12, 0x3d, + 0x46, 0xe4, 0x5d, 0xb6, 0xb5, 0xd5, 0x37, 0x0a, 0x7f, 0x20, 0xfb, 0x63, + 0x31, 0x55, 0xd3, 0x8f, 0xfa, 0x16, 0xd2, 0xbd, 0x76, 0x1d, 0xca, 0xc4, + 0x74, 0xb9, 0xa2, 0xf5, 0x02, 0x3a, 0x40, 0x49, 0x31, 0x01, 0xc9, 0x62, + 0xcd, 0x4d, 0x2f, 0xdd, 0xf7, 0x82, 0x28, 0x5e, 0x64, 0x58, 0x41, 0x39, + 0xc2, 0xf9, 0x1b, 0x47, 0xf8, 0x7f, 0xf8, 0x23, 0x54, 0xd6, 0x63, 0x0f, + 0x74, 0x6a, 0x28, 0xa0, 0xdb, 0x25, 0x74, 0x1b, 0x5b, 0x34, 0xa8, 0x28, + 0x00, 0x8b, 0x22, 0xac, 0xc2, 0x3f, 0x92, 0x4f, 0xaa, 0xfb, 0xd4, 0xd3, + 0x3f, 0x81, 0xea, 0x66, 0x95, 0x6d, 0xfe, 0xaa, 0x2b, 0xfd, 0xfc, 0xf5}; +const uint8_t kP521Spki[] = { + 0x30, 0x81, 0x9b, 0x30, 0x10, 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, + 0x02, 0x01, 0x06, 0x05, 0x2b, 0x81, 0x04, 0x00, 0x23, 0x03, 0x81, 0x86, + 0x00, 0x04, 0x01, 0x89, 0x45, 0x50, 0xd0, 0x78, 0x59, 0x32, 0xe0, 0x0e, + 0xaa, 0x23, 0xb6, 0x94, 0xf2, 0x13, 0xf8, 0xc3, 0x12, 0x1f, 0x86, 0xdc, + 0x97, 0xa0, 0x4e, 0x5a, 0x71, 0x67, 0xdb, 0x4e, 0x5b, 0xcd, 0x37, 0x11, + 0x23, 0xd4, 0x6e, 0x45, 0xdb, 0x6b, 0x5d, 0x53, 0x70, 0xa7, 0xf2, 0x0f, + 0xb6, 0x33, 0x15, 0x5d, 0x38, 0xff, 0xa1, 0x6d, 0x2b, 0xd7, 0x61, 0xdc, + 0xac, 0x47, 0x4b, 0x9a, 0x2f, 0x50, 0x23, 0xa4, 0x00, 0x49, 0x31, 0x01, + 0xc9, 0x62, 0xcd, 0x4d, 0x2f, 0xdd, 0xf7, 0x82, 0x28, 0x5e, 0x64, 0x58, + 0x41, 0x39, 0xc2, 0xf9, 0x1b, 0x47, 0xf8, 0x7f, 0xf8, 0x23, 0x54, 0xd6, + 0x63, 0x0f, 0x74, 0x6a, 0x28, 0xa0, 0xdb, 0x25, 0x74, 0x1b, 0x5b, 0x34, + 0xa8, 0x28, 0x00, 0x8b, 0x22, 0xac, 0xc2, 0x3f, 0x92, 0x4f, 0xaa, 0xfb, + 0xd4, 0xd3, 0x3f, 0x81, 0xea, 0x66, 0x95, 0x6d, 0xfe, 0xaa, 0x2b, 0xfd, + 0xfc, 0xf5}; +const uint8_t kP521Data[] = {'s', 'a', 'm', 'p', 'l', 'e'}; +const uint8_t kP521Signature[] = { + 0x00, 0xc3, 0x28, 0xfa, 0xfc, 0xbd, 0x79, 0xdd, 0x77, 0x85, 0x03, 0x70, + 0xc4, 0x63, 0x25, 0xd9, 0x87, 0xcb, 0x52, 0x55, 0x69, 0xfb, 0x63, 0xc5, + 0xd3, 0xbc, 0x53, 0x95, 0x0e, 0x6d, 0x4c, 0x5f, 0x17, 0x4e, 0x25, 0xa1, + 0xee, 0x90, 0x17, 0xb5, 0xd4, 0x50, 0x60, 0x6a, 0xdd, 0x15, 0x2b, 0x53, + 0x49, 0x31, 0xd7, 0xd4, 0xe8, 0x45, 0x5c, 0xc9, 0x1f, 0x9b, 0x15, 0xbf, + 0x05, 0xec, 0x36, 0xe3, 0x77, 0xfa, 0x00, 0x61, 0x7c, 0xce, 0x7c, 0xf5, + 0x06, 0x48, 0x06, 0xc4, 0x67, 0xf6, 0x78, 0xd3, 0xb4, 0x08, 0x0d, 0x6f, + 0x1c, 0xc5, 0x0a, 0xf2, 0x6c, 0xa2, 0x09, 0x41, 0x73, 0x08, 0x28, 0x1b, + 0x68, 0xaf, 0x28, 0x26, 0x23, 0xea, 0xa6, 0x3e, 0x5b, 0x5c, 0x07, 0x23, + 0xd8, 0xb8, 0xc3, 0x7f, 0xf0, 0x77, 0x7b, 0x1a, 0x20, 0xf8, 0xcc, 0xb1, + 0xdc, 0xcc, 0x43, 0x99, 0x7f, 0x1e, 0xe0, 0xe4, 0x4d, 0xa4, 0xa6, 0x7a}; + +// ECDSA P256 test case with a leading zero in the private key +const uint8_t kP256Pkcs8ZeroPad[] = { + 0x30, 0x81, 0x87, 0x02, 0x01, 0x00, 0x30, 0x13, 0x06, 0x07, 0x2a, 0x86, + 0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, + 0x03, 0x01, 0x07, 0x04, 0x6d, 0x30, 0x6b, 0x02, 0x01, 0x01, 0x04, 0x20, + 0x00, 0x16, 0x40, 0x71, 0x99, 0xe3, 0x07, 0xaa, 0xdc, 0x98, 0x0b, 0x21, + 0x62, 0xce, 0x66, 0x1f, 0xe4, 0x1a, 0x86, 0x9a, 0x23, 0x33, 0xf6, 0x72, + 0xb4, 0xa3, 0xdc, 0x3b, 0x50, 0xba, 0x20, 0xce, 0xa1, 0x44, 0x03, 0x42, + 0x00, 0x04, 0x53, 0x11, 0x9a, 0x86, 0xa0, 0xc2, 0x99, 0x4f, 0xa6, 0xf8, + 0x08, 0xf8, 0x61, 0x01, 0x0e, 0x6b, 0x04, 0x9c, 0xd8, 0x15, 0x63, 0x2e, + 0xd1, 0x38, 0x00, 0x10, 0xee, 0xe4, 0xc9, 0x11, 0xff, 0x05, 0xba, 0xd6, + 0xcd, 0x94, 0xea, 0x00, 0xec, 0x85, 0x26, 0x2c, 0xbd, 0x4d, 0x85, 0xbd, + 0x20, 0xce, 0xa5, 0xb1, 0x3f, 0x4d, 0x82, 0x9b, 0x9f, 0x28, 0x2e, 0xd3, + 0x8a, 0x87, 0x1f, 0x89, 0xf8, 0x02}; +const uint8_t kP256SpkiZeroPad[] = { + 0x30, 0x59, 0x30, 0x13, 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, + 0x01, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07, 0x03, + 0x42, 0x00, 0x04, 0x53, 0x11, 0x9a, 0x86, 0xa0, 0xc2, 0x99, 0x4f, 0xa6, + 0xf8, 0x08, 0xf8, 0x61, 0x01, 0x0e, 0x6b, 0x04, 0x9c, 0xd8, 0x15, 0x63, + 0x2e, 0xd1, 0x38, 0x00, 0x10, 0xee, 0xe4, 0xc9, 0x11, 0xff, 0x05, 0xba, + 0xd6, 0xcd, 0x94, 0xea, 0x00, 0xec, 0x85, 0x26, 0x2c, 0xbd, 0x4d, 0x85, + 0xbd, 0x20, 0xce, 0xa5, 0xb1, 0x3f, 0x4d, 0x82, 0x9b, 0x9f, 0x28, 0x2e, + 0xd3, 0x8a, 0x87, 0x1f, 0x89, 0xf8, 0x02}; +const uint8_t kP256DataZeroPad[] = {'s', 'a', 'm', 'p', 'l', 'e'}; +const uint8_t kP256SignatureZeroPad[] = { + 0xa6, 0xf4, 0xe4, 0xa8, 0x3f, 0x03, 0x59, 0x89, 0x60, 0x53, 0xe7, + 0xdc, 0xb5, 0xbe, 0x78, 0xaf, 0xc1, 0xca, 0xc0, 0x65, 0xba, 0xa4, + 0x3c, 0xf1, 0xe4, 0xae, 0xe3, 0xba, 0x22, 0x3d, 0xac, 0x9d, 0x6d, + 0x1b, 0x26, 0x00, 0xcf, 0x47, 0xa1, 0xe1, 0x04, 0x21, 0x8d, 0x0b, + 0xbb, 0x16, 0xfa, 0x3e, 0x59, 0x32, 0x01, 0xb0, 0x45, 0x3e, 0x27, + 0xa4, 0xc4, 0xfd, 0x31, 0xc9, 0x1a, 0x8e, 0x74, 0xd8}; + +// ECDSA test vectors, SPKI and PKCS#8 edge cases. +const uint8_t kP256Pkcs8NoCurveOIDOrAlgorithmParams[] = { + 0x30, 0x7d, 0x02, 0x01, 0x00, 0x30, 0x09, 0x06, 0x07, 0x2a, 0x86, 0x48, + 0xce, 0x3d, 0x02, 0x01, 0x04, 0x6d, 0x30, 0x6b, 0x02, 0x01, 0x01, 0x04, + 0x20, 0xc9, 0xaf, 0xa9, 0xd8, 0x45, 0xba, 0x75, 0x16, 0x6b, 0x5c, 0x21, + 0x57, 0x67, 0xb1, 0xd6, 0x93, 0x4e, 0x50, 0xc3, 0xdb, 0x36, 0xe8, 0x9b, + 0x12, 0x7b, 0x8a, 0x62, 0x2b, 0x12, 0x0f, 0x67, 0x21, 0xa1, 0x44, 0x03, + 0x42, 0x00, 0x04, 0x60, 0xfe, 0xd4, 0xba, 0x25, 0x5a, 0x9d, 0x31, 0xc9, + 0x61, 0xeb, 0x74, 0xc6, 0x35, 0x6d, 0x68, 0xc0, 0x49, 0xb8, 0x92, 0x3b, + 0x61, 0xfa, 0x6c, 0xe6, 0x69, 0x62, 0x2e, 0x60, 0xf2, 0x9f, 0xb6, 0x79, + 0x03, 0xfe, 0x10, 0x08, 0xb8, 0xbc, 0x99, 0xa4, 0x1a, 0xe9, 0xe9, 0x56, + 0x28, 0xbc, 0x64, 0xf2, 0xf1, 0xb2, 0x0c, 0x2d, 0x7e, 0x9f, 0x51, 0x77, + 0xa3, 0xc2, 0x94, 0xd4, 0x46, 0x22, 0x99}; +const uint8_t kP256Pkcs8OnlyAlgorithmParams[] = { + 0x30, 0x81, 0x87, 0x02, 0x01, 0x00, 0x30, 0x13, 0x06, 0x07, 0x2a, 0x86, + 0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, + 0x03, 0x01, 0x07, 0x04, 0x6d, 0x30, 0x6b, 0x02, 0x01, 0x01, 0x04, 0x20, + 0xc9, 0xaf, 0xa9, 0xd8, 0x45, 0xba, 0x75, 0x16, 0x6b, 0x5c, 0x21, 0x57, + 0x67, 0xb1, 0xd6, 0x93, 0x4e, 0x50, 0xc3, 0xdb, 0x36, 0xe8, 0x9b, 0x12, + 0x7b, 0x8a, 0x62, 0x2b, 0x12, 0x0f, 0x67, 0x21, 0xa1, 0x44, 0x03, 0x42, + 0x00, 0x04, 0x60, 0xfe, 0xd4, 0xba, 0x25, 0x5a, 0x9d, 0x31, 0xc9, 0x61, + 0xeb, 0x74, 0xc6, 0x35, 0x6d, 0x68, 0xc0, 0x49, 0xb8, 0x92, 0x3b, 0x61, + 0xfa, 0x6c, 0xe6, 0x69, 0x62, 0x2e, 0x60, 0xf2, 0x9f, 0xb6, 0x79, 0x03, + 0xfe, 0x10, 0x08, 0xb8, 0xbc, 0x99, 0xa4, 0x1a, 0xe9, 0xe9, 0x56, 0x28, + 0xbc, 0x64, 0xf2, 0xf1, 0xb2, 0x0c, 0x2d, 0x7e, 0x9f, 0x51, 0x77, 0xa3, + 0xc2, 0x94, 0xd4, 0x46, 0x22, 0x99}; +const uint8_t kP256Pkcs8NoAlgorithmParams[] = { + 0x30, 0x81, 0x89, 0x02, 0x01, 0x00, 0x30, 0x09, 0x06, 0x07, 0x2a, 0x86, + 0x48, 0xce, 0x3d, 0x02, 0x01, 0x04, 0x79, 0x30, 0x77, 0x02, 0x01, 0x01, + 0x04, 0x20, 0xc9, 0xaf, 0xa9, 0xd8, 0x45, 0xba, 0x75, 0x16, 0x6b, 0x5c, + 0x21, 0x57, 0x67, 0xb1, 0xd6, 0x93, 0x4e, 0x50, 0xc3, 0xdb, 0x36, 0xe8, + 0x9b, 0x12, 0x7b, 0x8a, 0x62, 0x2b, 0x12, 0x0f, 0x67, 0x21, 0xa0, 0x0a, + 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07, 0xa1, 0x44, + 0x03, 0x42, 0x00, 0x04, 0x60, 0xfe, 0xd4, 0xba, 0x25, 0x5a, 0x9d, 0x31, + 0xc9, 0x61, 0xeb, 0x74, 0xc6, 0x35, 0x6d, 0x68, 0xc0, 0x49, 0xb8, 0x92, + 0x3b, 0x61, 0xfa, 0x6c, 0xe6, 0x69, 0x62, 0x2e, 0x60, 0xf2, 0x9f, 0xb6, + 0x79, 0x03, 0xfe, 0x10, 0x08, 0xb8, 0xbc, 0x99, 0xa4, 0x1a, 0xe9, 0xe9, + 0x56, 0x28, 0xbc, 0x64, 0xf2, 0xf1, 0xb2, 0x0c, 0x2d, 0x7e, 0x9f, 0x51, + 0x77, 0xa3, 0xc2, 0x94, 0xd4, 0x46, 0x22, 0x99}; +const uint8_t kP256Pkcs8MatchingCurveOIDAndAlgorithmParams[] = { + 0x30, 0x81, 0x93, 0x02, 0x01, 0x00, 0x30, 0x13, 0x06, 0x07, 0x2a, 0x86, + 0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, + 0x03, 0x01, 0x07, 0x04, 0x79, 0x30, 0x77, 0x02, 0x01, 0x01, 0x04, 0x20, + 0xc9, 0xaf, 0xa9, 0xd8, 0x45, 0xba, 0x75, 0x16, 0x6b, 0x5c, 0x21, 0x57, + 0x67, 0xb1, 0xd6, 0x93, 0x4e, 0x50, 0xc3, 0xdb, 0x36, 0xe8, 0x9b, 0x12, + 0x7b, 0x8a, 0x62, 0x2b, 0x12, 0x0f, 0x67, 0x21, 0xa0, 0x0a, 0x06, 0x08, + 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07, 0xa1, 0x44, 0x03, 0x42, + 0x00, 0x04, 0x60, 0xfe, 0xd4, 0xba, 0x25, 0x5a, 0x9d, 0x31, 0xc9, 0x61, + 0xeb, 0x74, 0xc6, 0x35, 0x6d, 0x68, 0xc0, 0x49, 0xb8, 0x92, 0x3b, 0x61, + 0xfa, 0x6c, 0xe6, 0x69, 0x62, 0x2e, 0x60, 0xf2, 0x9f, 0xb6, 0x79, 0x03, + 0xfe, 0x10, 0x08, 0xb8, 0xbc, 0x99, 0xa4, 0x1a, 0xe9, 0xe9, 0x56, 0x28, + 0xbc, 0x64, 0xf2, 0xf1, 0xb2, 0x0c, 0x2d, 0x7e, 0x9f, 0x51, 0x77, 0xa3, + 0xc2, 0x94, 0xd4, 0x46, 0x22, 0x99}; +const uint8_t kP256Pkcs8DissimilarCurveOIDAndAlgorithmParams[] = { + 0x30, 0x81, 0x90, 0x02, 0x01, 0x00, 0x30, 0x13, 0x06, 0x07, 0x2a, 0x86, + 0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, + 0x03, 0x01, 0x07, 0x04, 0x76, 0x30, 0x74, 0x02, 0x01, 0x01, 0x04, 0x20, + 0xc9, 0xaf, 0xa9, 0xd8, 0x45, 0xba, 0x75, 0x16, 0x6b, 0x5c, 0x21, 0x57, + 0x67, 0xb1, 0xd6, 0x93, 0x4e, 0x50, 0xc3, 0xdb, 0x36, 0xe8, 0x9b, 0x12, + 0x7b, 0x8a, 0x62, 0x2b, 0x12, 0x0f, 0x67, 0x21, 0xa0, 0x07, 0x06, 0x05, + 0x2b, 0x81, 0x04, 0x00, 0x22, 0xa1, 0x44, 0x03, 0x42, 0x00, 0x04, 0x60, + 0xfe, 0xd4, 0xba, 0x25, 0x5a, 0x9d, 0x31, 0xc9, 0x61, 0xeb, 0x74, 0xc6, + 0x35, 0x6d, 0x68, 0xc0, 0x49, 0xb8, 0x92, 0x3b, 0x61, 0xfa, 0x6c, 0xe6, + 0x69, 0x62, 0x2e, 0x60, 0xf2, 0x9f, 0xb6, 0x79, 0x03, 0xfe, 0x10, 0x08, + 0xb8, 0xbc, 0x99, 0xa4, 0x1a, 0xe9, 0xe9, 0x56, 0x28, 0xbc, 0x64, 0xf2, + 0xf1, 0xb2, 0x0c, 0x2d, 0x7e, 0x9f, 0x51, 0x77, 0xa3, 0xc2, 0x94, 0xd4, + 0x46, 0x22, 0x99}; +const uint8_t kP256Pkcs8InvalidAlgorithmParams[] = { + 0x30, 0x81, 0x82, 0x02, 0x01, 0x00, 0x30, 0x0e, 0x06, 0x07, 0x2a, 0x86, + 0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x03, 0x2a, 0x03, 0x04, 0x04, 0x6d, + 0x30, 0x6b, 0x02, 0x01, 0x01, 0x04, 0x20, 0xc9, 0xaf, 0xa9, 0xd8, 0x45, + 0xba, 0x75, 0x16, 0x6b, 0x5c, 0x21, 0x57, 0x67, 0xb1, 0xd6, 0x93, 0x4e, + 0x50, 0xc3, 0xdb, 0x36, 0xe8, 0x9b, 0x12, 0x7b, 0x8a, 0x62, 0x2b, 0x12, + 0x0f, 0x67, 0x21, 0xa1, 0x44, 0x03, 0x42, 0x00, 0x04, 0x60, 0xfe, 0xd4, + 0xba, 0x25, 0x5a, 0x9d, 0x31, 0xc9, 0x61, 0xeb, 0x74, 0xc6, 0x35, 0x6d, + 0x68, 0xc0, 0x49, 0xb8, 0x92, 0x3b, 0x61, 0xfa, 0x6c, 0xe6, 0x69, 0x62, + 0x2e, 0x60, 0xf2, 0x9f, 0xb6, 0x79, 0x03, 0xfe, 0x10, 0x08, 0xb8, 0xbc, + 0x99, 0xa4, 0x1a, 0xe9, 0xe9, 0x56, 0x28, 0xbc, 0x64, 0xf2, 0xf1, 0xb2, + 0x0c, 0x2d, 0x7e, 0x9f, 0x51, 0x77, 0xa3, 0xc2, 0x94, 0xd4, 0x46, 0x22, + 0x99}; +const uint8_t kP256Pkcs8PointNotOnCurve[] = { + 0x30, 0x81, 0x87, 0x02, 0x01, 0x00, 0x30, 0x13, 0x06, 0x07, 0x2a, 0x86, + 0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, + 0x03, 0x01, 0x07, 0x04, 0x6d, 0x30, 0x6b, 0x02, 0x01, 0x01, 0x04, 0x20, + 0xc9, 0xaf, 0xa9, 0xd8, 0x45, 0xba, 0x75, 0x16, 0x6b, 0x5c, 0x21, 0x57, + 0x67, 0xb1, 0xd6, 0x93, 0x4e, 0x50, 0xc3, 0xdb, 0x36, 0xe8, 0x9b, 0x12, + 0x7b, 0x8a, 0x62, 0x2b, 0x12, 0x0f, 0x67, 0x21, 0xa1, 0x44, 0x03, 0x42, + 0x00, 0x04, 0x60, 0xfe, 0xd4, 0xba, 0x25, 0x5a, 0x9d, 0x31, 0xc9, 0x61, + 0xeb, 0x74, 0xc6, 0x35, 0x6d, 0x68, 0xc0, 0x49, 0xb8, 0x92, 0x3b, 0x61, + 0xfa, 0x6c, 0xe6, 0x69, 0x62, 0x2e, 0x60, 0xf2, 0x9f, 0xb6, 0x79, 0x03, + 0xfe, 0x10, 0x08, 0xb8, 0xbc, 0x99, 0xa4, 0x1a, 0xe9, 0xe9, 0x56, 0x28, + 0xbc, 0x64, 0xf2, 0xf1, 0xb2, 0x0c, 0x2d, 0x7e, 0x9f, 0x51, 0x77, 0xa3, + 0xc2, 0x94, 0xd4, 0x33, 0x11, 0x77}; +const uint8_t kP256Pkcs8NoPublicKey[] = { + 0x30, 0x41, 0x02, 0x01, 0x00, 0x30, 0x13, 0x06, 0x07, 0x2a, 0x86, 0x48, + 0xce, 0x3d, 0x02, 0x01, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, + 0x01, 0x07, 0x04, 0x27, 0x30, 0x25, 0x02, 0x01, 0x01, 0x04, 0x20, 0xc9, + 0xaf, 0xa9, 0xd8, 0x45, 0xba, 0x75, 0x16, 0x6b, 0x5c, 0x21, 0x57, 0x67, + 0xb1, 0xd6, 0x93, 0x4e, 0x50, 0xc3, 0xdb, 0x36, 0xe8, 0x9b, 0x12, 0x7b, + 0x8a, 0x62, 0x2b, 0x12, 0x0f, 0x67, 0x21}; +const uint8_t kP256SpkiNoAlgorithmParams[] = { + 0x30, 0x4f, 0x30, 0x09, 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, + 0x01, 0x03, 0x42, 0x00, 0x04, 0x60, 0xfe, 0xd4, 0xba, 0x25, 0x5a, 0x9d, + 0x31, 0xc9, 0x61, 0xeb, 0x74, 0xc6, 0x35, 0x6d, 0x68, 0xc0, 0x49, 0xb8, + 0x92, 0x3b, 0x61, 0xfa, 0x6c, 0xe6, 0x69, 0x62, 0x2e, 0x60, 0xf2, 0x9f, + 0xb6, 0x79, 0x03, 0xfe, 0x10, 0x08, 0xb8, 0xbc, 0x99, 0xa4, 0x1a, 0xe9, + 0xe9, 0x56, 0x28, 0xbc, 0x64, 0xf2, 0xf1, 0xb2, 0x0c, 0x2d, 0x7e, 0x9f, + 0x51, 0x77, 0xa3, 0xc2, 0x94, 0xd4, 0x46, 0x22, 0x99}; +const uint8_t kP256SpkiPointNotOnCurve[] = { + 0x30, 0x59, 0x30, 0x13, 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, + 0x01, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07, 0x03, + 0x42, 0x00, 0x04, 0x60, 0xfe, 0xd4, 0xba, 0x25, 0x5a, 0x9d, 0x31, 0xc9, + 0x61, 0xeb, 0x74, 0xc6, 0x35, 0x6d, 0x68, 0xc0, 0x49, 0xb8, 0x92, 0x3b, + 0x61, 0xfa, 0x6c, 0xe6, 0x69, 0x62, 0x2e, 0x60, 0xf2, 0x9f, 0xb6, 0x79, + 0x03, 0xfe, 0x10, 0x08, 0xb8, 0xbc, 0x99, 0xa4, 0x1a, 0xe9, 0xe9, 0x56, + 0x28, 0xbc, 0x64, 0xf2, 0xf1, 0xb2, 0x0c, 0x2d, 0x7e, 0x9f, 0x51, 0x77, + 0xa3, 0xc2, 0x94, 0x00, 0x33, 0x11, 0x77}; + +} // namespace nss_test diff --git a/security/nss/gtests/pk11_gtest/pk11_encrypt_derive_unittest.cc b/security/nss/gtests/pk11_gtest/pk11_encrypt_derive_unittest.cc new file mode 100644 index 0000000000..c3cb75d48c --- /dev/null +++ b/security/nss/gtests/pk11_gtest/pk11_encrypt_derive_unittest.cc @@ -0,0 +1,225 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "pk11pub.h" +#include "nssutil.h" +#include <stdio.h> +#include "prerror.h" +#include "nss.h" +#include "gtest/gtest.h" +#include "nss_scoped_ptrs.h" +#include "cpputil.h" +#include "databuffer.h" +#include "util.h" + +#define MAX_KEY_SIZE 24 + +namespace nss_test { + +static const uint8_t kIv[] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, + 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff, + 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77}; +static const uint8_t kInput[] = { + 0x77, 0x66, 0x55, 0x44, 0x33, 0x22, 0x11, 0x00, 0xff, 0xee, 0xdd, 0xcc, + 0xbb, 0xaa, 0x99, 0x88, 0x77, 0x66, 0x55, 0x44, 0x33, 0x22, 0x11, 0x00}; + +class EncryptDeriveTest + : public ::testing::Test, + public ::testing::WithParamInterface<CK_MECHANISM_TYPE> { + public: + void TestEncryptDerive() { + ScopedPK11SymKey derived_key(PK11_Derive(key_.get(), derive_mech(), + derive_param(), encrypt_mech(), + CKA_DECRYPT, keysize())); + ASSERT_TRUE(derived_key); + + uint8_t derived_key_data[MAX_KEY_SIZE]; + ASSERT_GE(sizeof(derived_key_data), keysize()); + GetKeyData(derived_key, derived_key_data, keysize()); + RemoveChecksum(derived_key_data); + + uint8_t reference_key_data[MAX_KEY_SIZE]; + unsigned int reference_len = 0; + SECStatus rv = PK11_Encrypt(key_.get(), encrypt_mech(), encrypt_param(), + reference_key_data, &reference_len, keysize(), + kInput, keysize()); + ASSERT_EQ(SECSuccess, rv); + ASSERT_EQ(keysize(), static_cast<size_t>(reference_len)); + RemoveChecksum(reference_key_data); + + EXPECT_EQ(DataBuffer(reference_key_data, keysize()), + DataBuffer(derived_key_data, keysize())); + } + + protected: + unsigned int keysize() const { return 16; } + + private: + CK_MECHANISM_TYPE encrypt_mech() const { return GetParam(); } + + CK_MECHANISM_TYPE derive_mech() const { + switch (encrypt_mech()) { + case CKM_DES3_ECB: + return CKM_DES3_ECB_ENCRYPT_DATA; + case CKM_DES3_CBC: + return CKM_DES3_CBC_ENCRYPT_DATA; + case CKM_AES_ECB: + return CKM_AES_ECB_ENCRYPT_DATA; + case CKM_AES_CBC: + return CKM_AES_CBC_ENCRYPT_DATA; + case CKM_CAMELLIA_ECB: + return CKM_CAMELLIA_ECB_ENCRYPT_DATA; + case CKM_CAMELLIA_CBC: + return CKM_CAMELLIA_CBC_ENCRYPT_DATA; +#ifndef NSS_DISABLE_DEPRECATED_SEED + case CKM_SEED_ECB: + return CKM_SEED_ECB_ENCRYPT_DATA; + case CKM_SEED_CBC: + return CKM_SEED_CBC_ENCRYPT_DATA; +#endif + default: + ADD_FAILURE() << "Unknown mechanism"; + break; + } + return CKM_INVALID_MECHANISM; + } + + SECItem* derive_param() const { + static CK_AES_CBC_ENCRYPT_DATA_PARAMS aes_data; + static CK_DES_CBC_ENCRYPT_DATA_PARAMS des_data; + static CK_KEY_DERIVATION_STRING_DATA string_data; + static SECItem param = {siBuffer, NULL, 0}; + + switch (encrypt_mech()) { + case CKM_DES3_ECB: + case CKM_AES_ECB: + case CKM_CAMELLIA_ECB: +#ifndef NSS_DISABLE_DEPRECATED_SEED + case CKM_SEED_ECB: +#endif + string_data.pData = toUcharPtr(kInput); + string_data.ulLen = keysize(); + param.data = reinterpret_cast<uint8_t*>(&string_data); + param.len = sizeof(string_data); + break; + + case CKM_DES3_CBC: + des_data.pData = toUcharPtr(kInput); + des_data.length = keysize(); + PORT_Memcpy(des_data.iv, kIv, 8); + param.data = reinterpret_cast<uint8_t*>(&des_data); + param.len = sizeof(des_data); + break; + + case CKM_AES_CBC: + case CKM_CAMELLIA_CBC: +#ifndef NSS_DISABLE_DEPRECATED_SEED + case CKM_SEED_CBC: +#endif + aes_data.pData = toUcharPtr(kInput); + aes_data.length = keysize(); + PORT_Memcpy(aes_data.iv, kIv, keysize()); + param.data = reinterpret_cast<uint8_t*>(&aes_data); + param.len = sizeof(aes_data); + break; + + default: + ADD_FAILURE() << "Unknown mechanism"; + break; + } + return ¶m; + } + + SECItem* encrypt_param() const { + static SECItem param = {siBuffer, NULL, 0}; + + switch (encrypt_mech()) { + case CKM_DES3_ECB: + case CKM_AES_ECB: + case CKM_CAMELLIA_ECB: +#ifndef NSS_DISABLE_DEPRECATED_SEED + case CKM_SEED_ECB: +#endif + // No parameter needed here. + break; + + case CKM_DES3_CBC: + case CKM_AES_CBC: + case CKM_CAMELLIA_CBC: +#ifndef NSS_DISABLE_DEPRECATED_SEED + case CKM_SEED_CBC: +#endif + param.data = toUcharPtr(kIv); + param.len = keysize(); + break; + + default: + ADD_FAILURE() << "Unknown mechanism"; + break; + } + return ¶m; + } + + virtual void SetUp() { + slot_.reset(PK11_GetBestSlot(derive_mech(), NULL)); + ASSERT_TRUE(slot_); + + key_.reset(PK11_TokenKeyGenWithFlags(slot_.get(), encrypt_mech(), NULL, + keysize(), NULL, + CKF_ENCRYPT | CKF_DERIVE, 0, NULL)); + ASSERT_TRUE(key_); + } + + void GetKeyData(ScopedPK11SymKey& key, uint8_t* buf, size_t max_len) const { + ASSERT_EQ(SECSuccess, PK11_ExtractKeyValue(key.get())); + SECItem* data = PK11_GetKeyData(key.get()); + ASSERT_TRUE(data); + ASSERT_EQ(max_len, static_cast<size_t>(data->len)); + PORT_Memcpy(buf, data->data, data->len); + } + + // Remove checksum if the key is a 3DES key. + void RemoveChecksum(uint8_t* key_data) const { + if (encrypt_mech() != CKM_DES3_CBC && encrypt_mech() != CKM_DES3_ECB) { + return; + } + for (size_t i = 0; i < keysize(); ++i) { + key_data[i] &= 0xfe; + } + } + + ScopedPK11SlotInfo slot_; + ScopedPK11SymKey key_; +}; + +TEST_P(EncryptDeriveTest, Test) { TestEncryptDerive(); } + +static const CK_MECHANISM_TYPE kEncryptDeriveMechanisms[] = { + CKM_DES3_ECB, CKM_DES3_CBC, CKM_AES_ECB, CKM_AES_ECB, CKM_AES_CBC, + CKM_CAMELLIA_ECB, CKM_CAMELLIA_CBC +#ifndef NSS_DISABLE_DEPRECATED_SEED + , + CKM_SEED_ECB, CKM_SEED_CBC +#endif +}; + +INSTANTIATE_TEST_SUITE_P(EncryptDeriveTests, EncryptDeriveTest, + ::testing::ValuesIn(kEncryptDeriveMechanisms)); + +// This class handles the case where 3DES takes a 192-bit key +// where all 24 octets will be used. +class EncryptDerive3Test : public EncryptDeriveTest { + protected: + unsigned int keysize() const { return 24; } +}; + +TEST_P(EncryptDerive3Test, Test) { TestEncryptDerive(); } + +static const CK_MECHANISM_TYPE kDES3EncryptDeriveMechanisms[] = {CKM_DES3_ECB, + CKM_DES3_CBC}; + +INSTANTIATE_TEST_SUITE_P(Encrypt3DeriveTests, EncryptDerive3Test, + ::testing::ValuesIn(kDES3EncryptDeriveMechanisms)); + +} // namespace nss_test diff --git a/security/nss/gtests/pk11_gtest/pk11_export_unittest.cc b/security/nss/gtests/pk11_gtest/pk11_export_unittest.cc new file mode 100644 index 0000000000..bfd65b952e --- /dev/null +++ b/security/nss/gtests/pk11_gtest/pk11_export_unittest.cc @@ -0,0 +1,66 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include <memory> +#include "nss.h" +#include "pk11pub.h" + +#include "gtest/gtest.h" +#include "nss_scoped_ptrs.h" + +namespace nss_test { + +class Pkcs11ExportTest : public ::testing::Test { + public: + void Derive(bool is_export) { + ScopedPK11SlotInfo slot(PK11_GetInternalSlot()); + EXPECT_TRUE(slot.get()); + + uint8_t keyData[48] = {0}; + SECItem keyItem = {siBuffer, (unsigned char*)keyData, sizeof(keyData)}; + + CK_MECHANISM_TYPE mechanism = CKM_NSS_TLS_KEY_AND_MAC_DERIVE_SHA256; + ScopedPK11SymKey baseKey(PK11_ImportSymKey( + slot.get(), mechanism, PK11_OriginUnwrap, CKA_WRAP, &keyItem, nullptr)); + EXPECT_TRUE(baseKey.get()); + + CK_SSL3_KEY_MAT_OUT kmo; + kmo.hClientMacSecret = CK_INVALID_HANDLE; + kmo.hServerMacSecret = CK_INVALID_HANDLE; + kmo.hClientKey = CK_INVALID_HANDLE; + kmo.hServerKey = CK_INVALID_HANDLE; + + CK_BYTE iv[8]; + kmo.pIVClient = iv; + kmo.pIVServer = iv; + + CK_SSL3_KEY_MAT_PARAMS kmp; + kmp.ulMacSizeInBits = 256; + kmp.ulKeySizeInBits = 128; + kmp.ulIVSizeInBits = 64; + kmp.pReturnedKeyMaterial = &kmo; + kmp.bIsExport = is_export; + + unsigned char random[32] = {0}; + kmp.RandomInfo.pClientRandom = random; + kmp.RandomInfo.ulClientRandomLen = sizeof(random); + kmp.RandomInfo.pServerRandom = random; + kmp.RandomInfo.ulServerRandomLen = sizeof(random); + + SECItem params = {siBuffer, (unsigned char*)&kmp, sizeof(kmp)}; + ScopedPK11SymKey symKey(PK11_Derive(baseKey.get(), mechanism, ¶ms, + CKM_SHA512_HMAC, CKA_SIGN, 16)); + + // Deriving must fail when is_export=true. + EXPECT_EQ(!symKey.get(), is_export); + } +}; + +TEST_F(Pkcs11ExportTest, DeriveNonExport) { Derive(false); } + +TEST_F(Pkcs11ExportTest, DeriveExport) { Derive(true); } + +} // namespace nss_test diff --git a/security/nss/gtests/pk11_gtest/pk11_find_certs_unittest.cc b/security/nss/gtests/pk11_gtest/pk11_find_certs_unittest.cc new file mode 100644 index 0000000000..9f6baf1787 --- /dev/null +++ b/security/nss/gtests/pk11_gtest/pk11_find_certs_unittest.cc @@ -0,0 +1,626 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* vim: set ts=4 et sw=4 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include <string.h> + +#include "nss.h" +#include "pk11pub.h" +#include "prenv.h" +#include "prerror.h" +#include "secmod.h" + +#include "gtest/gtest.h" +#include "nss_scoped_ptrs.h" +#include "util.h" + +namespace nss_test { + +// These test certificates were generated using pycert/pykey from +// mozilla-central (https://hg.mozilla.org/mozilla-central/file/ ... +// 9968319230a74eb8c1953444a0e6973c7500a9f8/security/manager/ssl/ ... +// tests/unit/pycert.py). + +// issuer:test cert +// subject:test cert +// issuerKey:secp256r1 +// subjectKey:secp256r1 +// serialNumber:1 +const std::vector<uint8_t> kTestCert1DER = { + 0x30, 0x82, 0x01, 0x1D, 0x30, 0x81, 0xC2, 0xA0, 0x03, 0x02, 0x01, 0x02, + 0x02, 0x01, 0x01, 0x30, 0x0D, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, + 0x0D, 0x01, 0x01, 0x0B, 0x05, 0x00, 0x30, 0x14, 0x31, 0x12, 0x30, 0x10, + 0x06, 0x03, 0x55, 0x04, 0x03, 0x0C, 0x09, 0x74, 0x65, 0x73, 0x74, 0x20, + 0x63, 0x65, 0x72, 0x74, 0x30, 0x22, 0x18, 0x0F, 0x32, 0x30, 0x31, 0x37, + 0x31, 0x31, 0x32, 0x37, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5A, 0x18, + 0x0F, 0x32, 0x30, 0x32, 0x30, 0x30, 0x32, 0x30, 0x35, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x5A, 0x30, 0x14, 0x31, 0x12, 0x30, 0x10, 0x06, 0x03, + 0x55, 0x04, 0x03, 0x0C, 0x09, 0x74, 0x65, 0x73, 0x74, 0x20, 0x63, 0x65, + 0x72, 0x74, 0x30, 0x59, 0x30, 0x13, 0x06, 0x07, 0x2A, 0x86, 0x48, 0xCE, + 0x3D, 0x02, 0x01, 0x06, 0x08, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x03, 0x01, + 0x07, 0x03, 0x42, 0x00, 0x04, 0x4F, 0xBF, 0xBB, 0xBB, 0x61, 0xE0, 0xF8, + 0xF9, 0xB1, 0xA6, 0x0A, 0x59, 0xAC, 0x87, 0x04, 0xE2, 0xEC, 0x05, 0x0B, + 0x42, 0x3E, 0x3C, 0xF7, 0x2E, 0x92, 0x3F, 0x2C, 0x4F, 0x79, 0x4B, 0x45, + 0x5C, 0x2A, 0x69, 0xD2, 0x33, 0x45, 0x6C, 0x36, 0xC4, 0x11, 0x9D, 0x07, + 0x06, 0xE0, 0x0E, 0xED, 0xC8, 0xD1, 0x93, 0x90, 0xD7, 0x99, 0x1B, 0x7B, + 0x2D, 0x07, 0xA3, 0x04, 0xEA, 0xA0, 0x4A, 0xA6, 0xC0, 0x30, 0x0D, 0x06, + 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x0B, 0x05, 0x00, + 0x03, 0x47, 0x00, 0x30, 0x44, 0x02, 0x20, 0x5C, 0x75, 0x51, 0x9F, 0x13, + 0x11, 0x50, 0xCD, 0x5D, 0x8A, 0xDE, 0x20, 0xA3, 0xBC, 0x06, 0x30, 0x91, + 0xFF, 0xB2, 0x73, 0x75, 0x5F, 0x31, 0x64, 0xEC, 0xFD, 0xCB, 0x42, 0x80, + 0x0A, 0x70, 0xE6, 0x02, 0x20, 0x11, 0xFA, 0xA2, 0xCA, 0x06, 0xF3, 0xBC, + 0x5F, 0x8A, 0xCA, 0x17, 0x63, 0x36, 0x87, 0xCF, 0x8D, 0x5C, 0xA0, 0x56, + 0x84, 0x44, 0x61, 0xB2, 0x33, 0x42, 0x07, 0x58, 0x9F, 0x0C, 0x9E, 0x49, + 0x83, +}; + +// issuer:test cert +// subject:test cert +// issuerKey:secp256r1 +// subjectKey:secp256r1 +// serialNumber:2 +const std::vector<uint8_t> kTestCert2DER = { + 0x30, 0x82, 0x01, 0x1E, 0x30, 0x81, 0xC2, 0xA0, 0x03, 0x02, 0x01, 0x02, + 0x02, 0x01, 0x02, 0x30, 0x0D, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, + 0x0D, 0x01, 0x01, 0x0B, 0x05, 0x00, 0x30, 0x14, 0x31, 0x12, 0x30, 0x10, + 0x06, 0x03, 0x55, 0x04, 0x03, 0x0C, 0x09, 0x74, 0x65, 0x73, 0x74, 0x20, + 0x63, 0x65, 0x72, 0x74, 0x30, 0x22, 0x18, 0x0F, 0x32, 0x30, 0x31, 0x37, + 0x31, 0x31, 0x32, 0x37, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5A, 0x18, + 0x0F, 0x32, 0x30, 0x32, 0x30, 0x30, 0x32, 0x30, 0x35, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x5A, 0x30, 0x14, 0x31, 0x12, 0x30, 0x10, 0x06, 0x03, + 0x55, 0x04, 0x03, 0x0C, 0x09, 0x74, 0x65, 0x73, 0x74, 0x20, 0x63, 0x65, + 0x72, 0x74, 0x30, 0x59, 0x30, 0x13, 0x06, 0x07, 0x2A, 0x86, 0x48, 0xCE, + 0x3D, 0x02, 0x01, 0x06, 0x08, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x03, 0x01, + 0x07, 0x03, 0x42, 0x00, 0x04, 0x4F, 0xBF, 0xBB, 0xBB, 0x61, 0xE0, 0xF8, + 0xF9, 0xB1, 0xA6, 0x0A, 0x59, 0xAC, 0x87, 0x04, 0xE2, 0xEC, 0x05, 0x0B, + 0x42, 0x3E, 0x3C, 0xF7, 0x2E, 0x92, 0x3F, 0x2C, 0x4F, 0x79, 0x4B, 0x45, + 0x5C, 0x2A, 0x69, 0xD2, 0x33, 0x45, 0x6C, 0x36, 0xC4, 0x11, 0x9D, 0x07, + 0x06, 0xE0, 0x0E, 0xED, 0xC8, 0xD1, 0x93, 0x90, 0xD7, 0x99, 0x1B, 0x7B, + 0x2D, 0x07, 0xA3, 0x04, 0xEA, 0xA0, 0x4A, 0xA6, 0xC0, 0x30, 0x0D, 0x06, + 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x0B, 0x05, 0x00, + 0x03, 0x48, 0x00, 0x30, 0x45, 0x02, 0x20, 0x5C, 0x75, 0x51, 0x9F, 0x13, + 0x11, 0x50, 0xCD, 0x5D, 0x8A, 0xDE, 0x20, 0xA3, 0xBC, 0x06, 0x30, 0x91, + 0xFF, 0xB2, 0x73, 0x75, 0x5F, 0x31, 0x64, 0xEC, 0xFD, 0xCB, 0x42, 0x80, + 0x0A, 0x70, 0xE6, 0x02, 0x21, 0x00, 0xF6, 0x5E, 0x42, 0xC7, 0x54, 0x40, + 0x81, 0xE9, 0x4C, 0x16, 0x48, 0xB1, 0x39, 0x0A, 0xA0, 0xE2, 0x8C, 0x23, + 0xAA, 0xC5, 0xBB, 0xAC, 0xEB, 0x9B, 0x15, 0x0B, 0x2F, 0xB7, 0xF5, 0x85, + 0xB2, 0x54, +}; + +const std::vector<uint8_t> kTestCertSubjectDER = { + 0x30, 0x14, 0x31, 0x12, 0x30, 0x10, 0x06, 0x03, 0x55, 0x04, 0x03, + 0x0C, 0x09, 0x74, 0x65, 0x73, 0x74, 0x20, 0x63, 0x65, 0x72, 0x74, +}; + +// issuer:test cert +// subject:unrelated subject DN +// issuerKey:secp256r1 +// subjectKey:secp256r1 +// serialNumber:3 +const std::vector<uint8_t> kUnrelatedTestCertDER = { + 0x30, 0x82, 0x01, 0x28, 0x30, 0x81, 0xCD, 0xA0, 0x03, 0x02, 0x01, 0x02, + 0x02, 0x01, 0x03, 0x30, 0x0D, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, + 0x0D, 0x01, 0x01, 0x0B, 0x05, 0x00, 0x30, 0x14, 0x31, 0x12, 0x30, 0x10, + 0x06, 0x03, 0x55, 0x04, 0x03, 0x0C, 0x09, 0x74, 0x65, 0x73, 0x74, 0x20, + 0x63, 0x65, 0x72, 0x74, 0x30, 0x22, 0x18, 0x0F, 0x32, 0x30, 0x31, 0x37, + 0x31, 0x31, 0x32, 0x37, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5A, 0x18, + 0x0F, 0x32, 0x30, 0x32, 0x30, 0x30, 0x32, 0x30, 0x35, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x5A, 0x30, 0x1F, 0x31, 0x1D, 0x30, 0x1B, 0x06, 0x03, + 0x55, 0x04, 0x03, 0x0C, 0x14, 0x75, 0x6E, 0x72, 0x65, 0x6C, 0x61, 0x74, + 0x65, 0x64, 0x20, 0x73, 0x75, 0x62, 0x6A, 0x65, 0x63, 0x74, 0x20, 0x44, + 0x4E, 0x30, 0x59, 0x30, 0x13, 0x06, 0x07, 0x2A, 0x86, 0x48, 0xCE, 0x3D, + 0x02, 0x01, 0x06, 0x08, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x03, 0x01, 0x07, + 0x03, 0x42, 0x00, 0x04, 0x4F, 0xBF, 0xBB, 0xBB, 0x61, 0xE0, 0xF8, 0xF9, + 0xB1, 0xA6, 0x0A, 0x59, 0xAC, 0x87, 0x04, 0xE2, 0xEC, 0x05, 0x0B, 0x42, + 0x3E, 0x3C, 0xF7, 0x2E, 0x92, 0x3F, 0x2C, 0x4F, 0x79, 0x4B, 0x45, 0x5C, + 0x2A, 0x69, 0xD2, 0x33, 0x45, 0x6C, 0x36, 0xC4, 0x11, 0x9D, 0x07, 0x06, + 0xE0, 0x0E, 0xED, 0xC8, 0xD1, 0x93, 0x90, 0xD7, 0x99, 0x1B, 0x7B, 0x2D, + 0x07, 0xA3, 0x04, 0xEA, 0xA0, 0x4A, 0xA6, 0xC0, 0x30, 0x0D, 0x06, 0x09, + 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x0B, 0x05, 0x00, 0x03, + 0x47, 0x00, 0x30, 0x44, 0x02, 0x20, 0x5C, 0x75, 0x51, 0x9F, 0x13, 0x11, + 0x50, 0xCD, 0x5D, 0x8A, 0xDE, 0x20, 0xA3, 0xBC, 0x06, 0x30, 0x91, 0xFF, + 0xB2, 0x73, 0x75, 0x5F, 0x31, 0x64, 0xEC, 0xFD, 0xCB, 0x42, 0x80, 0x0A, + 0x70, 0xE6, 0x02, 0x20, 0x0F, 0x1A, 0x04, 0xC2, 0xF8, 0xBA, 0xC2, 0x94, + 0x26, 0x6E, 0xBC, 0x91, 0x7D, 0xDB, 0x75, 0x7B, 0xE8, 0xA3, 0x4F, 0x69, + 0x1B, 0xF3, 0x1F, 0x2C, 0xCE, 0x82, 0x67, 0xC9, 0x5B, 0xBB, 0xBA, 0x0A, +}; + +class PK11FindCertsTestBase : public ::testing::Test { + protected: + PK11FindCertsTestBase() + : m_slot(nullptr), test_cert_db_dir_("PK11FindCertsTestBase-") {} + + virtual void SetUp() { + std::string test_cert_db_path(test_cert_db_dir_.GetPath()); + const char* test_name = + ::testing::UnitTest::GetInstance()->current_test_info()->name(); + std::string mod_spec = "configDir='sql:"; + mod_spec.append(test_cert_db_path); + mod_spec.append("' tokenDescription='"); + mod_spec.append(test_name); + mod_spec.append("'"); + m_slot = SECMOD_OpenUserDB(mod_spec.c_str()); + ASSERT_NE(nullptr, m_slot); + } + + virtual void TearDown() { + ASSERT_EQ(SECSuccess, SECMOD_CloseUserDB(m_slot)); + PK11_FreeSlot(m_slot); + std::string test_cert_db_path(test_cert_db_dir_.GetPath()); + ASSERT_EQ(0, unlink((test_cert_db_path + "/cert9.db").c_str())); + ASSERT_EQ(0, unlink((test_cert_db_path + "/key4.db").c_str())); + } + + PK11SlotInfo* m_slot; + ScopedUniqueDirectory test_cert_db_dir_; +}; + +class PK11FindRawCertsBySubjectTest : public PK11FindCertsTestBase {}; + +TEST_F(PK11FindCertsTestBase, CertAddListWithData) { + ScopedPK11SlotInfo slot(PK11_GetInternalKeySlot()); + ASSERT_TRUE(slot); + SECItem cert1_item = {siBuffer, const_cast<uint8_t*>(kTestCert1DER.data()), + (unsigned int)kTestCert1DER.size()}; + SECItem cert2_item = {siBuffer, const_cast<uint8_t*>(kTestCert2DER.data()), + (unsigned int)kTestCert2DER.size()}; + + // Make certificates. ScopedCERTCertList will own. + ScopedCERTCertList list(CERT_NewCertList()); + ASSERT_TRUE(list); + CERTCertificate* cert1 = CERT_NewTempCertificate( + CERT_GetDefaultCertDB(), &cert1_item, nullptr, false, false); + CERTCertificate* cert2 = CERT_NewTempCertificate( + CERT_GetDefaultCertDB(), &cert2_item, nullptr, false, false); + ASSERT_NE(nullptr, cert1); + ASSERT_NE(nullptr, cert2); + ASSERT_NE(cert1, cert2); + + SECStatus rv = CERT_AddCertToListHeadWithData(list.get(), cert1, cert1); + EXPECT_EQ(SECSuccess, rv); + rv = CERT_AddCertToListTailWithData(list.get(), cert2, cert2); + EXPECT_EQ(SECSuccess, rv); + + CERTCertListNode* node = CERT_LIST_HEAD(list.get()); + ASSERT_NE(nullptr, node); + EXPECT_EQ(node->cert, cert1); + EXPECT_EQ(node->appData, cert1); + + node = CERT_LIST_TAIL(list.get()); + ASSERT_NE(nullptr, node); + EXPECT_EQ(node->cert, cert2); + EXPECT_EQ(node->appData, cert2); +} + +// If we don't have any certificates, we shouldn't get any when we search for +// them. +TEST_F(PK11FindRawCertsBySubjectTest, TestNoCertsImportedNoCertsFound) { + SECItem subject_item = { + siBuffer, const_cast<unsigned char*>(kTestCertSubjectDER.data()), + (unsigned int)kTestCertSubjectDER.size()}; + CERTCertificateList* certificates = nullptr; + SECStatus rv = + PK11_FindRawCertsWithSubject(m_slot, &subject_item, &certificates); + EXPECT_EQ(SECSuccess, rv); + EXPECT_EQ(nullptr, certificates); +} + +// If we have one certificate but it has an unrelated subject DN, we shouldn't +// get it when we search. +TEST_F(PK11FindRawCertsBySubjectTest, TestOneCertImportedNoCertsFound) { + char cert_nickname[] = "Unrelated Cert"; + SECItem cert_item = {siBuffer, + const_cast<unsigned char*>(kUnrelatedTestCertDER.data()), + (unsigned int)kUnrelatedTestCertDER.size()}; + ASSERT_EQ(SECSuccess, + PK11_ImportDERCert(m_slot, &cert_item, CK_INVALID_HANDLE, + cert_nickname, false)); + + SECItem subject_item = { + siBuffer, const_cast<unsigned char*>(kTestCertSubjectDER.data()), + (unsigned int)kTestCertSubjectDER.size()}; + CERTCertificateList* certificates = nullptr; + SECStatus rv = + PK11_FindRawCertsWithSubject(m_slot, &subject_item, &certificates); + EXPECT_EQ(SECSuccess, rv); + EXPECT_EQ(nullptr, certificates); +} + +TEST_F(PK11FindRawCertsBySubjectTest, TestMultipleMatchingCertsFound) { + char cert1_nickname[] = "Test Cert 1"; + SECItem cert1_item = {siBuffer, + const_cast<unsigned char*>(kTestCert1DER.data()), + (unsigned int)kTestCert1DER.size()}; + ASSERT_EQ(SECSuccess, + PK11_ImportDERCert(m_slot, &cert1_item, CK_INVALID_HANDLE, + cert1_nickname, false)); + char cert2_nickname[] = "Test Cert 2"; + SECItem cert2_item = {siBuffer, + const_cast<unsigned char*>(kTestCert2DER.data()), + (unsigned int)kTestCert2DER.size()}; + ASSERT_EQ(SECSuccess, + PK11_ImportDERCert(m_slot, &cert2_item, CK_INVALID_HANDLE, + cert2_nickname, false)); + char unrelated_cert_nickname[] = "Unrelated Test Cert"; + SECItem unrelated_cert_item = { + siBuffer, const_cast<unsigned char*>(kUnrelatedTestCertDER.data()), + (unsigned int)kUnrelatedTestCertDER.size()}; + ASSERT_EQ(SECSuccess, + PK11_ImportDERCert(m_slot, &unrelated_cert_item, CK_INVALID_HANDLE, + unrelated_cert_nickname, false)); + + CERTCertificateList* certificates = nullptr; + SECItem subject_item = { + siBuffer, const_cast<unsigned char*>(kTestCertSubjectDER.data()), + (unsigned int)kTestCertSubjectDER.size()}; + SECStatus rv = + PK11_FindRawCertsWithSubject(m_slot, &subject_item, &certificates); + EXPECT_EQ(SECSuccess, rv); + ASSERT_NE(nullptr, certificates); + ScopedCERTCertificateList scoped_certificates(certificates); + ASSERT_EQ(2, scoped_certificates->len); + + std::vector<uint8_t> found_cert1( + scoped_certificates->certs[0].data, + scoped_certificates->certs[0].data + scoped_certificates->certs[0].len); + std::vector<uint8_t> found_cert2( + scoped_certificates->certs[1].data, + scoped_certificates->certs[1].data + scoped_certificates->certs[1].len); + EXPECT_TRUE(found_cert1 == kTestCert1DER || found_cert1 == kTestCert2DER); + EXPECT_TRUE(found_cert2 == kTestCert1DER || found_cert2 == kTestCert2DER); + EXPECT_TRUE(found_cert1 != found_cert2); +} + +// If we try to search the internal slots, we won't find the certificate we just +// imported (because it's on a different slot). +TEST_F(PK11FindRawCertsBySubjectTest, TestNoCertsOnInternalSlots) { + char cert1_nickname[] = "Test Cert 1"; + SECItem cert1_item = {siBuffer, + const_cast<unsigned char*>(kTestCert1DER.data()), + (unsigned int)kTestCert1DER.size()}; + ASSERT_EQ(SECSuccess, + PK11_ImportDERCert(m_slot, &cert1_item, CK_INVALID_HANDLE, + cert1_nickname, false)); + + SECItem subject_item = { + siBuffer, const_cast<unsigned char*>(kTestCertSubjectDER.data()), + (unsigned int)kTestCertSubjectDER.size()}; + CERTCertificateList* internal_key_slot_certificates = nullptr; + ScopedPK11SlotInfo internal_key_slot(PK11_GetInternalKeySlot()); + SECStatus rv = PK11_FindRawCertsWithSubject( + internal_key_slot.get(), &subject_item, &internal_key_slot_certificates); + EXPECT_EQ(SECSuccess, rv); + EXPECT_EQ(nullptr, internal_key_slot_certificates); + + CERTCertificateList* internal_slot_certificates = nullptr; + ScopedPK11SlotInfo internal_slot(PK11_GetInternalSlot()); + rv = PK11_FindRawCertsWithSubject(internal_slot.get(), &subject_item, + &internal_slot_certificates); + EXPECT_EQ(SECSuccess, rv); + EXPECT_EQ(nullptr, internal_slot_certificates); +} + +// issuer:test cert +// subject:(empty - this had to be done by hand as pycert doesn't support this) +// issuerKey:secp256r1 +// subjectKey:secp256r1 +// serialNumber:4 +const std::vector<uint8_t> kEmptySubjectCertDER = { + 0x30, 0x82, 0x01, 0x09, 0x30, 0x81, 0xAE, 0xA0, 0x03, 0x02, 0x01, 0x02, + 0x02, 0x01, 0x04, 0x30, 0x0D, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, + 0x0D, 0x01, 0x01, 0x0B, 0x05, 0x00, 0x30, 0x14, 0x31, 0x12, 0x30, 0x10, + 0x06, 0x03, 0x55, 0x04, 0x03, 0x0C, 0x09, 0x74, 0x65, 0x73, 0x74, 0x20, + 0x63, 0x65, 0x72, 0x74, 0x30, 0x22, 0x18, 0x0F, 0x32, 0x30, 0x31, 0x37, + 0x31, 0x31, 0x32, 0x37, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5A, 0x18, + 0x0F, 0x32, 0x30, 0x32, 0x30, 0x30, 0x32, 0x30, 0x35, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x5A, 0x30, 0x00, 0x30, 0x59, 0x30, 0x13, 0x06, 0x07, + 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x02, 0x01, 0x06, 0x08, 0x2A, 0x86, 0x48, + 0xCE, 0x3D, 0x03, 0x01, 0x07, 0x03, 0x42, 0x00, 0x04, 0x4F, 0xBF, 0xBB, + 0xBB, 0x61, 0xE0, 0xF8, 0xF9, 0xB1, 0xA6, 0x0A, 0x59, 0xAC, 0x87, 0x04, + 0xE2, 0xEC, 0x05, 0x0B, 0x42, 0x3E, 0x3C, 0xF7, 0x2E, 0x92, 0x3F, 0x2C, + 0x4F, 0x79, 0x4B, 0x45, 0x5C, 0x2A, 0x69, 0xD2, 0x33, 0x45, 0x6C, 0x36, + 0xC4, 0x11, 0x9D, 0x07, 0x06, 0xE0, 0x0E, 0xED, 0xC8, 0xD1, 0x93, 0x90, + 0xD7, 0x99, 0x1B, 0x7B, 0x2D, 0x07, 0xA3, 0x04, 0xEA, 0xA0, 0x4A, 0xA6, + 0xC0, 0x30, 0x0D, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, + 0x01, 0x0B, 0x05, 0x00, 0x03, 0x47, 0x00, 0x30, 0x44, 0x02, 0x20, 0x5C, + 0x75, 0x51, 0x9F, 0x13, 0x11, 0x50, 0xCD, 0x5D, 0x8A, 0xDE, 0x20, 0xA3, + 0xBC, 0x06, 0x30, 0x91, 0xFF, 0xB2, 0x73, 0x75, 0x5F, 0x31, 0x64, 0xEC, + 0xFD, 0xCB, 0x42, 0x80, 0x0A, 0x70, 0xE6, 0x02, 0x20, 0x31, 0x1B, 0x92, + 0xAA, 0xA8, 0xB7, 0x51, 0x52, 0x7B, 0x64, 0xD6, 0xF7, 0x2F, 0x0C, 0xFB, + 0xBB, 0xD5, 0xDF, 0x86, 0xA3, 0x97, 0x96, 0x60, 0x42, 0xDA, 0xD4, 0xA8, + 0x5F, 0x2F, 0xA4, 0xDE, 0x7C}; + +std::vector<uint8_t> kEmptySubjectDER = {0x30, 0x00}; + +// This certificate has the smallest possible subject. Finding it should work. +TEST_F(PK11FindRawCertsBySubjectTest, TestFindEmptySubject) { + char empty_subject_cert_nickname[] = "Empty Subject Cert"; + SECItem empty_subject_cert_item = { + siBuffer, const_cast<unsigned char*>(kEmptySubjectCertDER.data()), + (unsigned int)kEmptySubjectCertDER.size()}; + ASSERT_EQ(SECSuccess, PK11_ImportDERCert(m_slot, &empty_subject_cert_item, + CK_INVALID_HANDLE, + empty_subject_cert_nickname, false)); + + SECItem subject_item = {siBuffer, + const_cast<unsigned char*>(kEmptySubjectDER.data()), + (unsigned int)kEmptySubjectDER.size()}; + CERTCertificateList* certificates = nullptr; + SECStatus rv = + PK11_FindRawCertsWithSubject(m_slot, &subject_item, &certificates); + EXPECT_EQ(SECSuccess, rv); + ASSERT_NE(nullptr, certificates); + ScopedCERTCertificateList scoped_certificates(certificates); + ASSERT_EQ(1, scoped_certificates->len); + + std::vector<uint8_t> found_cert( + scoped_certificates->certs[0].data, + scoped_certificates->certs[0].data + scoped_certificates->certs[0].len); + EXPECT_EQ(kEmptySubjectCertDER, found_cert); +} + +// Searching for a zero-length subject doesn't make sense (the minimum subject +// is the SEQUENCE tag followed by a length byte of 0), but it shouldn't cause +// problems. +TEST_F(PK11FindRawCertsBySubjectTest, TestSearchForNullSubject) { + char cert1_nickname[] = "Test Cert 1"; + SECItem cert1_item = {siBuffer, + const_cast<unsigned char*>(kTestCert1DER.data()), + (unsigned int)kTestCert1DER.size()}; + ASSERT_EQ(SECSuccess, + PK11_ImportDERCert(m_slot, &cert1_item, CK_INVALID_HANDLE, + cert1_nickname, false)); + + SECItem subject_item = {siBuffer, nullptr, 0}; + CERTCertificateList* certificates = nullptr; + SECStatus rv = + PK11_FindRawCertsWithSubject(m_slot, &subject_item, &certificates); + EXPECT_EQ(SECSuccess, rv); + EXPECT_EQ(nullptr, certificates); +} + +class PK11GetCertsMatchingPrivateKeyTest : public PK11FindCertsTestBase {}; + +// This is the private secp256r1 key corresponding to the above test +// certificates. +const std::vector<uint8_t> kTestPrivateKeyInfoDER = { + 0x30, 0x81, 0x87, 0x02, 0x01, 0x00, 0x30, 0x13, 0x06, 0x07, 0x2a, 0x86, + 0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, + 0x03, 0x01, 0x07, 0x04, 0x6d, 0x30, 0x6b, 0x02, 0x01, 0x01, 0x04, 0x20, + 0x21, 0x91, 0x40, 0x3d, 0x57, 0x10, 0xbf, 0x15, 0xa2, 0x65, 0x81, 0x8c, + 0xd4, 0x2e, 0xd6, 0xfe, 0xdf, 0x09, 0xad, 0xd9, 0x2d, 0x78, 0xb1, 0x8e, + 0x7a, 0x1e, 0x9f, 0xeb, 0x95, 0x52, 0x47, 0x02, 0xa1, 0x44, 0x03, 0x42, + 0x00, 0x04, 0x4f, 0xbf, 0xbb, 0xbb, 0x61, 0xe0, 0xf8, 0xf9, 0xb1, 0xa6, + 0x0a, 0x59, 0xac, 0x87, 0x04, 0xe2, 0xec, 0x05, 0x0b, 0x42, 0x3e, 0x3c, + 0xf7, 0x2e, 0x92, 0x3f, 0x2c, 0x4f, 0x79, 0x4b, 0x45, 0x5c, 0x2a, 0x69, + 0xd2, 0x33, 0x45, 0x6c, 0x36, 0xc4, 0x11, 0x9d, 0x07, 0x06, 0xe0, 0x0e, + 0xed, 0xc8, 0xd1, 0x93, 0x90, 0xd7, 0x99, 0x1b, 0x7b, 0x2d, 0x07, 0xa3, + 0x04, 0xea, 0xa0, 0x4a, 0xa6, 0xc0, +}; + +// issuer:test cert (different key) +// subject:test cert (different key) +// issuerKey:secp256k1 +// subjectKey:secp256k1 +// serialNumber:1 +const std::vector<uint8_t> kTestCertWithOtherKeyDER = { + 0x30, 0x82, 0x01, 0x3a, 0x30, 0x81, 0xdf, 0xa0, 0x03, 0x02, 0x01, 0x02, + 0x02, 0x01, 0x01, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, + 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30, 0x24, 0x31, 0x22, 0x30, 0x20, + 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x19, 0x74, 0x65, 0x73, 0x74, 0x20, + 0x63, 0x65, 0x72, 0x74, 0x20, 0x28, 0x64, 0x69, 0x66, 0x66, 0x65, 0x72, + 0x65, 0x6e, 0x74, 0x20, 0x6b, 0x65, 0x79, 0x29, 0x30, 0x22, 0x18, 0x0f, + 0x32, 0x30, 0x31, 0x37, 0x31, 0x31, 0x32, 0x37, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x5a, 0x18, 0x0f, 0x32, 0x30, 0x32, 0x30, 0x30, 0x32, 0x30, + 0x35, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x30, 0x24, 0x31, 0x22, + 0x30, 0x20, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x19, 0x74, 0x65, 0x73, + 0x74, 0x20, 0x63, 0x65, 0x72, 0x74, 0x20, 0x28, 0x64, 0x69, 0x66, 0x66, + 0x65, 0x72, 0x65, 0x6e, 0x74, 0x20, 0x6b, 0x65, 0x79, 0x29, 0x30, 0x56, + 0x30, 0x10, 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, + 0x05, 0x2b, 0x81, 0x04, 0x00, 0x0a, 0x03, 0x42, 0x00, 0x04, 0x35, 0xee, + 0x7c, 0x72, 0x89, 0xd8, 0xfe, 0xf7, 0xa8, 0x6a, 0xfe, 0x5d, 0xa6, 0x6d, + 0x8b, 0xc2, 0xeb, 0xb6, 0xa8, 0x54, 0x3f, 0xd2, 0xfe, 0xad, 0x08, 0x9f, + 0x45, 0xce, 0x7a, 0xcd, 0x0f, 0xa6, 0x43, 0x82, 0xa9, 0x50, 0x0c, 0x41, + 0xda, 0xd7, 0x70, 0xff, 0xd4, 0xb5, 0x11, 0xbf, 0x4b, 0x49, 0x2e, 0xb1, + 0x23, 0x88, 0x00, 0xc3, 0x2c, 0x4f, 0x76, 0xc7, 0x3a, 0x3f, 0x32, 0x94, + 0xe7, 0xc5, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, + 0x01, 0x01, 0x0b, 0x05, 0x00, 0x03, 0x47, 0x00, 0x30, 0x44, 0x02, 0x20, + 0x63, 0x59, 0x02, 0x01, 0x89, 0xd7, 0x3e, 0x5b, 0xff, 0xd1, 0x16, 0x4e, + 0xe3, 0xe2, 0x0a, 0xe0, 0x4a, 0xd8, 0x75, 0xaf, 0x77, 0x5c, 0x93, 0x60, + 0xba, 0x10, 0x1f, 0x97, 0xdd, 0x27, 0x2d, 0x24, 0x02, 0x20, 0x1e, 0xa0, + 0x7b, 0xee, 0x90, 0x9b, 0x5f, 0x2c, 0x49, 0xd6, 0x61, 0xda, 0x31, 0x14, + 0xb1, 0xa4, 0x0d, 0x2d, 0x90, 0x2b, 0x70, 0xd8, 0x6b, 0x07, 0x64, 0x27, + 0xa5, 0x2e, 0xfe, 0xca, 0x6e, 0xe6, +}; + +// If there are no certs at all, we'll get back a null list. +TEST_F(PK11GetCertsMatchingPrivateKeyTest, TestNoCertsAtAll) { + SECItem private_key_info = { + siBuffer, const_cast<unsigned char*>(kTestPrivateKeyInfoDER.data()), + (unsigned int)kTestPrivateKeyInfoDER.size(), + }; + SECKEYPrivateKey* priv_key = nullptr; + ASSERT_EQ(SECSuccess, PK11_ImportDERPrivateKeyInfoAndReturnKey( + m_slot, &private_key_info, nullptr, nullptr, false, + false, KU_ALL, &priv_key, nullptr)); + ASSERT_NE(nullptr, priv_key); + ScopedSECKEYPrivateKey scoped_priv_key(priv_key); + ScopedCERTCertList certs( + PK11_GetCertsMatchingPrivateKey(scoped_priv_key.get())); + ASSERT_TRUE(CERT_LIST_EMPTY(certs)); +} + +// If there are no certs for the private key, we'll get back a null list. +TEST_F(PK11GetCertsMatchingPrivateKeyTest, TestNoCertsForKey) { + SECItem private_key_info = { + siBuffer, const_cast<unsigned char*>(kTestPrivateKeyInfoDER.data()), + (unsigned int)kTestPrivateKeyInfoDER.size(), + }; + SECKEYPrivateKey* priv_key = nullptr; + ASSERT_EQ(SECSuccess, PK11_ImportDERPrivateKeyInfoAndReturnKey( + m_slot, &private_key_info, nullptr, nullptr, false, + false, KU_ALL, &priv_key, nullptr)); + ASSERT_NE(nullptr, priv_key); + ScopedSECKEYPrivateKey scoped_priv_key(priv_key); + + char cert_nickname[] = "Test Cert With Other Key"; + SECItem cert_item = { + siBuffer, const_cast<unsigned char*>(kTestCertWithOtherKeyDER.data()), + (unsigned int)kTestCertWithOtherKeyDER.size()}; + ASSERT_EQ(SECSuccess, + PK11_ImportDERCert(m_slot, &cert_item, CK_INVALID_HANDLE, + cert_nickname, false)); + + ScopedCERTCertList certs( + PK11_GetCertsMatchingPrivateKey(scoped_priv_key.get())); + ASSERT_TRUE(CERT_LIST_EMPTY(certs)); +} + +void CheckCertListForSubjects( + ScopedCERTCertList& list, + const std::vector<const char*>& expected_subjects) { + ASSERT_NE(nullptr, list.get()); + ASSERT_NE(0ul, expected_subjects.size()); + for (const auto& expected_subject : expected_subjects) { + size_t list_length = 0; + bool found = false; + for (CERTCertListNode* n = CERT_LIST_HEAD(list); !CERT_LIST_END(n, list); + n = CERT_LIST_NEXT(n)) { + list_length++; + if (strcmp(n->cert->subjectName, expected_subject) == 0) { + ASSERT_FALSE(found); + found = true; + } + } + ASSERT_TRUE(found); + ASSERT_EQ(expected_subjects.size(), list_length); + } +} + +// We should only get back certs that actually match the private key. +TEST_F(PK11GetCertsMatchingPrivateKeyTest, TestOneCertForKey) { + SECItem private_key_info = { + siBuffer, const_cast<unsigned char*>(kTestPrivateKeyInfoDER.data()), + (unsigned int)kTestPrivateKeyInfoDER.size(), + }; + SECKEYPrivateKey* priv_key = nullptr; + ASSERT_EQ(SECSuccess, PK11_ImportDERPrivateKeyInfoAndReturnKey( + m_slot, &private_key_info, nullptr, nullptr, false, + false, KU_ALL, &priv_key, nullptr)); + ASSERT_NE(nullptr, priv_key); + ScopedSECKEYPrivateKey scoped_priv_key(priv_key); + + char cert1_nickname[] = "Test Cert 1"; + SECItem cert1_item = {siBuffer, + const_cast<unsigned char*>(kTestCert1DER.data()), + (unsigned int)kTestCert1DER.size()}; + ASSERT_EQ(SECSuccess, + PK11_ImportDERCert(m_slot, &cert1_item, CK_INVALID_HANDLE, + cert1_nickname, false)); + + char cert_nickname[] = "Test Cert With Other Key"; + SECItem cert_item = { + siBuffer, const_cast<unsigned char*>(kTestCertWithOtherKeyDER.data()), + (unsigned int)kTestCertWithOtherKeyDER.size()}; + ASSERT_EQ(SECSuccess, + PK11_ImportDERCert(m_slot, &cert_item, CK_INVALID_HANDLE, + cert_nickname, false)); + + ScopedCERTCertList certs( + PK11_GetCertsMatchingPrivateKey(scoped_priv_key.get())); + CheckCertListForSubjects(certs, {"CN=test cert"}); +} + +// We should be able to get back all certs that match the private key. +TEST_F(PK11GetCertsMatchingPrivateKeyTest, TestTwoCertsForKey) { + SECItem private_key_info = { + siBuffer, const_cast<unsigned char*>(kTestPrivateKeyInfoDER.data()), + (unsigned int)kTestPrivateKeyInfoDER.size(), + }; + SECKEYPrivateKey* priv_key = nullptr; + ASSERT_EQ(SECSuccess, PK11_ImportDERPrivateKeyInfoAndReturnKey( + m_slot, &private_key_info, nullptr, nullptr, false, + false, KU_ALL, &priv_key, nullptr)); + ASSERT_NE(nullptr, priv_key); + ScopedSECKEYPrivateKey scoped_priv_key(priv_key); + + char cert1_nickname[] = "Test Cert 1"; + SECItem cert1_item = {siBuffer, + const_cast<unsigned char*>(kTestCert1DER.data()), + (unsigned int)kTestCert1DER.size()}; + ASSERT_EQ(SECSuccess, + PK11_ImportDERCert(m_slot, &cert1_item, CK_INVALID_HANDLE, + cert1_nickname, false)); + char cert2_nickname[] = "Test Cert 2 (same key, different subject)"; + SECItem cert2_item = { + siBuffer, const_cast<unsigned char*>(kUnrelatedTestCertDER.data()), + (unsigned int)kUnrelatedTestCertDER.size()}; + ASSERT_EQ(SECSuccess, + PK11_ImportDERCert(m_slot, &cert2_item, CK_INVALID_HANDLE, + cert2_nickname, false)); + + char cert_nickname[] = "Test Cert With Other Key"; + SECItem cert_item = { + siBuffer, const_cast<unsigned char*>(kTestCertWithOtherKeyDER.data()), + (unsigned int)kTestCertWithOtherKeyDER.size()}; + ASSERT_EQ(SECSuccess, + PK11_ImportDERCert(m_slot, &cert_item, CK_INVALID_HANDLE, + cert_nickname, false)); + + ScopedCERTCertList certs( + PK11_GetCertsMatchingPrivateKey(scoped_priv_key.get())); + CheckCertListForSubjects(certs, {"CN=test cert", "CN=unrelated subject DN"}); +} + +class PK11FindEncodedCertInSlotTest : public PK11FindCertsTestBase {}; + +TEST_F(PK11FindEncodedCertInSlotTest, TestFindEncodedCert) { + char cert_nickname[] = "Test Cert"; + SECItem cert_item = {siBuffer, + const_cast<unsigned char*>(kTestCert1DER.data()), + (unsigned int)kTestCert1DER.size()}; + ASSERT_EQ(SECSuccess, + PK11_ImportDERCert(m_slot, &cert_item, CK_INVALID_HANDLE, + cert_nickname, false)); + + // This certificate was just imported, so finding it by its encoded value + // should succeed. + CK_OBJECT_HANDLE cert_handle_in_slot = + PK11_FindEncodedCertInSlot(m_slot, &cert_item, nullptr); + // CK_INVALID_HANDLE is #defined to be the literal 0, which the compiler + // interprets as a signed value, which then causes a warning-as-an-error + // about comparing values of different signs. + ASSERT_NE(static_cast<CK_ULONG>(CK_INVALID_HANDLE), cert_handle_in_slot); + + // The certificate should not exist on the internal slot, so this should + // return CK_INVALID_HANDLE. + ScopedPK11SlotInfo internal_slot(PK11_GetInternalSlot()); + ASSERT_NE(nullptr, internal_slot); + CK_OBJECT_HANDLE cert_handle_in_internal_slot = + PK11_FindEncodedCertInSlot(internal_slot.get(), &cert_item, nullptr); + ASSERT_EQ(static_cast<CK_ULONG>(CK_INVALID_HANDLE), + cert_handle_in_internal_slot); + + // The certificate should not exist on the internal key slot, so this should + // return CK_INVALID_HANDLE. + ScopedPK11SlotInfo internal_key_slot(PK11_GetInternalKeySlot()); + ASSERT_NE(nullptr, internal_key_slot); + CK_OBJECT_HANDLE cert_handle_in_internal_key_slot = + PK11_FindEncodedCertInSlot(internal_key_slot.get(), &cert_item, nullptr); + ASSERT_EQ(static_cast<CK_ULONG>(CK_INVALID_HANDLE), + cert_handle_in_internal_key_slot); + + // This certificate hasn't been imported to any token, so looking for it + // should return CK_INVALID_HANDLE. + SECItem unknown_cert_item = {siBuffer, + const_cast<unsigned char*>(kTestCert2DER.data()), + (unsigned int)kTestCert2DER.size()}; + CK_OBJECT_HANDLE unknown_cert_handle_in_slot = + PK11_FindEncodedCertInSlot(m_slot, &unknown_cert_item, nullptr); + ASSERT_EQ(static_cast<CK_ULONG>(CK_INVALID_HANDLE), + unknown_cert_handle_in_slot); +} + +} // namespace nss_test diff --git a/security/nss/gtests/pk11_gtest/pk11_gtest.gyp b/security/nss/gtests/pk11_gtest/pk11_gtest.gyp new file mode 100644 index 0000000000..4171ea3828 --- /dev/null +++ b/security/nss/gtests/pk11_gtest/pk11_gtest.gyp @@ -0,0 +1,87 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +{ + 'includes': [ + '../../coreconf/config.gypi', + '../common/gtest.gypi', + ], + 'targets': [ + { + 'target_name': 'pk11_gtest', + 'type': 'executable', + 'sources': [ + 'pk11_aes_cmac_unittest.cc', + 'pk11_aes_gcm_unittest.cc', + 'pk11_aeskeywrap_unittest.cc', + 'pk11_aeskeywrapkwp_unittest.cc', + 'pk11_aeskeywrappad_unittest.cc', + 'pk11_cbc_unittest.cc', + 'pk11_chacha20poly1305_unittest.cc', + 'pk11_cipherop_unittest.cc', + 'pk11_curve25519_unittest.cc', + 'pk11_der_private_key_import_unittest.cc', + 'pk11_des_unittest.cc', + 'pk11_dsa_unittest.cc', + 'pk11_ecdsa_unittest.cc', + 'pk11_ecdh_unittest.cc', + 'pk11_encrypt_derive_unittest.cc', + 'pk11_find_certs_unittest.cc', + 'pk11_hkdf_unittest.cc', + 'pk11_hmac_unittest.cc', + 'pk11_hpke_unittest.cc', + 'pk11_ike_unittest.cc', + 'pk11_import_unittest.cc', + 'pk11_kbkdf.cc', + 'pk11_keygen.cc', + 'pk11_key_unittest.cc', + 'pk11_module_unittest.cc', + 'pk11_pbkdf2_unittest.cc', + 'pk11_prf_unittest.cc', + 'pk11_prng_unittest.cc', + 'pk11_rsaencrypt_unittest.cc', + 'pk11_rsaoaep_unittest.cc', + 'pk11_rsapkcs1_unittest.cc', + 'pk11_rsapss_unittest.cc', + 'pk11_seed_cbc_unittest.cc', + '<(DEPTH)/gtests/common/gtests.cc' + ], + 'dependencies': [ + '<(DEPTH)/exports.gyp:nss_exports', + '<(DEPTH)/cpputil/cpputil.gyp:cpputil', + '<(DEPTH)/gtests/google_test/google_test.gyp:gtest', + '<(DEPTH)/lib/util/util.gyp:nssutil3', + ], + 'conditions': [ + [ 'static_libs==1', { + 'dependencies': [ + '<(DEPTH)/lib/base/base.gyp:nssb', + '<(DEPTH)/lib/certdb/certdb.gyp:certdb', + '<(DEPTH)/lib/certhigh/certhigh.gyp:certhi', + '<(DEPTH)/lib/cryptohi/cryptohi.gyp:cryptohi', + '<(DEPTH)/lib/dev/dev.gyp:nssdev', + '<(DEPTH)/lib/nss/nss.gyp:nss_static', + '<(DEPTH)/lib/pk11wrap/pk11wrap.gyp:pk11wrap_static', + '<(DEPTH)/lib/pki/pki.gyp:nsspki', + '<(DEPTH)/lib/ssl/ssl.gyp:ssl', + '<(DEPTH)/lib/libpkix/libpkix.gyp:libpkix', + ], + }, { + 'dependencies': [ + '<(DEPTH)/lib/nss/nss.gyp:nss3', + '<(DEPTH)/lib/ssl/ssl.gyp:ssl3', + ], + }], + ], + } + ], + 'target_defaults': { + 'defines': [ + 'DLL_PREFIX=\"<(dll_prefix)\"', + 'DLL_SUFFIX=\"<(dll_suffix)\"' + ] + }, + 'variables': { + 'module': 'nss' + } +} diff --git a/security/nss/gtests/pk11_gtest/pk11_hkdf_unittest.cc b/security/nss/gtests/pk11_gtest/pk11_hkdf_unittest.cc new file mode 100644 index 0000000000..83e39abe43 --- /dev/null +++ b/security/nss/gtests/pk11_gtest/pk11_hkdf_unittest.cc @@ -0,0 +1,199 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include <memory> +#include "blapi.h" +#include "gtest/gtest.h" +#include "nss.h" +#include "nss_scoped_ptrs.h" +#include "pk11pub.h" +#include "secerr.h" +#include "sechash.h" +#include "util.h" + +#include "testvectors/hkdf-sha1-vectors.h" +#include "testvectors/hkdf-sha256-vectors.h" +#include "testvectors/hkdf-sha384-vectors.h" +#include "testvectors/hkdf-sha512-vectors.h" + +namespace nss_test { + +enum class HkdfTestType { + legacy, /* CKM_NSS_HKDF_SHA... */ + derive, /* CKM_HKDF_DERIVE, ikm as secret key, salt as data. */ + deriveDataKey, /* CKM_HKDF_DERIVE, ikm as data, salt as data. */ + saltDerive, /* CKM_HKDF_DERIVE, [ikm, salt] as secret key, salt as key. */ + saltDeriveDataKey, /* CKM_HKDF_DERIVE, [ikm, salt] as data, salt as key. */ + hkdfData /* CKM_HKDF_DATA, ikm as data, salt as data. */ +}; +static const HkdfTestType kHkdfTestTypesAll[] = { + HkdfTestType::legacy, + HkdfTestType::derive, + HkdfTestType::deriveDataKey, + HkdfTestType::saltDerive, + HkdfTestType::saltDeriveDataKey, + HkdfTestType::hkdfData, +}; + +class Pkcs11HkdfTest + : public ::testing::TestWithParam< + std::tuple<HkdfTestVector, HkdfTestType, CK_MECHANISM_TYPE>> { + protected: + CK_MECHANISM_TYPE Pk11MechToVendorMech(CK_MECHANISM_TYPE pk11_mech) { + switch (pk11_mech) { + case CKM_SHA_1: + return CKM_NSS_HKDF_SHA1; + case CKM_SHA256: + return CKM_NSS_HKDF_SHA256; + case CKM_SHA384: + return CKM_NSS_HKDF_SHA384; + case CKM_SHA512: + return CKM_NSS_HKDF_SHA512; + default: + ADD_FAILURE() << "Unknown hash mech"; + return CKM_INVALID_MECHANISM; + } + } + + ScopedPK11SymKey ImportKey(SECItem &ikm_item, bool import_as_data) { + ScopedPK11SlotInfo slot(PK11_GetInternalSlot()); + if (!slot) { + ADD_FAILURE() << "Can't get slot"; + return nullptr; + } + + ScopedPK11SymKey ikm; + if (import_as_data) { + ikm.reset(PK11_ImportDataKey(slot.get(), CKM_HKDF_KEY_GEN, + PK11_OriginUnwrap, CKA_SIGN, &ikm_item, + nullptr)); + } else { + ikm.reset(PK11_ImportSymKey(slot.get(), CKM_GENERIC_SECRET_KEY_GEN, + PK11_OriginUnwrap, CKA_SIGN, &ikm_item, + nullptr)); + } + return ikm; + } + + void RunWycheproofTest(const HkdfTestVector &vec, HkdfTestType test_type, + CK_MECHANISM_TYPE hash_mech) { + std::string msg = "Test #" + std::to_string(vec.id) + " failed"; + std::vector<uint8_t> vec_ikm = hex_string_to_bytes(vec.ikm); + std::vector<uint8_t> vec_okm = hex_string_to_bytes(vec.okm); + std::vector<uint8_t> vec_info = hex_string_to_bytes(vec.info); + std::vector<uint8_t> vec_salt = hex_string_to_bytes(vec.salt); + SECItem ikm_item = {siBuffer, vec_ikm.data(), + static_cast<unsigned int>(vec_ikm.size())}; + SECItem okm_item = {siBuffer, vec_okm.data(), + static_cast<unsigned int>(vec_okm.size())}; + SECItem salt_item = {siBuffer, vec_salt.data(), + static_cast<unsigned int>(vec_salt.size())}; + CK_MECHANISM_TYPE derive_mech = CKM_HKDF_DERIVE; + ScopedPK11SymKey salt_key = nullptr; + ScopedPK11SymKey ikm = nullptr; + + // Legacy vendor mech params + CK_NSS_HKDFParams nss_hkdf_params = { + true, vec_salt.data(), static_cast<unsigned int>(vec_salt.size()), + true, vec_info.data(), static_cast<unsigned int>(vec_info.size())}; + + // PKCS #11 v3.0 + CK_HKDF_PARAMS hkdf_params = { + true, + true, + hash_mech, + vec_salt.size() ? CKF_HKDF_SALT_DATA : CKF_HKDF_SALT_NULL, + vec_salt.size() ? vec_salt.data() : nullptr, + static_cast<unsigned int>(vec_salt.size()), + CK_INVALID_HANDLE, + vec_info.data(), + static_cast<unsigned int>(vec_info.size())}; + SECItem params_item = {siBuffer, (unsigned char *)&hkdf_params, + sizeof(hkdf_params)}; + + switch (test_type) { + case HkdfTestType::legacy: + derive_mech = Pk11MechToVendorMech(hash_mech); + params_item.data = (uint8_t *)&nss_hkdf_params; + params_item.len = sizeof(nss_hkdf_params); + ikm = ImportKey(ikm_item, false); + break; + case HkdfTestType::derive: + ikm = ImportKey(ikm_item, false); + break; + case HkdfTestType::deriveDataKey: + ikm = ImportKey(ikm_item, true); + break; + case HkdfTestType::saltDerive: + ikm = ImportKey(ikm_item, false); + salt_key = ImportKey(salt_item, false); + break; + case HkdfTestType::saltDeriveDataKey: + ikm = ImportKey(ikm_item, true); + salt_key = ImportKey(salt_item, true); + break; + case HkdfTestType::hkdfData: + derive_mech = CKM_HKDF_DATA; + ikm = ImportKey(ikm_item, true); + break; + default: + ADD_FAILURE() << msg; + return; + } + ASSERT_NE(nullptr, ikm) << msg; + + if (test_type == HkdfTestType::saltDerive || + test_type == HkdfTestType::saltDeriveDataKey) { + ASSERT_NE(nullptr, salt_key) << msg; + hkdf_params.ulSaltType = CKF_HKDF_SALT_KEY; + hkdf_params.ulSaltLen = 0; + hkdf_params.pSalt = NULL; + hkdf_params.hSaltKey = PK11_GetSymKeyHandle(salt_key.get()); + } + + ScopedPK11SymKey okm = ScopedPK11SymKey( + PK11_Derive(ikm.get(), derive_mech, ¶ms_item, + CKM_GENERIC_SECRET_KEY_GEN, CKA_DERIVE, vec.size)); + if (vec.valid) { + ASSERT_NE(nullptr, okm.get()) << msg; + ASSERT_EQ(SECSuccess, PK11_ExtractKeyValue(okm.get())) << msg; + ASSERT_EQ(0, SECITEM_CompareItem(&okm_item, PK11_GetKeyData(okm.get()))) + << msg; + } else { + ASSERT_EQ(nullptr, okm.get()) << msg; + } + } +}; + +TEST_P(Pkcs11HkdfTest, WycheproofVectors) { + RunWycheproofTest(std::get<0>(GetParam()), std::get<1>(GetParam()), + std::get<2>(GetParam())); +} + +INSTANTIATE_TEST_SUITE_P( + HkdfSha1, Pkcs11HkdfTest, + ::testing::Combine(::testing::ValuesIn(kHkdfSha1WycheproofVectors), + ::testing::ValuesIn(kHkdfTestTypesAll), + ::testing::Values(CKM_SHA_1))); + +INSTANTIATE_TEST_SUITE_P( + HkdfSha256, Pkcs11HkdfTest, + ::testing::Combine(::testing::ValuesIn(kHkdfSha256WycheproofVectors), + ::testing::ValuesIn(kHkdfTestTypesAll), + ::testing::Values(CKM_SHA256))); + +INSTANTIATE_TEST_SUITE_P( + HkdfSha384, Pkcs11HkdfTest, + ::testing::Combine(::testing::ValuesIn(kHkdfSha384WycheproofVectors), + ::testing::ValuesIn(kHkdfTestTypesAll), + ::testing::Values(CKM_SHA384))); + +INSTANTIATE_TEST_SUITE_P( + HkdfSha512, Pkcs11HkdfTest, + ::testing::Combine(::testing::ValuesIn(kHkdfSha512WycheproofVectors), + ::testing::ValuesIn(kHkdfTestTypesAll), + ::testing::Values(CKM_SHA512))); +} // namespace nss_test diff --git a/security/nss/gtests/pk11_gtest/pk11_hmac_unittest.cc b/security/nss/gtests/pk11_gtest/pk11_hmac_unittest.cc new file mode 100644 index 0000000000..99aed44fcf --- /dev/null +++ b/security/nss/gtests/pk11_gtest/pk11_hmac_unittest.cc @@ -0,0 +1,74 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include <memory> +#include <tuple> + +#include "nss.h" +#include "pk11pub.h" +#include "secerr.h" +#include "sechash.h" +#include "blapi.h" +#include "gtest/gtest.h" +#include "nss_scoped_ptrs.h" +#include "testvectors/hmac-sha256-vectors.h" +#include "testvectors/hmac-sha384-vectors.h" +#include "testvectors/hmac-sha512-vectors.h" +#include "util.h" + +namespace nss_test { + +class Pkcs11HmacTest : public ::testing::TestWithParam< + std::tuple<HmacTestVector, CK_MECHANISM_TYPE>> { + protected: + void RunTestVector(const HmacTestVector &vec, CK_MECHANISM_TYPE mech) { + std::string err = "Test #" + std::to_string(vec.id) + " failed"; + std::vector<uint8_t> vec_key = hex_string_to_bytes(vec.key); + std::vector<uint8_t> vec_mac = hex_string_to_bytes(vec.tag); + std::vector<uint8_t> vec_msg = hex_string_to_bytes(vec.msg); + std::vector<uint8_t> output(vec_mac.size()); + + // Don't provide a null pointer, even if the input is empty. + uint8_t tmp; + SECItem key = {siBuffer, vec_key.data() ? vec_key.data() : &tmp, + static_cast<unsigned int>(vec_key.size())}; + SECItem mac = {siBuffer, vec_mac.data() ? vec_mac.data() : &tmp, + static_cast<unsigned int>(vec_mac.size())}; + SECItem msg = {siBuffer, vec_msg.data() ? vec_msg.data() : &tmp, + static_cast<unsigned int>(vec_msg.size())}; + SECItem out = {siBuffer, output.data() ? output.data() : &tmp, + static_cast<unsigned int>(output.size())}; + + ScopedPK11SlotInfo slot(PK11_GetInternalSlot()); + ASSERT_NE(nullptr, slot) << err; + + ScopedPK11SymKey p11_key(PK11_ImportSymKey( + slot.get(), mech, PK11_OriginUnwrap, CKA_SIGN, &key, nullptr)); + ASSERT_NE(nullptr, p11_key.get()) << err; + + SECStatus rv = PK11_SignWithSymKey(p11_key.get(), mech, NULL, &out, &msg); + EXPECT_EQ(SECSuccess, rv) << err; + EXPECT_EQ(!vec.invalid, 0 == SECITEM_CompareItem(&out, &mac)) << err; + } +}; + +TEST_P(Pkcs11HmacTest, WycheproofVectors) { + RunTestVector(std::get<0>(GetParam()), std::get<1>(GetParam())); +} + +INSTANTIATE_TEST_SUITE_P( + HmacSha256, Pkcs11HmacTest, + ::testing::Combine(::testing::ValuesIn(kHmacSha256WycheproofVectors), + ::testing::Values(CKM_SHA256_HMAC))); +INSTANTIATE_TEST_SUITE_P( + HmacSha384, Pkcs11HmacTest, + ::testing::Combine(::testing::ValuesIn(kHmacSha384WycheproofVectors), + ::testing::Values(CKM_SHA384_HMAC))); +INSTANTIATE_TEST_SUITE_P( + HmacSha512, Pkcs11HmacTest, + ::testing::Combine(::testing::ValuesIn(kHmacSha512WycheproofVectors), + ::testing::Values(CKM_SHA512_HMAC))); +} // namespace nss_test diff --git a/security/nss/gtests/pk11_gtest/pk11_hpke_unittest.cc b/security/nss/gtests/pk11_gtest/pk11_hpke_unittest.cc new file mode 100644 index 0000000000..c8220621e2 --- /dev/null +++ b/security/nss/gtests/pk11_gtest/pk11_hpke_unittest.cc @@ -0,0 +1,547 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include <memory> +#include "blapi.h" +#include "gtest/gtest.h" +#include "nss.h" +#include "nss_scoped_ptrs.h" +#include "pk11hpke.h" +#include "pk11pub.h" +#include "secerr.h" +#include "sechash.h" +#include "testvectors/hpke-vectors.h" +#include "util.h" + +namespace nss_test { + +/* See note in pk11pub.h. */ +#ifdef NSS_ENABLE_DRAFT_HPKE +#include "cpputil.h" + +class Pkcs11HpkeTest : public ::testing::TestWithParam<hpke_vector> { + protected: + void ReadVector(const hpke_vector &vec) { + ScopedPK11SymKey vec_psk; + if (!vec.psk.empty()) { + ASSERT_FALSE(vec.psk_id.empty()); + vec_psk_id = hex_string_to_bytes(vec.psk_id); + + std::vector<uint8_t> psk_bytes = hex_string_to_bytes(vec.psk); + SECItem psk_item = {siBuffer, toUcharPtr(psk_bytes.data()), + static_cast<unsigned int>(psk_bytes.size())}; + ScopedPK11SlotInfo slot(PK11_GetInternalSlot()); + ASSERT_TRUE(slot); + PK11SymKey *psk_key = + PK11_ImportSymKey(slot.get(), CKM_HKDF_KEY_GEN, PK11_OriginUnwrap, + CKA_WRAP, &psk_item, nullptr); + ASSERT_NE(nullptr, psk_key); + vec_psk_key.reset(psk_key); + } + + vec_pkcs8_r = hex_string_to_bytes(vec.pkcs8_r); + vec_pkcs8_e = hex_string_to_bytes(vec.pkcs8_e); + vec_key = hex_string_to_bytes(vec.key); + vec_nonce = hex_string_to_bytes(vec.nonce); + vec_enc = hex_string_to_bytes(vec.enc); + vec_info = hex_string_to_bytes(vec.info); + vec_encryptions = vec.encrypt_vecs; + vec_exports = vec.export_vecs; + } + + void CheckEquality(const std::vector<uint8_t> &expected, SECItem *actual) { + if (!actual) { + EXPECT_TRUE(expected.empty()); + return; + } + std::vector<uint8_t> vact(actual->data, actual->data + actual->len); + EXPECT_EQ(expected, vact); + } + + void CheckEquality(SECItem *expected, SECItem *actual) { + EXPECT_EQ(!!expected, !!actual); + if (expected && actual) { + EXPECT_EQ(expected->len, actual->len); + if (expected->len == actual->len) { + EXPECT_EQ(0, memcmp(expected->data, actual->data, actual->len)); + } + } + } + + void CheckEquality(const std::vector<uint8_t> &expected, PK11SymKey *actual) { + if (!actual) { + EXPECT_TRUE(expected.empty()); + return; + } + SECStatus rv = PK11_ExtractKeyValue(actual); + EXPECT_EQ(SECSuccess, rv); + if (rv != SECSuccess) { + return; + } + SECItem *rawkey = PK11_GetKeyData(actual); + CheckEquality(expected, rawkey); + } + + void CheckEquality(PK11SymKey *expected, PK11SymKey *actual) { + if (!actual || !expected) { + EXPECT_EQ(!!expected, !!actual); + return; + } + SECStatus rv = PK11_ExtractKeyValue(expected); + EXPECT_EQ(SECSuccess, rv); + if (rv != SECSuccess) { + return; + } + SECItem *raw = PK11_GetKeyData(expected); + ASSERT_NE(nullptr, raw); + ASSERT_NE(nullptr, raw->data); + std::vector<uint8_t> expected_vec(raw->data, raw->data + raw->len); + CheckEquality(expected_vec, actual); + } + + void SetupS(const ScopedHpkeContext &cx, const ScopedSECKEYPublicKey &pkE, + const ScopedSECKEYPrivateKey &skE, + const ScopedSECKEYPublicKey &pkR, + const std::vector<uint8_t> &info) { + SECItem info_item = {siBuffer, toUcharPtr(vec_info.data()), + static_cast<unsigned int>(vec_info.size())}; + SECStatus rv = + PK11_HPKE_SetupS(cx.get(), pkE.get(), skE.get(), pkR.get(), &info_item); + EXPECT_EQ(SECSuccess, rv); + } + + void SetupR(const ScopedHpkeContext &cx, const ScopedSECKEYPublicKey &pkR, + const ScopedSECKEYPrivateKey &skR, + const std::vector<uint8_t> &enc, + const std::vector<uint8_t> &info) { + SECItem enc_item = {siBuffer, toUcharPtr(enc.data()), + static_cast<unsigned int>(enc.size())}; + SECItem info_item = {siBuffer, toUcharPtr(vec_info.data()), + static_cast<unsigned int>(vec_info.size())}; + SECStatus rv = + PK11_HPKE_SetupR(cx.get(), pkR.get(), skR.get(), &enc_item, &info_item); + EXPECT_EQ(SECSuccess, rv); + } + + void Seal(const ScopedHpkeContext &cx, std::vector<uint8_t> &aad_vec, + std::vector<uint8_t> &pt_vec, SECItem **out_ct) { + SECItem aad_item = {siBuffer, toUcharPtr(aad_vec.data()), + static_cast<unsigned int>(aad_vec.size())}; + SECItem pt_item = {siBuffer, toUcharPtr(pt_vec.data()), + static_cast<unsigned int>(pt_vec.size())}; + + SECStatus rv = PK11_HPKE_Seal(cx.get(), &aad_item, &pt_item, out_ct); + EXPECT_EQ(SECSuccess, rv); + } + + void Open(const ScopedHpkeContext &cx, std::vector<uint8_t> &aad_vec, + std::vector<uint8_t> &ct_vec, SECItem **out_pt) { + SECItem aad_item = {siBuffer, toUcharPtr(aad_vec.data()), + static_cast<unsigned int>(aad_vec.size())}; + SECItem ct_item = {siBuffer, toUcharPtr(ct_vec.data()), + static_cast<unsigned int>(ct_vec.size())}; + SECStatus rv = PK11_HPKE_Open(cx.get(), &aad_item, &ct_item, out_pt); + EXPECT_EQ(SECSuccess, rv); + } + + void TestExports(const ScopedHpkeContext &sender, + const ScopedHpkeContext &receiver) { + SECStatus rv; + + for (auto &vec : vec_exports) { + std::vector<uint8_t> context = hex_string_to_bytes(vec.ctxt); + std::vector<uint8_t> expected = hex_string_to_bytes(vec.exported); + SECItem context_item = {siBuffer, toUcharPtr(context.data()), + static_cast<unsigned int>(context.size())}; + PK11SymKey *actual_r = nullptr; + PK11SymKey *actual_s = nullptr; + rv = PK11_HPKE_ExportSecret(sender.get(), &context_item, vec.len, + &actual_s); + ASSERT_EQ(SECSuccess, rv); + rv = PK11_HPKE_ExportSecret(receiver.get(), &context_item, vec.len, + &actual_r); + ASSERT_EQ(SECSuccess, rv); + ScopedPK11SymKey scoped_act_s(actual_s); + ScopedPK11SymKey scoped_act_r(actual_r); + CheckEquality(expected, scoped_act_s.get()); + CheckEquality(expected, scoped_act_r.get()); + } + } + + void TestEncryptions(const ScopedHpkeContext &sender, + const ScopedHpkeContext &receiver) { + for (auto &enc_vec : vec_encryptions) { + std::vector<uint8_t> msg = hex_string_to_bytes(enc_vec.pt); + std::vector<uint8_t> aad = hex_string_to_bytes(enc_vec.aad); + std::vector<uint8_t> expect_ct = hex_string_to_bytes(enc_vec.ct); + SECItem *act_ct = nullptr; + Seal(sender, aad, msg, &act_ct); + CheckEquality(expect_ct, act_ct); + ScopedSECItem scoped_ct(act_ct); + + SECItem *act_pt = nullptr; + Open(receiver, aad, expect_ct, &act_pt); + CheckEquality(msg, act_pt); + ScopedSECItem scoped_pt(act_pt); + } + } + + void ImportKeyPairs(const ScopedHpkeContext &sender, + const ScopedHpkeContext &receiver) { + ScopedPK11SlotInfo slot(PK11_GetInternalSlot()); + if (!slot) { + ADD_FAILURE() << "No slot"; + return; + } + + SECItem pkcs8_e_item = {siBuffer, toUcharPtr(vec_pkcs8_e.data()), + static_cast<unsigned int>(vec_pkcs8_e.size())}; + SECKEYPrivateKey *sk_e = nullptr; + SECStatus rv = PK11_ImportDERPrivateKeyInfoAndReturnKey( + slot.get(), &pkcs8_e_item, nullptr, nullptr, false, false, KU_ALL, + &sk_e, nullptr); + EXPECT_EQ(SECSuccess, rv); + skE_derived.reset(sk_e); + SECKEYPublicKey *pk_e = SECKEY_ConvertToPublicKey(skE_derived.get()); + ASSERT_NE(nullptr, pk_e); + pkE_derived.reset(pk_e); + + SECItem pkcs8_r_item = {siBuffer, toUcharPtr(vec_pkcs8_r.data()), + static_cast<unsigned int>(vec_pkcs8_r.size())}; + SECKEYPrivateKey *sk_r = nullptr; + rv = PK11_ImportDERPrivateKeyInfoAndReturnKey( + slot.get(), &pkcs8_r_item, nullptr, nullptr, false, false, KU_ALL, + &sk_r, nullptr); + EXPECT_EQ(SECSuccess, rv); + skR_derived.reset(sk_r); + SECKEYPublicKey *pk_r = SECKEY_ConvertToPublicKey(skR_derived.get()); + ASSERT_NE(nullptr, pk_r); + pkR_derived.reset(pk_r); + } + + void SetupSenderReceiver(const ScopedHpkeContext &sender, + const ScopedHpkeContext &receiver) { + SetupS(sender, pkE_derived, skE_derived, pkR_derived, vec_info); + uint8_t buf[32]; // Curve25519 only, fixed size. + SECItem encap_item = {siBuffer, const_cast<uint8_t *>(buf), sizeof(buf)}; + SECStatus rv = PK11_HPKE_Serialize(pkE_derived.get(), encap_item.data, + &encap_item.len, encap_item.len); + ASSERT_EQ(SECSuccess, rv); + CheckEquality(vec_enc, &encap_item); + SetupR(receiver, pkR_derived, skR_derived, vec_enc, vec_info); + } + + bool GenerateKeyPair(ScopedSECKEYPublicKey &pub_key, + ScopedSECKEYPrivateKey &priv_key) { + unsigned char param_buf[65]; + + ScopedPK11SlotInfo slot(PK11_GetInternalSlot()); + if (!slot) { + ADD_FAILURE() << "Couldn't get slot"; + return false; + } + + SECItem ecdsa_params = {siBuffer, param_buf, sizeof(param_buf)}; + SECOidData *oid_data = SECOID_FindOIDByTag(SEC_OID_CURVE25519); + if (!oid_data) { + ADD_FAILURE() << "Couldn't get oid_data"; + return false; + } + + ecdsa_params.data[0] = SEC_ASN1_OBJECT_ID; + ecdsa_params.data[1] = oid_data->oid.len; + memcpy(ecdsa_params.data + 2, oid_data->oid.data, oid_data->oid.len); + ecdsa_params.len = oid_data->oid.len + 2; + SECKEYPublicKey *pub_tmp; + SECKEYPrivateKey *priv_tmp; + priv_tmp = + PK11_GenerateKeyPair(slot.get(), CKM_EC_KEY_PAIR_GEN, &ecdsa_params, + &pub_tmp, PR_FALSE, PR_TRUE, nullptr); + if (!pub_tmp || !priv_tmp) { + ADD_FAILURE() << "PK11_GenerateKeyPair failed"; + return false; + } + + pub_key.reset(pub_tmp); + priv_key.reset(priv_tmp); + return true; + } + + void RunTestVector(const hpke_vector &vec) { + ReadVector(vec); + SECItem psk_id_item = {siBuffer, toUcharPtr(vec_psk_id.data()), + static_cast<unsigned int>(vec_psk_id.size())}; + PK11SymKey *psk = vec_psk_key ? vec_psk_key.get() : nullptr; + SECItem *psk_id = psk ? &psk_id_item : nullptr; + + ScopedHpkeContext sender( + PK11_HPKE_NewContext(vec.kem_id, vec.kdf_id, vec.aead_id, psk, psk_id)); + ScopedHpkeContext receiver( + PK11_HPKE_NewContext(vec.kem_id, vec.kdf_id, vec.aead_id, psk, psk_id)); + ASSERT_TRUE(sender); + ASSERT_TRUE(receiver); + + ImportKeyPairs(sender, receiver); + SetupSenderReceiver(sender, receiver); + TestEncryptions(sender, receiver); + TestExports(sender, receiver); + } + + private: + ScopedPK11SymKey vec_psk_key; + std::vector<uint8_t> vec_psk_id; + std::vector<uint8_t> vec_pkcs8_e; + std::vector<uint8_t> vec_pkcs8_r; + std::vector<uint8_t> vec_enc; + std::vector<uint8_t> vec_info; + std::vector<uint8_t> vec_key; + std::vector<uint8_t> vec_nonce; + std::vector<hpke_encrypt_vector> vec_encryptions; + std::vector<hpke_export_vector> vec_exports; + ScopedSECKEYPublicKey pkE_derived; + ScopedSECKEYPublicKey pkR_derived; + ScopedSECKEYPrivateKey skE_derived; + ScopedSECKEYPrivateKey skR_derived; +}; + +TEST_P(Pkcs11HpkeTest, TestVectors) { RunTestVector(GetParam()); } + +INSTANTIATE_TEST_SUITE_P(Pkcs11HpkeTests, Pkcs11HpkeTest, + ::testing::ValuesIn(kHpkeTestVectors)); + +TEST_F(Pkcs11HpkeTest, BadEncapsulatedPubKey) { + ScopedHpkeContext sender( + PK11_HPKE_NewContext(HpkeDhKemX25519Sha256, HpkeKdfHkdfSha256, + HpkeAeadAes128Gcm, nullptr, nullptr)); + ScopedHpkeContext receiver( + PK11_HPKE_NewContext(HpkeDhKemX25519Sha256, HpkeKdfHkdfSha256, + HpkeAeadAes128Gcm, nullptr, nullptr)); + + SECItem empty = {siBuffer, nullptr, 0}; + uint8_t buf[100]; + SECItem short_encap = {siBuffer, buf, 1}; + SECItem long_encap = {siBuffer, buf, sizeof(buf)}; + + SECKEYPublicKey *tmp_pub_key; + ScopedSECKEYPublicKey pub_key; + ScopedSECKEYPrivateKey priv_key; + ASSERT_TRUE(GenerateKeyPair(pub_key, priv_key)); + + // Decapsulating an empty buffer should fail. + SECStatus rv = + PK11_HPKE_Deserialize(sender.get(), empty.data, empty.len, &tmp_pub_key); + EXPECT_EQ(SECFailure, rv); + EXPECT_EQ(SEC_ERROR_INVALID_ARGS, PORT_GetError()); + + // Decapsulating anything else will succeed, but the setup will fail. + rv = PK11_HPKE_Deserialize(sender.get(), short_encap.data, short_encap.len, + &tmp_pub_key); + ScopedSECKEYPublicKey bad_pub_key(tmp_pub_key); + EXPECT_EQ(SECSuccess, rv); + + rv = PK11_HPKE_SetupS(receiver.get(), pub_key.get(), priv_key.get(), + bad_pub_key.get(), &empty); + EXPECT_EQ(SECFailure, rv); + EXPECT_EQ(SEC_ERROR_INVALID_KEY, PORT_GetError()); + + // Test the same for a receiver. + rv = PK11_HPKE_SetupR(sender.get(), pub_key.get(), priv_key.get(), &empty, + &empty); + EXPECT_EQ(SECFailure, rv); + EXPECT_EQ(SEC_ERROR_INVALID_ARGS, PORT_GetError()); + + rv = PK11_HPKE_SetupR(sender.get(), pub_key.get(), priv_key.get(), + &short_encap, &empty); + EXPECT_EQ(SECFailure, rv); + EXPECT_EQ(SEC_ERROR_INVALID_KEY, PORT_GetError()); + + // Encapsulated key too long + rv = PK11_HPKE_Deserialize(sender.get(), long_encap.data, long_encap.len, + &tmp_pub_key); + bad_pub_key.reset(tmp_pub_key); + EXPECT_EQ(SECSuccess, rv); + + rv = PK11_HPKE_SetupS(receiver.get(), pub_key.get(), priv_key.get(), + bad_pub_key.get(), &empty); + EXPECT_EQ(SECFailure, rv); + EXPECT_EQ(SEC_ERROR_INVALID_ARGS, PORT_GetError()); + + rv = PK11_HPKE_SetupR(sender.get(), pub_key.get(), priv_key.get(), + &long_encap, &empty); + EXPECT_EQ(SECFailure, rv); + EXPECT_EQ(SEC_ERROR_INVALID_ARGS, PORT_GetError()); +} + +// Vectors used fixed keypairs on each end. Make sure the +// ephemeral (particularly sender) path works. +TEST_F(Pkcs11HpkeTest, EphemeralKeys) { + unsigned char info[] = {"info"}; + unsigned char msg[] = {"secret"}; + unsigned char aad[] = {"aad"}; + SECItem info_item = {siBuffer, info, sizeof(info)}; + SECItem msg_item = {siBuffer, msg, sizeof(msg)}; + SECItem aad_item = {siBuffer, aad, sizeof(aad)}; + + ScopedHpkeContext sender( + PK11_HPKE_NewContext(HpkeDhKemX25519Sha256, HpkeKdfHkdfSha256, + HpkeAeadAes128Gcm, nullptr, nullptr)); + ScopedHpkeContext receiver( + PK11_HPKE_NewContext(HpkeDhKemX25519Sha256, HpkeKdfHkdfSha256, + HpkeAeadAes128Gcm, nullptr, nullptr)); + ASSERT_TRUE(sender); + ASSERT_TRUE(receiver); + + ScopedSECKEYPublicKey pub_key_r; + ScopedSECKEYPrivateKey priv_key_r; + ASSERT_TRUE(GenerateKeyPair(pub_key_r, priv_key_r)); + + SECStatus rv = PK11_HPKE_SetupS(sender.get(), nullptr, nullptr, + pub_key_r.get(), &info_item); + EXPECT_EQ(SECSuccess, rv); + + const SECItem *enc = PK11_HPKE_GetEncapPubKey(sender.get()); + EXPECT_NE(nullptr, enc); + rv = PK11_HPKE_SetupR(receiver.get(), pub_key_r.get(), priv_key_r.get(), + const_cast<SECItem *>(enc), &info_item); + EXPECT_EQ(SECSuccess, rv); + + SECItem *tmp_sealed = nullptr; + rv = PK11_HPKE_Seal(sender.get(), &aad_item, &msg_item, &tmp_sealed); + EXPECT_EQ(SECSuccess, rv); + ScopedSECItem sealed(tmp_sealed); + + SECItem *tmp_unsealed = nullptr; + rv = PK11_HPKE_Open(receiver.get(), &aad_item, sealed.get(), &tmp_unsealed); + EXPECT_EQ(SECSuccess, rv); + CheckEquality(&msg_item, tmp_unsealed); + ScopedSECItem unsealed(tmp_unsealed); + + // Once more + tmp_sealed = nullptr; + rv = PK11_HPKE_Seal(sender.get(), &aad_item, &msg_item, &tmp_sealed); + EXPECT_EQ(SECSuccess, rv); + ASSERT_NE(nullptr, sealed); + sealed.reset(tmp_sealed); + tmp_unsealed = nullptr; + rv = PK11_HPKE_Open(receiver.get(), &aad_item, sealed.get(), &tmp_unsealed); + EXPECT_EQ(SECSuccess, rv); + CheckEquality(&msg_item, tmp_unsealed); + unsealed.reset(tmp_unsealed); + + // Seal for negative tests + tmp_sealed = nullptr; + tmp_unsealed = nullptr; + rv = PK11_HPKE_Seal(sender.get(), &aad_item, &msg_item, &tmp_sealed); + EXPECT_EQ(SECSuccess, rv); + ASSERT_NE(nullptr, sealed); + sealed.reset(tmp_sealed); + + // Drop AAD + rv = PK11_HPKE_Open(receiver.get(), nullptr, sealed.get(), &tmp_unsealed); + EXPECT_EQ(SECFailure, rv); + EXPECT_EQ(nullptr, tmp_unsealed); + + // Modify AAD + aad_item.data[0] ^= 0xff; + rv = PK11_HPKE_Open(receiver.get(), &aad_item, sealed.get(), &tmp_unsealed); + EXPECT_EQ(SECFailure, rv); + EXPECT_EQ(nullptr, tmp_unsealed); + aad_item.data[0] ^= 0xff; + + // Modify ciphertext + sealed->data[0] ^= 0xff; + rv = PK11_HPKE_Open(receiver.get(), &aad_item, sealed.get(), &tmp_unsealed); + EXPECT_EQ(SECFailure, rv); + EXPECT_EQ(nullptr, tmp_unsealed); + sealed->data[0] ^= 0xff; + + rv = PK11_HPKE_Open(receiver.get(), &aad_item, sealed.get(), &tmp_unsealed); + EXPECT_EQ(SECSuccess, rv); + EXPECT_NE(nullptr, tmp_unsealed); + unsealed.reset(tmp_unsealed); +} + +TEST_F(Pkcs11HpkeTest, InvalidContextParams) { + HpkeContext *cx = + PK11_HPKE_NewContext(static_cast<HpkeKemId>(1), HpkeKdfHkdfSha256, + HpkeAeadChaCha20Poly1305, nullptr, nullptr); + EXPECT_EQ(nullptr, cx); + EXPECT_EQ(SEC_ERROR_INVALID_ARGS, PORT_GetError()); + + cx = PK11_HPKE_NewContext(HpkeDhKemX25519Sha256, static_cast<HpkeKdfId>(2), + HpkeAeadChaCha20Poly1305, nullptr, nullptr); + EXPECT_EQ(nullptr, cx); + EXPECT_EQ(SEC_ERROR_INVALID_ARGS, PORT_GetError()); + cx = PK11_HPKE_NewContext(HpkeDhKemX25519Sha256, HpkeKdfHkdfSha256, + static_cast<HpkeAeadId>(4), nullptr, nullptr); + EXPECT_EQ(nullptr, cx); + EXPECT_EQ(SEC_ERROR_INVALID_ARGS, PORT_GetError()); +} + +TEST_F(Pkcs11HpkeTest, InvalidReceiverKeyType) { + ScopedHpkeContext sender( + PK11_HPKE_NewContext(HpkeDhKemX25519Sha256, HpkeKdfHkdfSha256, + HpkeAeadChaCha20Poly1305, nullptr, nullptr)); + ASSERT_TRUE(!!sender); + + ScopedPK11SlotInfo slot(PK11_GetInternalSlot()); + if (!slot) { + ADD_FAILURE() << "No slot"; + return; + } + + // Give the client an RSA key + PK11RSAGenParams rsa_param; + rsa_param.keySizeInBits = 1024; + rsa_param.pe = 65537L; + SECKEYPublicKey *pub_tmp; + ScopedSECKEYPublicKey pub_key; + ScopedSECKEYPrivateKey priv_key( + PK11_GenerateKeyPair(slot.get(), CKM_RSA_PKCS_KEY_PAIR_GEN, &rsa_param, + &pub_tmp, PR_FALSE, PR_FALSE, nullptr)); + ASSERT_NE(nullptr, priv_key); + ASSERT_NE(nullptr, pub_tmp); + pub_key.reset(pub_tmp); + + SECItem info_item = {siBuffer, nullptr, 0}; + SECStatus rv = PK11_HPKE_SetupS(sender.get(), nullptr, nullptr, pub_key.get(), + &info_item); + EXPECT_EQ(SECFailure, rv); + EXPECT_EQ(SEC_ERROR_BAD_KEY, PORT_GetError()); + + // Try with an unexpected curve + StackSECItem ecParams; + SECOidData *oidData = SECOID_FindOIDByTag(SEC_OID_ANSIX962_EC_PRIME256V1); + ASSERT_NE(oidData, nullptr); + if (!SECITEM_AllocItem(nullptr, &ecParams, (2 + oidData->oid.len))) { + FAIL() << "Couldn't allocate memory for OID."; + } + ecParams.data[0] = SEC_ASN1_OBJECT_ID; + ecParams.data[1] = oidData->oid.len; + memcpy(ecParams.data + 2, oidData->oid.data, oidData->oid.len); + + priv_key.reset(PK11_GenerateKeyPair(slot.get(), CKM_EC_KEY_PAIR_GEN, + &ecParams, &pub_tmp, PR_FALSE, PR_FALSE, + nullptr)); + ASSERT_NE(nullptr, priv_key); + ASSERT_NE(nullptr, pub_tmp); + pub_key.reset(pub_tmp); + rv = PK11_HPKE_SetupS(sender.get(), nullptr, nullptr, pub_key.get(), + &info_item); + EXPECT_EQ(SECFailure, rv); + EXPECT_EQ(SEC_ERROR_BAD_KEY, PORT_GetError()); +} +#else +TEST(Pkcs11HpkeTest, EnsureNotImplemented) { + ScopedHpkeContext cx( + PK11_HPKE_NewContext(HpkeDhKemX25519Sha256, HpkeKdfHkdfSha256, + HpkeAeadChaCha20Poly1305, nullptr, nullptr)); + EXPECT_FALSE(cx.get()); + EXPECT_EQ(SEC_ERROR_INVALID_ALGORITHM, PORT_GetError()); +} +#endif // NSS_ENABLE_DRAFT_HPKE + +} // namespace nss_test diff --git a/security/nss/gtests/pk11_gtest/pk11_ike_unittest.cc b/security/nss/gtests/pk11_gtest/pk11_ike_unittest.cc new file mode 100644 index 0000000000..9a8c1d1a3c --- /dev/null +++ b/security/nss/gtests/pk11_gtest/pk11_ike_unittest.cc @@ -0,0 +1,197 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include <memory> +#include "blapi.h" +#include "gtest/gtest.h" +#include "nss.h" +#include "nss_scoped_ptrs.h" +#include "pk11pub.h" +#include "secerr.h" +#include "sechash.h" +#include "util.h" +#include "databuffer.h" + +#include "testvectors/ike-sha1-vectors.h" +#include "testvectors/ike-sha256-vectors.h" +#include "testvectors/ike-sha384-vectors.h" +#include "testvectors/ike-sha512-vectors.h" +#include "testvectors/ike-aesxcbc-vectors.h" + +namespace nss_test { + +class Pkcs11IkeTest : public ::testing::TestWithParam< + std::tuple<IkeTestVector, CK_MECHANISM_TYPE>> { + protected: + ScopedPK11SymKey ImportKey(SECItem &ikm_item) { + ScopedPK11SlotInfo slot(PK11_GetInternalSlot()); + if (!slot) { + ADD_FAILURE() << "Can't get slot"; + return nullptr; + } + ScopedPK11SymKey ikm( + PK11_ImportSymKey(slot.get(), CKM_GENERIC_SECRET_KEY_GEN, + PK11_OriginUnwrap, CKA_DERIVE, &ikm_item, nullptr)); + return ikm; + } + + void RunVectorTest(const IkeTestVector &vec, CK_MECHANISM_TYPE prf_mech) { + std::string msg = "Test #" + std::to_string(vec.id) + " failed"; + std::vector<uint8_t> vec_ikm = hex_string_to_bytes(vec.ikm); + std::vector<uint8_t> vec_okm = hex_string_to_bytes(vec.okm); + std::vector<uint8_t> vec_gxykm = hex_string_to_bytes(vec.gxykm); + std::vector<uint8_t> vec_prevkm = hex_string_to_bytes(vec.prevkm); + std::vector<uint8_t> vec_Ni = hex_string_to_bytes(vec.Ni); + std::vector<uint8_t> vec_Nr = hex_string_to_bytes(vec.Nr); + std::vector<uint8_t> vec_seed_data = hex_string_to_bytes(vec.seed_data); + SECItem ikm_item = {siBuffer, vec_ikm.data(), + static_cast<unsigned int>(vec_ikm.size())}; + SECItem okm_item = {siBuffer, vec_okm.data(), + static_cast<unsigned int>(vec_okm.size())}; + SECItem prevkm_item = {siBuffer, vec_prevkm.data(), + static_cast<unsigned int>(vec_prevkm.size())}; + SECItem gxykm_item = {siBuffer, vec_gxykm.data(), + static_cast<unsigned int>(vec_gxykm.size())}; + CK_MECHANISM_TYPE derive_mech = CKM_NSS_IKE_PRF_DERIVE; + ScopedPK11SymKey gxy_key = nullptr; + ScopedPK11SymKey prev_key = nullptr; + ScopedPK11SymKey ikm = ImportKey(ikm_item); + + // IKE_PRF structure (used in cases 1, 2 and 3) + CK_NSS_IKE_PRF_DERIVE_PARAMS nss_ike_prf_params = { + prf_mech, + CK_FALSE, + CK_FALSE, + vec_Ni.data(), + static_cast<CK_ULONG>(vec_Ni.size()), + vec_Nr.data(), + static_cast<CK_ULONG>(vec_Nr.size()), + CK_INVALID_HANDLE}; + + // IKE_V1_PRF, used to derive session keys. + CK_NSS_IKE1_PRF_DERIVE_PARAMS nss_ike_v1_prf_params = { + prf_mech, false, + CK_INVALID_HANDLE, CK_INVALID_HANDLE, + vec_Ni.data(), static_cast<CK_ULONG>(vec_Ni.size()), + vec_Nr.data(), static_cast<CK_ULONG>(vec_Nr.size()), + vec.key_number}; + + // IKE_V1_APP_B, do quick mode (all session keys in one call). + CK_NSS_IKE1_APP_B_PRF_DERIVE_PARAMS nss_ike_app_b_prf_params_quick = { + prf_mech, CK_FALSE, CK_INVALID_HANDLE, vec_seed_data.data(), + static_cast<CK_ULONG>(vec_seed_data.size())}; + + // IKE_V1_APP_B, used for long session keys in ike_v1 + CK_MECHANISM_TYPE nss_ike_app_b_prf_params = prf_mech; + + // IKE_PRF_PLUS, used to generate session keys in ike v2 + CK_NSS_IKE_PRF_PLUS_DERIVE_PARAMS nss_ike_prf_plus_params = { + prf_mech, CK_FALSE, CK_INVALID_HANDLE, vec_seed_data.data(), + static_cast<CK_ULONG>(vec_seed_data.size())}; + + SECItem params_item = {siBuffer, (unsigned char *)&nss_ike_prf_params, + sizeof(nss_ike_prf_params)}; + + switch (vec.test_type) { + case IkeTestType::ikeGxy: + nss_ike_prf_params.bDataAsKey = true; + break; + case IkeTestType::ikeV1Psk: + break; + case IkeTestType::ikeV2Rekey: + nss_ike_prf_params.bRekey = true; + gxy_key = ImportKey(gxykm_item); + nss_ike_prf_params.hNewKey = PK11_GetSymKeyHandle(gxy_key.get()); + break; + case IkeTestType::ikeV1: + derive_mech = CKM_NSS_IKE1_PRF_DERIVE; + params_item.data = (unsigned char *)&nss_ike_v1_prf_params; + params_item.len = sizeof(nss_ike_v1_prf_params); + gxy_key = ImportKey(gxykm_item); + nss_ike_v1_prf_params.hKeygxy = PK11_GetSymKeyHandle(gxy_key.get()); + if (prevkm_item.len != 0) { + prev_key = ImportKey(prevkm_item); + nss_ike_v1_prf_params.bHasPrevKey = true; + nss_ike_v1_prf_params.hPrevKey = PK11_GetSymKeyHandle(prev_key.get()); + } + break; + case IkeTestType::ikeV1AppB: + derive_mech = CKM_NSS_IKE1_APP_B_PRF_DERIVE; + params_item.data = (unsigned char *)&nss_ike_app_b_prf_params; + params_item.len = sizeof(nss_ike_app_b_prf_params); + break; + case IkeTestType::ikeV1AppBQuick: + derive_mech = CKM_NSS_IKE1_APP_B_PRF_DERIVE; + params_item.data = (unsigned char *)&nss_ike_app_b_prf_params_quick; + params_item.len = sizeof(nss_ike_app_b_prf_params_quick); + if (gxykm_item.len != 0) { + gxy_key = ImportKey(gxykm_item); + nss_ike_app_b_prf_params_quick.bHasKeygxy = true; + nss_ike_app_b_prf_params_quick.hKeygxy = + PK11_GetSymKeyHandle(gxy_key.get()); + } + break; + case IkeTestType::ikePlus: + derive_mech = CKM_NSS_IKE_PRF_PLUS_DERIVE; + params_item.data = (unsigned char *)&nss_ike_prf_plus_params; + params_item.len = sizeof(nss_ike_prf_plus_params); + break; + default: + ADD_FAILURE() << msg; + return; + } + ASSERT_NE(nullptr, ikm) << msg; + + ScopedPK11SymKey okm = ScopedPK11SymKey( + PK11_Derive(ikm.get(), derive_mech, ¶ms_item, + CKM_GENERIC_SECRET_KEY_GEN, CKA_DERIVE, vec.size)); + if (vec.valid) { + ASSERT_NE(nullptr, okm.get()) << msg; + ASSERT_EQ(SECSuccess, PK11_ExtractKeyValue(okm.get())) << msg; + SECItem *outItem = PK11_GetKeyData(okm.get()); + SECItem nullItem = {siBuffer, NULL, 0}; + if (outItem == NULL) { + outItem = &nullItem; + } + ASSERT_EQ(0, SECITEM_CompareItem(&okm_item, PK11_GetKeyData(okm.get()))) + << msg << std::endl + << " expect:" << DataBuffer(okm_item.data, okm_item.len) << std::endl + << " calc'd:" << DataBuffer(outItem->data, outItem->len) << std::endl; + } else { + ASSERT_EQ(nullptr, okm.get()) << msg; + } + } +}; + +TEST_P(Pkcs11IkeTest, IkeproofVectors) { + RunVectorTest(std::get<0>(GetParam()), std::get<1>(GetParam())); +} + +INSTANTIATE_TEST_SUITE_P( + IkeSha1, Pkcs11IkeTest, + ::testing::Combine(::testing::ValuesIn(kIkeSha1ProofVectors), + ::testing::Values(CKM_SHA_1_HMAC))); +INSTANTIATE_TEST_SUITE_P( + IkeSha256, Pkcs11IkeTest, + ::testing::Combine(::testing::ValuesIn(kIkeSha256ProofVectors), + ::testing::Values(CKM_SHA256_HMAC))); + +INSTANTIATE_TEST_SUITE_P( + IkeSha384, Pkcs11IkeTest, + ::testing::Combine(::testing::ValuesIn(kIkeSha384ProofVectors), + ::testing::Values(CKM_SHA384_HMAC))); + +INSTANTIATE_TEST_SUITE_P( + IkeSha512, Pkcs11IkeTest, + ::testing::Combine(::testing::ValuesIn(kIkeSha512ProofVectors), + ::testing::Values(CKM_SHA512_HMAC))); + +INSTANTIATE_TEST_SUITE_P( + IkeAESXCBC, Pkcs11IkeTest, + ::testing::Combine(::testing::ValuesIn(kIkeAesXcbcProofVectors), + ::testing::Values(CKM_AES_XCBC_MAC))); + +} // namespace nss_test diff --git a/security/nss/gtests/pk11_gtest/pk11_import_unittest.cc b/security/nss/gtests/pk11_gtest/pk11_import_unittest.cc new file mode 100644 index 0000000000..3dc7983f8b --- /dev/null +++ b/security/nss/gtests/pk11_gtest/pk11_import_unittest.cc @@ -0,0 +1,281 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include <memory> +#include "nss.h" +#include "pk11pub.h" +#include "pk11pqg.h" +#include "prerror.h" +#include "secoid.h" + +#include "cpputil.h" +#include "nss_scoped_ptrs.h" +#include "gtest/gtest.h" +#include "databuffer.h" +#include "pk11_keygen.h" + +namespace nss_test { + +// This deleter deletes a set of objects, unlike the deleter on +// ScopedPK11GenericObject, which only deletes one. +struct PK11GenericObjectsDeleter { + void operator()(PK11GenericObject* objs) { + if (objs) { + PK11_DestroyGenericObjects(objs); + } + } +}; + +class Pk11KeyImportTestBase : public ::testing::Test { + public: + Pk11KeyImportTestBase() = default; + virtual ~Pk11KeyImportTestBase() = default; + + void SetUp() override { + slot_.reset(PK11_GetInternalKeySlot()); + ASSERT_TRUE(slot_); + + static const uint8_t pw[] = "pw"; + SECItem pwItem = {siBuffer, toUcharPtr(pw), sizeof(pw)}; + password_.reset(SECITEM_DupItem(&pwItem)); + } + + void Test(const Pkcs11KeyPairGenerator& generator) { + // Generate a key and export it. + KeyType key_type = nullKey; + ScopedSECKEYEncryptedPrivateKeyInfo key_info; + ScopedSECItem public_value; + GenerateAndExport(generator, &key_type, &key_info, &public_value); + + // Note: NSS is currently unable export wrapped DH keys, so this doesn't + // test those beyond generate and verify. + if (key_type == dhKey) { + return; + } + ASSERT_NE(nullptr, public_value); + ASSERT_NE(nullptr, key_info); + + // Now import the encrypted key. + static const uint8_t nick[] = "nick"; + SECItem nickname = {siBuffer, toUcharPtr(nick), sizeof(nick)}; + SECKEYPrivateKey* priv_tmp; + SECStatus rv = PK11_ImportEncryptedPrivateKeyInfoAndReturnKey( + slot_.get(), key_info.get(), password_.get(), &nickname, + public_value.get(), PR_TRUE, PR_TRUE, key_type, 0, &priv_tmp, NULL); + ASSERT_EQ(SECSuccess, rv) << "PK11_ImportEncryptedPrivateKeyInfo failed " + << PORT_ErrorToName(PORT_GetError()); + ScopedSECKEYPrivateKey priv_key(priv_tmp); + ASSERT_NE(nullptr, priv_key); + + CheckForPublicKey(priv_key, public_value.get()); + } + + private: + SECItem GetPublicComponent(ScopedSECKEYPublicKey& pub_key) { + SECItem null = {siBuffer, NULL, 0}; + switch (SECKEY_GetPublicKeyType(pub_key.get())) { + case rsaKey: + case rsaPssKey: + case rsaOaepKey: + return pub_key->u.rsa.modulus; + case keaKey: + return pub_key->u.kea.publicValue; + case dsaKey: + return pub_key->u.dsa.publicValue; + case dhKey: + return pub_key->u.dh.publicValue; + case ecKey: + return pub_key->u.ec.publicValue; + case fortezzaKey: /* depricated */ + case nullKey: + /* didn't use default here so we can catch new key types at compile time + */ + break; + } + return null; + } + void CheckForPublicKey(const ScopedSECKEYPrivateKey& priv_key, + const SECItem* expected_public) { + // Verify the public key exists. + StackSECItem priv_id; + KeyType type = SECKEY_GetPrivateKeyType(priv_key.get()); + SECStatus rv = PK11_ReadRawAttribute(PK11_TypePrivKey, priv_key.get(), + CKA_ID, &priv_id); + ASSERT_EQ(SECSuccess, rv) << "Couldn't read CKA_ID from private key: " + << PORT_ErrorToName(PORT_GetError()); + + CK_ATTRIBUTE_TYPE value_type = CKA_VALUE; + switch (type) { + case rsaKey: + value_type = CKA_MODULUS; + break; + + case dhKey: + case dsaKey: + value_type = CKA_VALUE; + break; + + case ecKey: + value_type = CKA_EC_POINT; + break; + + default: + FAIL() << "unknown key type"; + } + + // Scan public key objects until we find one with the same CKA_ID as + // priv_key + std::unique_ptr<PK11GenericObject, PK11GenericObjectsDeleter> objs( + PK11_FindGenericObjects(slot_.get(), CKO_PUBLIC_KEY)); + ASSERT_NE(nullptr, objs); + for (PK11GenericObject* obj = objs.get(); obj != nullptr; + obj = PK11_GetNextGenericObject(obj)) { + StackSECItem pub_id; + rv = PK11_ReadRawAttribute(PK11_TypeGeneric, obj, CKA_ID, &pub_id); + if (rv != SECSuccess) { + // Can't read CKA_ID from object. + continue; + } + if (!SECITEM_ItemsAreEqual(&priv_id, &pub_id)) { + // This isn't the object we're looking for. + continue; + } + + StackSECItem token; + rv = PK11_ReadRawAttribute(PK11_TypeGeneric, obj, CKA_TOKEN, &token); + ASSERT_EQ(SECSuccess, rv); + ASSERT_EQ(1U, token.len); + ASSERT_NE(0, token.data[0]); + + StackSECItem raw_value; + SECItem decoded_value; + rv = PK11_ReadRawAttribute(PK11_TypeGeneric, obj, value_type, &raw_value); + ASSERT_EQ(SECSuccess, rv); + SECItem value = raw_value; + + // Decode the EC_POINT and check the output against expected. + // CKA_EC_POINT isn't stable, see Bug 1520649. + ScopedPLArenaPool arena(PORT_NewArena(DER_DEFAULT_CHUNKSIZE)); + ASSERT_TRUE(arena); + if (value_type == CKA_EC_POINT) { + // If this fails due to the noted inconsistency, we may need to + // check the whole raw_value, or remove a leading UNCOMPRESSED_POINT tag + rv = SEC_QuickDERDecodeItem(arena.get(), &decoded_value, + SEC_ASN1_GET(SEC_OctetStringTemplate), + &raw_value); + ASSERT_EQ(SECSuccess, rv); + value = decoded_value; + } + ASSERT_TRUE(SECITEM_ItemsAreEqual(expected_public, &value)) + << "expected: " + << DataBuffer(expected_public->data, expected_public->len) + << std::endl + << "actual: " << DataBuffer(value.data, value.len) << std::endl; + + // Finally, convert the private to public and ensure it matches. + ScopedSECKEYPublicKey pub_key(SECKEY_ConvertToPublicKey(priv_key.get())); + ASSERT_TRUE(pub_key); + SECItem converted_public = GetPublicComponent(pub_key); + ASSERT_TRUE(converted_public.len != 0); + + ASSERT_TRUE(SECITEM_ItemsAreEqual(expected_public, &converted_public)) + << "expected: " + << DataBuffer(expected_public->data, expected_public->len) + << std::endl + << "actual: " + << DataBuffer(converted_public.data, converted_public.len) + << std::endl; + } + } + + void GenerateAndExport(const Pkcs11KeyPairGenerator& generator, + KeyType* key_type, + ScopedSECKEYEncryptedPrivateKeyInfo* key_info, + ScopedSECItem* public_value) { + ScopedSECKEYPrivateKey priv_key; + ScopedSECKEYPublicKey pub_key; + generator.GenerateKey(&priv_key, &pub_key); + ASSERT_TRUE(priv_key); + + // Save the public value, which we will need on import */ + SECItem* pub_val; + KeyType t = SECKEY_GetPublicKeyType(pub_key.get()); + switch (t) { + case rsaKey: + pub_val = &pub_key->u.rsa.modulus; + break; + case dhKey: + pub_val = &pub_key->u.dh.publicValue; + break; + case dsaKey: + pub_val = &pub_key->u.dsa.publicValue; + break; + case ecKey: + pub_val = &pub_key->u.ec.publicValue; + break; + default: + FAIL() << "Unknown key type"; + } + + CheckForPublicKey(priv_key, pub_val); + + *key_type = t; + // Note: NSS is currently unable export wrapped DH keys, so this doesn't + // test those beyond generate and verify. + if (t == dhKey) { + return; + } + public_value->reset(SECITEM_DupItem(pub_val)); + + // Wrap and export the key. + ScopedSECKEYEncryptedPrivateKeyInfo epki(PK11_ExportEncryptedPrivKeyInfo( + slot_.get(), SEC_OID_AES_256_CBC, password_.get(), priv_key.get(), 1, + nullptr)); + ASSERT_NE(nullptr, epki) << "PK11_ExportEncryptedPrivKeyInfo failed: " + << PORT_ErrorToName(PORT_GetError()); + + key_info->swap(epki); + } + + ScopedPK11SlotInfo slot_; + ScopedSECItem password_; +}; + +class Pk11KeyImportTest + : public Pk11KeyImportTestBase, + public ::testing::WithParamInterface<CK_MECHANISM_TYPE> { + public: + Pk11KeyImportTest() = default; + virtual ~Pk11KeyImportTest() = default; +}; + +TEST_P(Pk11KeyImportTest, GenerateExportImport) { + Test(Pkcs11KeyPairGenerator(GetParam())); +} + +INSTANTIATE_TEST_SUITE_P(Pk11KeyImportTest, Pk11KeyImportTest, + ::testing::Values(CKM_RSA_PKCS_KEY_PAIR_GEN, + CKM_DSA_KEY_PAIR_GEN, + CKM_DH_PKCS_KEY_PAIR_GEN)); + +class Pk11KeyImportTestEC : public Pk11KeyImportTestBase, + public ::testing::WithParamInterface<SECOidTag> { + public: + Pk11KeyImportTestEC() = default; + virtual ~Pk11KeyImportTestEC() = default; +}; + +TEST_P(Pk11KeyImportTestEC, GenerateExportImport) { + Test(Pkcs11KeyPairGenerator(CKM_EC_KEY_PAIR_GEN, GetParam())); +} + +INSTANTIATE_TEST_SUITE_P(Pk11KeyImportTestEC, Pk11KeyImportTestEC, + ::testing::Values(SEC_OID_SECG_EC_SECP256R1, + SEC_OID_SECG_EC_SECP384R1, + SEC_OID_SECG_EC_SECP521R1, + SEC_OID_CURVE25519)); + +} // namespace nss_test diff --git a/security/nss/gtests/pk11_gtest/pk11_kbkdf.cc b/security/nss/gtests/pk11_gtest/pk11_kbkdf.cc new file mode 100644 index 0000000000..d8a0a0f58b --- /dev/null +++ b/security/nss/gtests/pk11_gtest/pk11_kbkdf.cc @@ -0,0 +1,136 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include <memory> +#include "nss.h" +#include "pk11pub.h" +#include "secerr.h" +#include "sechash.h" +#include "stdio.h" + +#include "blapi.h" + +#include "gtest/gtest.h" +#include "nss_scoped_ptrs.h" +#include "util.h" + +namespace nss_test { +class Pkcs11KbkdfTest : public ::testing::Test { + protected: + ScopedPK11SymKey ImportKey(CK_MECHANISM_TYPE mech, SECItem *key_item) { + ScopedPK11SlotInfo slot(PK11_GetInternalSlot()); + if (!slot) { + ADD_FAILURE() << "Can't get slot"; + return nullptr; + } + + ScopedPK11SymKey result(PK11_ImportSymKey( + slot.get(), mech, PK11_OriginUnwrap, CKA_SIGN, key_item, nullptr)); + + return result; + } + + void RunKDF(CK_MECHANISM_TYPE kdfMech, CK_SP800_108_KDF_PARAMS_PTR kdfParams, + CK_BYTE_PTR inputKey, unsigned int inputKeyLen, + CK_BYTE_PTR expectedKey, unsigned int expectedKeyLen, + CK_BYTE_PTR expectedAdditional, + unsigned int expectedAdditionalLen) { + SECItem keyItem = {siBuffer, inputKey, inputKeyLen}; + ScopedPK11SymKey p11Key = ImportKey(kdfParams->prfType, &keyItem); + + ASSERT_NE(kdfParams, nullptr); + SECItem paramsItem = {siBuffer, (unsigned char *)kdfParams, + sizeof(*kdfParams)}; + + ScopedPK11SymKey result(PK11_Derive(p11Key.get(), kdfMech, ¶msItem, + CKM_SHA512_HMAC, CKA_SIGN, + expectedKeyLen)); + ASSERT_NE(result, nullptr); + + ASSERT_EQ(PK11_ExtractKeyValue(result.get()), SECSuccess); + + /* We don't need to free this -- it is just a reference... */ + SECItem *actualItem = PK11_GetKeyData(result.get()); + ASSERT_NE(actualItem, nullptr); + + SECItem expectedItem = {siBuffer, expectedKey, expectedKeyLen}; + ASSERT_EQ(SECITEM_CompareItem(actualItem, &expectedItem), 0); + + /* Extract the additional key. */ + if (expectedAdditional == NULL || kdfParams->ulAdditionalDerivedKeys != 1) { + return; + } + + ScopedPK11SlotInfo slot(PK11_GetSlotFromKey(result.get())); + + CK_OBJECT_HANDLE_PTR keyHandle = kdfParams->pAdditionalDerivedKeys[0].phKey; + ScopedPK11SymKey additionalKey( + PK11_SymKeyFromHandle(slot.get(), result.get(), PK11_OriginDerive, + CKM_SHA512_HMAC, *keyHandle, PR_FALSE, NULL)); + + ASSERT_EQ(PK11_ExtractKeyValue(additionalKey.get()), SECSuccess); + + /* We don't need to free this -- it is just a reference... */ + actualItem = PK11_GetKeyData(additionalKey.get()); + ASSERT_NE(actualItem, nullptr); + + expectedItem = {siBuffer, expectedAdditional, expectedAdditionalLen}; + ASSERT_EQ(SECITEM_CompareItem(actualItem, &expectedItem), 0); + } +}; + +TEST_F(Pkcs11KbkdfTest, TestAdditionalKey) { + /* Test number 11 of NIST CAVP vectors for Counter mode KDF, with counter + * after a fixed input (AES/128 CMAC). Resulting key (of size 256 bits) + * split into two 128-bit chunks since that aligns with a PRF invocation + * boundary. */ + CK_BYTE inputKey[] = {0x23, 0xeb, 0x06, 0x5b, 0xe1, 0x27, 0xa8, 0x81, + 0xe3, 0x5a, 0x65, 0x14, 0xd4, 0x35, 0x67, 0x9f}; + CK_BYTE expectedKey[] = {0xea, 0x4e, 0xbb, 0xb4, 0xef, 0xff, 0x4b, 0x01, + 0x68, 0x40, 0x12, 0xed, 0x8f, 0xf9, 0xc6, 0x4e}; + CK_BYTE expectedAdditional[] = {0x70, 0xae, 0x38, 0x19, 0x7c, 0x36, + 0x44, 0x5a, 0x6c, 0x80, 0x4a, 0x0e, + 0x44, 0x81, 0x9a, 0xc3}; + + CK_SP800_108_COUNTER_FORMAT iterator = {CK_FALSE, 8}; + CK_BYTE fixedData[] = { + 0xe6, 0x79, 0x86, 0x1a, 0x61, 0x34, 0x65, 0xa6, 0x73, 0x85, 0x37, 0x26, + 0x71, 0xb1, 0x07, 0xe6, 0xb8, 0x95, 0xa2, 0xf6, 0x40, 0x43, 0xc9, 0x34, + 0xff, 0x42, 0x56, 0xa7, 0xe6, 0x3c, 0xfb, 0x8b, 0xfa, 0xcc, 0x21, 0x24, + 0x25, 0x1c, 0x90, 0xfa, 0x67, 0x0d, 0x45, 0x74, 0x5c, 0x1c, 0x35, 0xda, + 0x9b, 0x6e, 0x05, 0xaf, 0x77, 0xea, 0x9c, 0x4a, 0xd4, 0x86, 0xfd, 0x1a}; + + CK_PRF_DATA_PARAM dataParams[] = { + {CK_SP800_108_BYTE_ARRAY, fixedData, + sizeof(fixedData) / sizeof(*fixedData)}, + {CK_SP800_108_ITERATION_VARIABLE, &iterator, sizeof(iterator)}}; + + CK_KEY_TYPE ckGeneric = CKK_GENERIC_SECRET; + CK_OBJECT_CLASS ckClass = CKO_SECRET_KEY; + CK_ULONG derivedLength = 16; + + CK_ATTRIBUTE derivedTemplate[] = { + {CKA_CLASS, &ckClass, sizeof(ckClass)}, + {CKA_KEY_TYPE, &ckGeneric, sizeof(ckGeneric)}, + {CKA_VALUE_LEN, &derivedLength, sizeof(derivedLength)}}; + + CK_OBJECT_HANDLE keyHandle; + CK_DERIVED_KEY derivedKey = { + derivedTemplate, sizeof(derivedTemplate) / sizeof(*derivedTemplate), + &keyHandle}; + + CK_SP800_108_KDF_PARAMS kdfParams = {CKM_AES_CMAC, + sizeof(dataParams) / sizeof(*dataParams), + dataParams, 1, &derivedKey}; + + RunKDF(CKM_SP800_108_COUNTER_KDF, &kdfParams, inputKey, + sizeof(inputKey) / sizeof(*inputKey), expectedKey, + sizeof(expectedKey) / sizeof(*expectedKey), expectedAdditional, + sizeof(expectedAdditional) / sizeof(*expectedAdditional)); +} + +// Close the namespace +} diff --git a/security/nss/gtests/pk11_gtest/pk11_key_unittest.cc b/security/nss/gtests/pk11_gtest/pk11_key_unittest.cc new file mode 100644 index 0000000000..9d5c96f3b2 --- /dev/null +++ b/security/nss/gtests/pk11_gtest/pk11_key_unittest.cc @@ -0,0 +1,80 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include <memory> +#include "nss.h" +#include "pk11pub.h" +#include "pk11pqg.h" +#include "prerror.h" +#include "secoid.h" + +#include "gtest/gtest.h" +#include "nss_scoped_ptrs.h" +#include "pk11_keygen.h" + +namespace nss_test { + +class Pkcs11NullKeyTestBase : public ::testing::Test { + protected: + // This constructs a key pair, then erases the public value from the public + // key. NSS should reject this. + void Test(const Pkcs11KeyPairGenerator& generator, + CK_MECHANISM_TYPE dh_mech) { + ScopedSECKEYPrivateKey priv; + ScopedSECKEYPublicKey pub; + generator.GenerateKey(&priv, &pub); + ASSERT_TRUE(priv); + + // These don't leak because they are allocated to the arena associated with + // the public key. + SECItem* pub_val = nullptr; + switch (SECKEY_GetPublicKeyType(pub.get())) { + case rsaKey: + pub_val = &pub->u.rsa.modulus; + break; + + case dsaKey: + pub_val = &pub->u.dsa.publicValue; + break; + + case dhKey: + pub_val = &pub->u.dh.publicValue; + break; + + case ecKey: + pub_val = &pub->u.ec.publicValue; + break; + + default: + FAIL() << "Unknown key type " << SECKEY_GetPublicKeyType(pub.get()); + } + pub_val->data = nullptr; + pub_val->len = 0; + + ScopedPK11SymKey symKey(PK11_PubDeriveWithKDF( + priv.get(), pub.get(), false, nullptr, nullptr, dh_mech, + CKM_SHA512_HMAC, CKA_DERIVE, 0, CKD_NULL, nullptr, nullptr)); + ASSERT_FALSE(symKey); + } +}; + +class Pkcs11DhNullKeyTest : public Pkcs11NullKeyTestBase {}; +TEST_F(Pkcs11DhNullKeyTest, UseNullPublicValue) { + Test(Pkcs11KeyPairGenerator(CKM_DH_PKCS_KEY_PAIR_GEN), CKM_DH_PKCS_DERIVE); +} + +class Pkcs11EcdhNullKeyTest : public Pkcs11NullKeyTestBase, + public ::testing::WithParamInterface<SECOidTag> { +}; +TEST_P(Pkcs11EcdhNullKeyTest, UseNullPublicValue) { + Test(Pkcs11KeyPairGenerator(CKM_EC_KEY_PAIR_GEN, GetParam()), + CKM_ECDH1_DERIVE); +} +INSTANTIATE_TEST_SUITE_P(Pkcs11EcdhNullKeyTest, Pkcs11EcdhNullKeyTest, + ::testing::Values(SEC_OID_SECG_EC_SECP256R1, + SEC_OID_SECG_EC_SECP384R1, + SEC_OID_SECG_EC_SECP521R1, + SEC_OID_CURVE25519)); + +} // namespace nss_test diff --git a/security/nss/gtests/pk11_gtest/pk11_keygen.cc b/security/nss/gtests/pk11_gtest/pk11_keygen.cc new file mode 100644 index 0000000000..d96cd38f69 --- /dev/null +++ b/security/nss/gtests/pk11_gtest/pk11_keygen.cc @@ -0,0 +1,143 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "pk11_keygen.h" + +#include "pk11pub.h" +#include "pk11pqg.h" +#include "prerror.h" + +#include "gtest/gtest.h" + +namespace nss_test { + +class ParamHolder { + public: + virtual void* get() = 0; + virtual ~ParamHolder() = default; + + protected: + ParamHolder() = default; +}; + +void Pkcs11KeyPairGenerator::GenerateKey(ScopedSECKEYPrivateKey* priv_key, + ScopedSECKEYPublicKey* pub_key) const { + // This function returns if an assertion fails, so don't leak anything. + priv_key->reset(nullptr); + pub_key->reset(nullptr); + + auto params = MakeParams(); + ASSERT_NE(nullptr, params); + + ScopedPK11SlotInfo slot(PK11_GetInternalKeySlot()); + ASSERT_TRUE(slot); + + SECKEYPublicKey* pub_tmp; + ScopedSECKEYPrivateKey priv_tmp(PK11_GenerateKeyPair( + slot.get(), mech_, params->get(), &pub_tmp, PR_FALSE, PR_TRUE, nullptr)); + ASSERT_NE(nullptr, priv_tmp) << "PK11_GenerateKeyPair failed: " + << PORT_ErrorToName(PORT_GetError()); + ASSERT_NE(nullptr, pub_tmp); + + priv_key->swap(priv_tmp); + pub_key->reset(pub_tmp); +} + +class RsaParamHolder : public ParamHolder { + public: + RsaParamHolder() : params_({1024, 0x010001}) {} + ~RsaParamHolder() = default; + + void* get() override { return ¶ms_; } + + private: + PK11RSAGenParams params_; +}; + +class PqgParamHolder : public ParamHolder { + public: + PqgParamHolder(PQGParams* params) : params_(params) {} + ~PqgParamHolder() = default; + + void* get() override { return params_.get(); } + + private: + ScopedPQGParams params_; +}; + +class DhParamHolder : public PqgParamHolder { + public: + DhParamHolder(PQGParams* params) + : PqgParamHolder(params), + params_({nullptr, params->prime, params->base}) {} + ~DhParamHolder() = default; + + void* get() override { return ¶ms_; } + + private: + SECKEYDHParams params_; +}; + +class EcParamHolder : public ParamHolder { + public: + EcParamHolder(SECOidTag curve_oid) { + SECOidData* curve = SECOID_FindOIDByTag(curve_oid); + EXPECT_NE(nullptr, curve); + + size_t plen = curve->oid.len + 2; + extra_.reset(new uint8_t[plen]); + extra_[0] = SEC_ASN1_OBJECT_ID; + extra_[1] = static_cast<uint8_t>(curve->oid.len); + memcpy(&extra_[2], curve->oid.data, curve->oid.len); + + ec_params_ = {siBuffer, extra_.get(), static_cast<unsigned int>(plen)}; + } + ~EcParamHolder() = default; + + void* get() override { return &ec_params_; } + + private: + SECKEYECParams ec_params_; + std::unique_ptr<uint8_t[]> extra_; +}; + +std::unique_ptr<ParamHolder> Pkcs11KeyPairGenerator::MakeParams() const { + switch (mech_) { + case CKM_RSA_PKCS_KEY_PAIR_GEN: + std::cerr << "Generate RSA pair" << std::endl; + return std::unique_ptr<ParamHolder>(new RsaParamHolder()); + + case CKM_DSA_KEY_PAIR_GEN: + case CKM_DH_PKCS_KEY_PAIR_GEN: { + PQGParams* pqg_params = nullptr; + PQGVerify* pqg_verify = nullptr; + const unsigned int key_size = 1024; + SECStatus rv = PK11_PQG_ParamGenV2(key_size, 0, key_size / 16, + &pqg_params, &pqg_verify); + if (rv != SECSuccess) { + ADD_FAILURE() << "PK11_PQG_ParamGenV2 failed"; + return nullptr; + } + EXPECT_NE(nullptr, pqg_verify); + EXPECT_NE(nullptr, pqg_params); + PK11_PQG_DestroyVerify(pqg_verify); + if (mech_ == CKM_DSA_KEY_PAIR_GEN) { + std::cerr << "Generate DSA pair" << std::endl; + return std::unique_ptr<ParamHolder>(new PqgParamHolder(pqg_params)); + } + std::cerr << "Generate DH pair" << std::endl; + return std::unique_ptr<ParamHolder>(new DhParamHolder(pqg_params)); + } + + case CKM_EC_KEY_PAIR_GEN: + std::cerr << "Generate EC pair on " << curve_ << std::endl; + return std::unique_ptr<ParamHolder>(new EcParamHolder(curve_)); + + default: + ADD_FAILURE() << "unknown OID " << mech_; + } + return nullptr; +} + +} // namespace nss_test diff --git a/security/nss/gtests/pk11_gtest/pk11_keygen.h b/security/nss/gtests/pk11_gtest/pk11_keygen.h new file mode 100644 index 0000000000..05ff972107 --- /dev/null +++ b/security/nss/gtests/pk11_gtest/pk11_keygen.h @@ -0,0 +1,34 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "nss.h" +#include "secoid.h" + +#include "nss_scoped_ptrs.h" + +namespace nss_test { + +class ParamHolder; + +class Pkcs11KeyPairGenerator { + public: + Pkcs11KeyPairGenerator(CK_MECHANISM_TYPE mech, SECOidTag curve_oid) + : mech_(mech), curve_(curve_oid) {} + Pkcs11KeyPairGenerator(CK_MECHANISM_TYPE mech) + : Pkcs11KeyPairGenerator(mech, SEC_OID_UNKNOWN) {} + + CK_MECHANISM_TYPE mechanism() const { return mech_; } + SECOidTag curve() const { return curve_; } + + void GenerateKey(ScopedSECKEYPrivateKey* priv_key, + ScopedSECKEYPublicKey* pub_key) const; + + private: + std::unique_ptr<ParamHolder> MakeParams() const; + + CK_MECHANISM_TYPE mech_; + SECOidTag curve_; +}; + +} // namespace nss_test diff --git a/security/nss/gtests/pk11_gtest/pk11_module_unittest.cc b/security/nss/gtests/pk11_gtest/pk11_module_unittest.cc new file mode 100644 index 0000000000..9627c823e9 --- /dev/null +++ b/security/nss/gtests/pk11_gtest/pk11_module_unittest.cc @@ -0,0 +1,84 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include <memory> +#include "nss.h" +#include "pk11pub.h" +#include "prerror.h" +#include "prsystem.h" +#include "secoid.h" + +#include "nss_scoped_ptrs.h" +#include "gtest/gtest.h" +#include "databuffer.h" + +namespace nss_test { + +class Pkcs11ModuleTest : public ::testing::Test { + public: + Pkcs11ModuleTest() {} + + void SetUp() override { + ASSERT_EQ(SECSuccess, SECMOD_AddNewModule("Pkcs11ModuleTest", DLL_PREFIX + "pkcs11testmodule." DLL_SUFFIX, + 0, 0)) + << PORT_ErrorToName(PORT_GetError()); + } + + void TearDown() override { + int type; + ASSERT_EQ(SECSuccess, SECMOD_DeleteModule("Pkcs11ModuleTest", &type)); + ASSERT_EQ(SECMOD_EXTERNAL, type); + } +}; + +TEST_F(Pkcs11ModuleTest, LoadUnload) { + ScopedSECMODModule module(SECMOD_FindModule("Pkcs11ModuleTest")); + EXPECT_NE(nullptr, module); +} + +TEST_F(Pkcs11ModuleTest, ListSlots) { + ScopedPK11SlotList slots( + PK11_GetAllTokens(CKM_INVALID_MECHANISM, PR_FALSE, PR_FALSE, nullptr)); + EXPECT_NE(nullptr, slots); + + PK11SlotListElement* element = PK11_GetFirstSafe(slots.get()); + EXPECT_NE(nullptr, element); + + // These tokens are always present. + const std::vector<std::string> kSlotsWithToken = { + "NSS Internal Cryptographic Services", + "NSS User Private Key and Certificate Services", + "Test PKCS11 Public Certs Slot", "Test PKCS11 Slot 二"}; + std::vector<std::string> foundSlots; + + do { + std::string name = PK11_GetSlotName(element->slot); + foundSlots.push_back(name); + std::cerr << "loaded slot: " << name << std::endl; + } while ((element = PK11_GetNextSafe(slots.get(), element, PR_FALSE)) != + nullptr); + + std::sort(foundSlots.begin(), foundSlots.end()); + EXPECT_TRUE(std::equal(kSlotsWithToken.begin(), kSlotsWithToken.end(), + foundSlots.begin())); +} + +TEST_F(Pkcs11ModuleTest, PublicCertificatesToken) { + const std::string kRegularToken = "Test PKCS11 Tokeñ 2 Label"; + const std::string kPublicCertificatesToken = "Test PKCS11 Public Certs Token"; + + ScopedPK11SlotInfo slot1(PK11_FindSlotByName(kRegularToken.c_str())); + EXPECT_NE(nullptr, slot1); + EXPECT_FALSE(PK11_IsFriendly(slot1.get())); + + ScopedPK11SlotInfo slot2( + PK11_FindSlotByName(kPublicCertificatesToken.c_str())); + EXPECT_NE(nullptr, slot2); + EXPECT_TRUE(PK11_IsFriendly(slot2.get())); +} + +} // namespace nss_test diff --git a/security/nss/gtests/pk11_gtest/pk11_pbkdf2_unittest.cc b/security/nss/gtests/pk11_gtest/pk11_pbkdf2_unittest.cc new file mode 100644 index 0000000000..5036540612 --- /dev/null +++ b/security/nss/gtests/pk11_gtest/pk11_pbkdf2_unittest.cc @@ -0,0 +1,184 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include <memory> +#include "nss.h" +#include "pk11pub.h" + +#include "gtest/gtest.h" +#include "nss_scoped_ptrs.h" + +namespace nss_test { + +static unsigned char* ToUcharPtr(std::string& str) { + return const_cast<unsigned char*>( + reinterpret_cast<const unsigned char*>(str.c_str())); +} + +class Pkcs11Pbkdf2Test : public ::testing::Test { + public: + void Derive(std::vector<uint8_t>& derived, SECOidTag hash_alg) { + // Shared between test vectors. + const unsigned int kIterations = 4096; + std::string pass("passwordPASSWORDpassword"); + std::string salt("saltSALTsaltSALTsaltSALTsaltSALTsalt"); + + // Derivation must succeed with the right values. + EXPECT_TRUE(DeriveBytes(pass, salt, derived, hash_alg, kIterations)); + + // Derivation must fail when the password is bogus. + std::string bogus_pass("PasswordPASSWORDpassword"); + EXPECT_FALSE(DeriveBytes(bogus_pass, salt, derived, hash_alg, kIterations)); + + // Derivation must fail when the salt is bogus. + std::string bogus_salt("SaltSALTsaltSALTsaltSALTsaltSALTsalt"); + EXPECT_FALSE(DeriveBytes(pass, bogus_salt, derived, hash_alg, kIterations)); + + // Derivation must fail when using the wrong hash function. + SECOidTag next_hash_alg = static_cast<SECOidTag>(hash_alg + 1); + EXPECT_FALSE(DeriveBytes(pass, salt, derived, next_hash_alg, kIterations)); + + // Derivation must fail when using the wrong number of kIterations. + EXPECT_FALSE(DeriveBytes(pass, salt, derived, hash_alg, kIterations + 1)); + } + + void KeySizes(SECOidTag hash_alg) { + // These tests will only validate the controls around the key sizes. + // The resulting key is tested above, with valid key sizes. + const unsigned int kIterations = 10; + std::string pass("passwordPASSWORDpassword"); + std::string salt("saltSALTsaltSALTsaltSALTsaltSALTsalt"); + std::string salt_empty(""); + + // Derivation must fail when using key sizes bigger than MAX_KEY_LEN. + const int big_key_size = 768; + EXPECT_FALSE(KeySizeParam(pass, salt, big_key_size, hash_alg, kIterations)); + + // Zero is acceptable as key size and will be managed internally. + const int zero_key_size = 0; + EXPECT_TRUE(KeySizeParam(pass, salt, zero_key_size, hash_alg, kIterations)); + + // Zero is acceptable as salt size and will be managed internally. + EXPECT_TRUE( + KeySizeParam(pass, salt_empty, zero_key_size, hash_alg, kIterations)); + + // -1 will be set to 0 internally and this means that the key size will be + // obtained from the template. If the template doesn't have this defined, + // it must fail. + const int minus_key_size = -1; + EXPECT_FALSE( + KeySizeParam(pass, salt, minus_key_size, hash_alg, kIterations)); + + // Lower than -1 is not allowed, as -1 means no keyLen defined. + const int negative_key_size = -10; + EXPECT_FALSE( + KeySizeParam(pass, salt, negative_key_size, hash_alg, kIterations)); + + // Malformed inputs are handled without crashing + EXPECT_FALSE( + MalformedPass(pass, salt, big_key_size, hash_alg, kIterations)); + EXPECT_FALSE( + MalformedSalt(pass, salt, big_key_size, hash_alg, kIterations)); + } + + private: + bool DeriveBytes(std::string& pass, std::string& salt, + std::vector<uint8_t>& derived, SECOidTag hash_alg, + unsigned int kIterations) { + SECItem pass_item = {siBuffer, ToUcharPtr(pass), + static_cast<unsigned int>(pass.length())}; + SECItem salt_item = {siBuffer, ToUcharPtr(salt), + static_cast<unsigned int>(salt.length())}; + + // Set up PBKDF2 params. + ScopedSECAlgorithmID alg_id( + PK11_CreatePBEV2AlgorithmID(SEC_OID_PKCS5_PBKDF2, hash_alg, hash_alg, + derived.size(), kIterations, &salt_item)); + + // Derive. + ScopedPK11SlotInfo slot(PK11_GetInternalSlot()); + ScopedPK11SymKey sym_key( + PK11_PBEKeyGen(slot.get(), alg_id.get(), &pass_item, false, nullptr)); + + SECStatus rv = PK11_ExtractKeyValue(sym_key.get()); + EXPECT_EQ(rv, SECSuccess); + + SECItem* key_data = PK11_GetKeyData(sym_key.get()); + return !memcmp(&derived[0], key_data->data, key_data->len); + } + + bool GenerateKey(SECItem pass_item, SECItem salt_item, const int key_size, + SECOidTag hash_alg, unsigned int kIterations) { + // Set up PBKDF2 params. + ScopedSECAlgorithmID alg_id( + PK11_CreatePBEV2AlgorithmID(SEC_OID_PKCS5_PBKDF2, hash_alg, hash_alg, + key_size, kIterations, &salt_item)); + + // Try to generate a key with the defined params. + ScopedPK11SlotInfo slot(PK11_GetInternalSlot()); + ScopedPK11SymKey sym_key( + PK11_PBEKeyGen(slot.get(), alg_id.get(), &pass_item, false, nullptr)); + + // Should be nullptr if fail. + return sym_key.get(); + } + + bool KeySizeParam(std::string& pass, std::string& salt, const int key_size, + SECOidTag hash_alg, unsigned int kIterations) { + SECItem pass_item = {siBuffer, ToUcharPtr(pass), + static_cast<unsigned int>(pass.length())}; + SECItem salt_item = {siBuffer, ToUcharPtr(salt), + static_cast<unsigned int>(salt.length())}; + + return GenerateKey(pass_item, salt_item, key_size, hash_alg, kIterations); + } + + bool MalformedSalt(std::string& pass, std::string& salt, const int key_size, + SECOidTag hash_alg, unsigned int kIterations) { + SECItem pass_item = {siBuffer, ToUcharPtr(pass), + static_cast<unsigned int>(pass.length())}; + SECItem salt_item = {siBuffer, nullptr, 0}; + + return GenerateKey(pass_item, salt_item, key_size, hash_alg, kIterations); + } + + bool MalformedPass(std::string& pass, std::string& salt, const int key_size, + SECOidTag hash_alg, unsigned int kIterations) { + SECItem pass_item = {siBuffer, nullptr, 0}; + SECItem salt_item = {siBuffer, ToUcharPtr(salt), + static_cast<unsigned int>(salt.length())}; + + return GenerateKey(pass_item, salt_item, key_size, hash_alg, kIterations); + } +}; + +// RFC 6070 <http://tools.ietf.org/html/rfc6070> +TEST_F(Pkcs11Pbkdf2Test, DeriveKnown1) { + std::vector<uint8_t> derived = {0x3d, 0x2e, 0xec, 0x4f, 0xe4, 0x1c, 0x84, + 0x9b, 0x80, 0xc8, 0xd8, 0x36, 0x62, 0xc0, + 0xe4, 0x4a, 0x8b, 0x29, 0x1a, 0x96, 0x4c, + 0xf2, 0xf0, 0x70, 0x38}; + + Derive(derived, SEC_OID_HMAC_SHA1); +} + +// https://stackoverflow.com/questions/5130513/pbkdf2-hmac-sha2-test-vectors +TEST_F(Pkcs11Pbkdf2Test, DeriveKnown2) { + std::vector<uint8_t> derived = { + 0x34, 0x8c, 0x89, 0xdb, 0xcb, 0xd3, 0x2b, 0x2f, 0x32, 0xd8, + 0x14, 0xb8, 0x11, 0x6e, 0x84, 0xcf, 0x2b, 0x17, 0x34, 0x7e, + 0xbc, 0x18, 0x00, 0x18, 0x1c, 0x4e, 0x2a, 0x1f, 0xb8, 0xdd, + 0x53, 0xe1, 0xc6, 0x35, 0x51, 0x8c, 0x7d, 0xac, 0x47, 0xe9}; + + Derive(derived, SEC_OID_HMAC_SHA256); +} + +TEST_F(Pkcs11Pbkdf2Test, KeyLenSizes) { + // The size controls are regardless of the algorithms. + KeySizes(SEC_OID_HMAC_SHA256); +} + +} // namespace nss_test diff --git a/security/nss/gtests/pk11_gtest/pk11_prf_unittest.cc b/security/nss/gtests/pk11_gtest/pk11_prf_unittest.cc new file mode 100644 index 0000000000..3580b10a2f --- /dev/null +++ b/security/nss/gtests/pk11_gtest/pk11_prf_unittest.cc @@ -0,0 +1,227 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include <memory> +#include "nss.h" +#include "pk11pub.h" + +#include "cpputil.h" + +#include "gtest/gtest.h" + +namespace nss_test { + +const size_t kPmsSize = 48; +const size_t kMasterSecretSize = 48; +const size_t kPrfSeedSizeSha256 = 32; +const size_t kPrfSeedSizeTlsPrf = 36; + +// This is not the right size for anything +const size_t kIncorrectSize = 17; + +const uint8_t kPmsData[] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, + 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, + 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f}; + +const uint8_t kPrfSeed[] = { + 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, + 0xfc, 0xfd, 0xfe, 0xff, 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, + 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, 0xd0, 0xd1, 0xd2, 0xd3}; + +const uint8_t kExpectedOutputEmsSha256[] = { + 0x75, 0xa7, 0xa5, 0x98, 0xef, 0xab, 0x90, 0xe7, 0x7c, 0x67, 0x80, 0xde, + 0xab, 0x3a, 0x11, 0xf3, 0x5d, 0xb2, 0xf8, 0x47, 0xff, 0x09, 0x01, 0xec, + 0xf8, 0x93, 0x89, 0xfc, 0x98, 0x2e, 0x6e, 0xf9, 0x2c, 0xf5, 0x9b, 0x04, + 0x04, 0x6f, 0xd7, 0x28, 0x6e, 0xea, 0xe3, 0x83, 0xc4, 0x4a, 0xff, 0x03}; + +const uint8_t kExpectedOutputEmsTlsPrf[] = { + 0x06, 0xbf, 0x29, 0x86, 0x5d, 0xf3, 0x3e, 0x38, 0xfd, 0xfa, 0x91, 0x10, + 0x2a, 0x20, 0xff, 0xd6, 0xb9, 0xd5, 0x72, 0x5a, 0x6d, 0x42, 0x20, 0x16, + 0xde, 0xa4, 0xa0, 0x51, 0xe5, 0x53, 0xc1, 0x28, 0x04, 0x99, 0xbc, 0xb1, + 0x2c, 0x9d, 0xe8, 0x0b, 0x18, 0xa2, 0x0e, 0x48, 0x52, 0x8d, 0x61, 0x13}; + +class TlsPrfTest : public ::testing::Test { + public: + TlsPrfTest() + : params_({siBuffer, nullptr, 0}), + pms_item_({siBuffer, toUcharPtr(kPmsData), kPmsSize}), + key_mech_(0), + slot_(nullptr), + pms_(nullptr), + ms_(nullptr), + pms_version_({0, 0}) {} + + ~TlsPrfTest() { + if (slot_) { + PK11_FreeSlot(slot_); + } + ClearTempVars(); + } + + void ClearTempVars() { + if (pms_) { + PK11_FreeSymKey(pms_); + } + if (ms_) { + PK11_FreeSymKey(ms_); + } + } + + void Init() { + params_.type = siBuffer; + + pms_item_.type = siBuffer; + pms_item_.data = + const_cast<unsigned char*>(static_cast<const unsigned char*>(kPmsData)); + + slot_ = PK11_GetInternalSlot(); + ASSERT_NE(nullptr, slot_); + } + + void CheckForError(CK_MECHANISM_TYPE hash_mech, size_t seed_len, + size_t pms_len, size_t output_len) { + // Error tests don't depend on the derivation mechansim + Inner(CKM_NSS_TLS_EXTENDED_MASTER_KEY_DERIVE, hash_mech, seed_len, pms_len, + output_len, nullptr, nullptr); + } + + void ComputeAndVerifyMs(CK_MECHANISM_TYPE derive_mech, + CK_MECHANISM_TYPE hash_mech, CK_VERSION* version, + const uint8_t* expected) { + // Infer seed length from mechanism + int seed_len = 0; + switch (hash_mech) { + case CKM_TLS_PRF: + seed_len = kPrfSeedSizeTlsPrf; + break; + case CKM_SHA256: + seed_len = kPrfSeedSizeSha256; + break; + default: + ASSERT_TRUE(false); + } + + Inner(derive_mech, hash_mech, seed_len, kPmsSize, 0, version, expected); + } + + // Set output == nullptr to test when errors occur + void Inner(CK_MECHANISM_TYPE derive_mech, CK_MECHANISM_TYPE hash_mech, + size_t seed_len, size_t pms_len, size_t output_len, + CK_VERSION* version, const uint8_t* expected) { + ClearTempVars(); + + // Infer the key mechanism from the hash type + switch (hash_mech) { + case CKM_TLS_PRF: + key_mech_ = CKM_TLS_KEY_AND_MAC_DERIVE; + break; + case CKM_SHA256: + key_mech_ = CKM_NSS_TLS_KEY_AND_MAC_DERIVE_SHA256; + break; + default: + ASSERT_TRUE(false); + } + + // Import the params + CK_NSS_TLS_EXTENDED_MASTER_KEY_DERIVE_PARAMS master_params = { + hash_mech, toUcharPtr(kPrfSeed), static_cast<CK_ULONG>(seed_len), + version}; + params_.data = reinterpret_cast<unsigned char*>(&master_params); + params_.len = sizeof(master_params); + + // Import the PMS + pms_item_.len = pms_len; + pms_ = PK11_ImportSymKey(slot_, derive_mech, PK11_OriginUnwrap, CKA_DERIVE, + &pms_item_, NULL); + ASSERT_NE(nullptr, pms_); + + // Compute the EMS + ms_ = PK11_DeriveWithFlags(pms_, derive_mech, ¶ms_, key_mech_, + CKA_DERIVE, output_len, CKF_SIGN | CKF_VERIFY); + + // Verify the EMS has the expected value (null or otherwise) + if (!expected) { + EXPECT_EQ(nullptr, ms_); + } else { + ASSERT_NE(nullptr, ms_); + + SECStatus rv = PK11_ExtractKeyValue(ms_); + ASSERT_EQ(SECSuccess, rv); + + SECItem* msData = PK11_GetKeyData(ms_); + ASSERT_NE(nullptr, msData); + + ASSERT_EQ(kMasterSecretSize, msData->len); + EXPECT_EQ(0, memcmp(msData->data, expected, kMasterSecretSize)); + } + } + + protected: + SECItem params_; + SECItem pms_item_; + CK_MECHANISM_TYPE key_mech_; + PK11SlotInfo* slot_; + PK11SymKey* pms_; + PK11SymKey* ms_; + CK_VERSION pms_version_; +}; + +TEST_F(TlsPrfTest, ExtendedMsParamErr) { + Init(); + + // This should fail; it's the correct set from which the below are derived + // CheckForError(CKM_NSS_TLS_EXTENDED_MASTER_KEY_DERIVE, CKM_TLS_PRF, + // kPrfSeedSizeTlsPrf, kPmsSize, 0); + + // Output key size != 0, SSL3_MASTER_SECRET_LENGTH + CheckForError(CKM_TLS_PRF, kPrfSeedSizeTlsPrf, kPmsSize, kIncorrectSize); + + // not-DH && pms size != SSL3_PMS_LENGTH + CheckForError(CKM_TLS_PRF, kPrfSeedSizeTlsPrf, kIncorrectSize, 0); + + // CKM_TLS_PRF && seed length != MD5_LENGTH + SHA1_LENGTH + CheckForError(CKM_TLS_PRF, kIncorrectSize, kPmsSize, 0); + + // !CKM_TLS_PRF && seed length != hash output length + CheckForError(CKM_SHA256, kIncorrectSize, kPmsSize, 0); +} + +// Test matrix: +// +// DH RSA +// TLS_PRF 1 2 +// SHA256 3 4 +TEST_F(TlsPrfTest, ExtendedMsDhTlsPrf) { + Init(); + ComputeAndVerifyMs(CKM_NSS_TLS_EXTENDED_MASTER_KEY_DERIVE_DH, CKM_TLS_PRF, + nullptr, kExpectedOutputEmsTlsPrf); +} + +TEST_F(TlsPrfTest, ExtendedMsRsaTlsPrf) { + Init(); + ComputeAndVerifyMs(CKM_NSS_TLS_EXTENDED_MASTER_KEY_DERIVE, CKM_TLS_PRF, + &pms_version_, kExpectedOutputEmsTlsPrf); + EXPECT_EQ(0, pms_version_.major); + EXPECT_EQ(1, pms_version_.minor); +} + +TEST_F(TlsPrfTest, ExtendedMsDhSha256) { + Init(); + ComputeAndVerifyMs(CKM_NSS_TLS_EXTENDED_MASTER_KEY_DERIVE_DH, CKM_SHA256, + nullptr, kExpectedOutputEmsSha256); +} + +TEST_F(TlsPrfTest, ExtendedMsRsaSha256) { + Init(); + ComputeAndVerifyMs(CKM_NSS_TLS_EXTENDED_MASTER_KEY_DERIVE, CKM_SHA256, + &pms_version_, kExpectedOutputEmsSha256); + EXPECT_EQ(0, pms_version_.major); + EXPECT_EQ(1, pms_version_.minor); +} + +} // namespace nss_test diff --git a/security/nss/gtests/pk11_gtest/pk11_prng_unittest.cc b/security/nss/gtests/pk11_gtest/pk11_prng_unittest.cc new file mode 100644 index 0000000000..ef05fe51cd --- /dev/null +++ b/security/nss/gtests/pk11_gtest/pk11_prng_unittest.cc @@ -0,0 +1,121 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include <memory> +#include "blapi.h" +#include "pk11pub.h" + +#include "gtest/gtest.h" + +namespace nss_test { + +class PK11PrngTest : public ::testing::Test {}; + +#ifdef UNSAFE_FUZZER_MODE + +// Test that two consecutive calls to the RNG return two distinct values. +TEST_F(PK11PrngTest, Fuzz_DetPRNG) { + std::vector<uint8_t> rnd1(2048, 0); + std::vector<uint8_t> rnd2(2048, 0); + + SECStatus rv = PK11_GenerateRandom(rnd1.data(), rnd1.size()); + EXPECT_EQ(rv, SECSuccess); + + rv = PK11_GenerateRandom(rnd2.data(), rnd2.size()); + EXPECT_EQ(rv, SECSuccess); + + EXPECT_NE(rnd1, rnd2); +} + +// Test that two consecutive calls to the RNG return two equal values +// when the RNG's internal state is reset before each call. +TEST_F(PK11PrngTest, Fuzz_DetPRNG_Reset) { + std::vector<uint8_t> rnd1(2048, 0); + std::vector<uint8_t> rnd2(2048, 0); + + EXPECT_EQ(SECSuccess, RNG_RandomUpdate(NULL, 0)); + + SECStatus rv = PK11_GenerateRandom(rnd1.data(), rnd1.size()); + EXPECT_EQ(rv, SECSuccess); + + EXPECT_EQ(SECSuccess, RNG_RandomUpdate(NULL, 0)); + + rv = PK11_GenerateRandom(rnd2.data(), rnd2.size()); + EXPECT_EQ(rv, SECSuccess); + + EXPECT_EQ(rnd1, rnd2); +} + +// Test that the RNG's internal state progresses in a consistent manner. +TEST_F(PK11PrngTest, Fuzz_DetPRNG_StatefulReset) { + std::vector<uint8_t> rnd1(2048, 0); + std::vector<uint8_t> rnd2(2048, 0); + + EXPECT_EQ(SECSuccess, RNG_RandomUpdate(NULL, 0)); + + SECStatus rv = PK11_GenerateRandom(rnd1.data(), rnd1.size() - 1024); + EXPECT_EQ(rv, SECSuccess); + + rv = PK11_GenerateRandom(rnd1.data() + 1024, rnd1.size() - 1024); + EXPECT_EQ(rv, SECSuccess); + + EXPECT_EQ(SECSuccess, RNG_RandomUpdate(NULL, 0)); + + rv = PK11_GenerateRandom(rnd2.data(), rnd2.size() - 1024); + EXPECT_EQ(rv, SECSuccess); + + rv = PK11_GenerateRandom(rnd2.data() + 1024, rnd2.size() - 1024); + EXPECT_EQ(rv, SECSuccess); + + EXPECT_EQ(rnd1, rnd2); +} + +TEST_F(PK11PrngTest, Fuzz_DetPRNG_Seed) { + std::vector<uint8_t> rnd1(2048, 0); + std::vector<uint8_t> rnd2(2048, 0); + std::vector<uint8_t> seed = {0x01, 0x22, 0xAA, 0x45}; + + SECStatus rv = PK11_RandomUpdate(seed.data(), seed.size()); + EXPECT_EQ(rv, SECSuccess); + + rv = PK11_GenerateRandom(rnd1.data(), rnd1.size()); + EXPECT_EQ(rv, SECSuccess); + + rv = PK11_GenerateRandom(rnd2.data(), rnd2.size()); + EXPECT_EQ(rv, SECSuccess); + + EXPECT_NE(rnd1, rnd2); +} + +TEST_F(PK11PrngTest, Fuzz_DetPRNG_StatefulReset_Seed) { + std::vector<uint8_t> rnd1(2048, 0); + std::vector<uint8_t> rnd2(2048, 0); + std::vector<uint8_t> seed = {0x01, 0x22, 0xAA, 0x45}; + + SECStatus rv = PK11_RandomUpdate(seed.data(), seed.size()); + EXPECT_EQ(rv, SECSuccess); + + rv = PK11_GenerateRandom(rnd1.data(), rnd1.size() - 1024); + EXPECT_EQ(rv, SECSuccess); + + rv = PK11_GenerateRandom(rnd1.data() + 1024, rnd1.size() - 1024); + EXPECT_EQ(rv, SECSuccess); + + rv = PK11_RandomUpdate(seed.data(), seed.size()); + EXPECT_EQ(rv, SECSuccess); + + rv = PK11_GenerateRandom(rnd2.data(), rnd2.size() - 1024); + EXPECT_EQ(rv, SECSuccess); + + rv = PK11_GenerateRandom(rnd2.data() + 1024, rnd2.size() - 1024); + EXPECT_EQ(rv, SECSuccess); + + EXPECT_EQ(rnd1, rnd2); +} + +#endif + +} // namespace nss_test diff --git a/security/nss/gtests/pk11_gtest/pk11_rsaencrypt_unittest.cc b/security/nss/gtests/pk11_gtest/pk11_rsaencrypt_unittest.cc new file mode 100644 index 0000000000..1b312027f3 --- /dev/null +++ b/security/nss/gtests/pk11_gtest/pk11_rsaencrypt_unittest.cc @@ -0,0 +1,130 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include <stdint.h> + +#include "cpputil.h" +#include "cryptohi.h" +#include "gtest/gtest.h" +#include "limits.h" +#include "nss.h" +#include "nss_scoped_ptrs.h" +#include "pk11pub.h" +#include "databuffer.h" + +#include "testvectors/rsa_pkcs1_2048_test-vectors.h" +#include "testvectors/rsa_pkcs1_3072_test-vectors.h" +#include "testvectors/rsa_pkcs1_4096_test-vectors.h" + +namespace nss_test { + +class RsaDecryptWycheproofTest + : public ::testing::TestWithParam<RsaDecryptTestVector> { + protected: + void TestDecrypt(const RsaDecryptTestVector vec) { + SECItem pkcs8_item = {siBuffer, toUcharPtr(vec.priv_key.data()), + static_cast<unsigned int>(vec.priv_key.size())}; + + ScopedPK11SlotInfo slot(PK11_GetInternalKeySlot()); + EXPECT_NE(nullptr, slot); + + SECKEYPrivateKey* key = nullptr; + SECStatus rv = PK11_ImportDERPrivateKeyInfoAndReturnKey( + slot.get(), &pkcs8_item, nullptr, nullptr, false, false, KU_ALL, &key, + nullptr); + ASSERT_EQ(SECSuccess, rv); + ASSERT_NE(nullptr, key); + ScopedSECKEYPrivateKey priv_key(key); + + // Decrypt + std::vector<uint8_t> decrypted(PR_MAX(1, vec.ct.size())); + unsigned int decrypted_len = 0; + rv = PK11_PrivDecryptPKCS1(priv_key.get(), decrypted.data(), &decrypted_len, + decrypted.size(), vec.ct.data(), vec.ct.size()); + + if (vec.valid) { + EXPECT_EQ(SECSuccess, rv); + decrypted.resize(decrypted_len); + EXPECT_EQ(vec.msg, decrypted); + } else { + DataBuffer::SetLogLimit(512); + decrypted.resize(decrypted_len); + EXPECT_EQ(SECFailure, rv) + << "Returned:" << DataBuffer(decrypted.data(), decrypted.size()); + } + }; +}; + +TEST_P(RsaDecryptWycheproofTest, Pkcs1Decrypt) { TestDecrypt(GetParam()); } + +INSTANTIATE_TEST_SUITE_P(WycheproofRsa2048DecryptTest, RsaDecryptWycheproofTest, + ::testing::ValuesIn(kRsa2048DecryptWycheproofVectors)); + +INSTANTIATE_TEST_SUITE_P(WycheproofRsa3072DecryptTest, RsaDecryptWycheproofTest, + ::testing::ValuesIn(kRsa3072DecryptWycheproofVectors)); + +INSTANTIATE_TEST_SUITE_P(WycheproofRsa4096DecryptTest, RsaDecryptWycheproofTest, + ::testing::ValuesIn(kRsa4096DecryptWycheproofVectors)); + +TEST(RsaEncryptTest, MessageLengths) { + const uint8_t spki[] = { + 0x30, 0x81, 0x9f, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, + 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x81, 0x8d, 0x00, 0x30, 0x81, + 0x89, 0x02, 0x81, 0x81, 0x00, 0xf8, 0xb8, 0x6c, 0x83, 0xb4, 0xbc, 0xd9, + 0xa8, 0x57, 0xc0, 0xa5, 0xb4, 0x59, 0x76, 0x8c, 0x54, 0x1d, 0x79, 0xeb, + 0x22, 0x52, 0x04, 0x7e, 0xd3, 0x37, 0xeb, 0x41, 0xfd, 0x83, 0xf9, 0xf0, + 0xa6, 0x85, 0x15, 0x34, 0x75, 0x71, 0x5a, 0x84, 0xa8, 0x3c, 0xd2, 0xef, + 0x5a, 0x4e, 0xd3, 0xde, 0x97, 0x8a, 0xdd, 0xff, 0xbb, 0xcf, 0x0a, 0xaa, + 0x86, 0x92, 0xbe, 0xb8, 0x50, 0xe4, 0xcd, 0x6f, 0x80, 0x33, 0x30, 0x76, + 0x13, 0x8f, 0xca, 0x7b, 0xdc, 0xec, 0x5a, 0xca, 0x63, 0xc7, 0x03, 0x25, + 0xef, 0xa8, 0x8a, 0x83, 0x58, 0x76, 0x20, 0xfa, 0x16, 0x77, 0xd7, 0x79, + 0x92, 0x63, 0x01, 0x48, 0x1a, 0xd8, 0x7b, 0x67, 0xf1, 0x52, 0x55, 0x49, + 0x4e, 0xd6, 0x6e, 0x4a, 0x5c, 0xd7, 0x7a, 0x37, 0x36, 0x0c, 0xde, 0xdd, + 0x8f, 0x44, 0xe8, 0xc2, 0xa7, 0x2c, 0x2b, 0xb5, 0xaf, 0x64, 0x4b, 0x61, + 0x07, 0x02, 0x03, 0x01, 0x00, 0x01, + }; + + // Import public key (use pre-generated for performance). + SECItem spki_item = {siBuffer, toUcharPtr(spki), sizeof(spki)}; + ScopedCERTSubjectPublicKeyInfo cert_spki( + SECKEY_DecodeDERSubjectPublicKeyInfo(&spki_item)); + ASSERT_TRUE(cert_spki); + ScopedSECKEYPublicKey pub_key(SECKEY_ExtractPublicKey(cert_spki.get())); + ASSERT_TRUE(pub_key); + + int mod_len = SECKEY_PublicKeyStrength(pub_key.get()); + ASSERT_TRUE(mod_len > 0); + + std::vector<uint8_t> ctxt(mod_len); + unsigned int ctxt_len; + std::vector<uint8_t> msg(mod_len, 0xff); + + // Test with valid inputs + SECStatus rv = + PK11_PubEncrypt(pub_key.get(), CKM_RSA_PKCS, nullptr, ctxt.data(), + &ctxt_len, mod_len, msg.data(), 1, nullptr); + ASSERT_EQ(SECSuccess, rv); + + // Maximum message length is mod_len - miniumum padding (8B) - flags (3B) + unsigned int max_msg_len = mod_len - 8 - 3; + rv = PK11_PubEncrypt(pub_key.get(), CKM_RSA_PKCS, nullptr, ctxt.data(), + &ctxt_len, mod_len, msg.data(), max_msg_len, nullptr); + ASSERT_EQ(SECSuccess, rv); + + // Test one past maximum length + rv = + PK11_PubEncrypt(pub_key.get(), CKM_RSA_PKCS, nullptr, ctxt.data(), + &ctxt_len, mod_len, msg.data(), max_msg_len + 1, nullptr); + ASSERT_EQ(SECFailure, rv); + + // Make sure the the length will not overflow - i.e. + // (padLen = modulusLen - (UINT_MAX + MINIMUM_PAD_LEN)) may overflow and + // result in a value that appears valid. + rv = PK11_PubEncrypt(pub_key.get(), CKM_RSA_PKCS, nullptr, ctxt.data(), + &ctxt_len, UINT_MAX, msg.data(), UINT_MAX, nullptr); + ASSERT_EQ(SECFailure, rv); +} +} // namespace nss_test diff --git a/security/nss/gtests/pk11_gtest/pk11_rsaoaep_unittest.cc b/security/nss/gtests/pk11_gtest/pk11_rsaoaep_unittest.cc new file mode 100644 index 0000000000..82f3f9fb89 --- /dev/null +++ b/security/nss/gtests/pk11_gtest/pk11_rsaoaep_unittest.cc @@ -0,0 +1,203 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include <stdint.h> + +#include "cpputil.h" +#include "cryptohi.h" +#include "gtest/gtest.h" +#include "limits.h" +#include "nss.h" +#include "nss_scoped_ptrs.h" +#include "pk11pub.h" + +#include "testvectors/rsa_oaep_2048_sha1_mgf1sha1-vectors.h" +#include "testvectors/rsa_oaep_2048_sha256_mgf1sha1-vectors.h" +#include "testvectors/rsa_oaep_2048_sha256_mgf1sha256-vectors.h" +#include "testvectors/rsa_oaep_2048_sha384_mgf1sha1-vectors.h" +#include "testvectors/rsa_oaep_2048_sha384_mgf1sha384-vectors.h" +#include "testvectors/rsa_oaep_2048_sha512_mgf1sha1-vectors.h" +#include "testvectors/rsa_oaep_2048_sha512_mgf1sha512-vectors.h" + +namespace nss_test { + +class RsaOaepWycheproofTest + : public ::testing::TestWithParam<RsaOaepTestVectorStr> { + protected: + void TestDecrypt(const RsaOaepTestVectorStr vec) { + SECItem pkcs8_item = {siBuffer, toUcharPtr(vec.priv_key.data()), + static_cast<unsigned int>(vec.priv_key.size())}; + + ScopedPK11SlotInfo slot(PK11_GetInternalKeySlot()); + EXPECT_NE(nullptr, slot); + + SECKEYPrivateKey* key = nullptr; + SECStatus rv = PK11_ImportDERPrivateKeyInfoAndReturnKey( + slot.get(), &pkcs8_item, nullptr, nullptr, false, false, KU_ALL, &key, + nullptr); + ASSERT_EQ(SECSuccess, rv); + ASSERT_NE(nullptr, key); + ScopedSECKEYPrivateKey priv_key(key); + + // Set up the OAEP parameters. + CK_RSA_PKCS_OAEP_PARAMS oaepParams; + oaepParams.source = CKZ_DATA_SPECIFIED; + oaepParams.pSourceData = const_cast<unsigned char*>(vec.label.data()); + oaepParams.ulSourceDataLen = vec.label.size(); + oaepParams.mgf = vec.mgf_hash; + oaepParams.hashAlg = HashOidToHashMech(vec.hash_oid); + SECItem params_item = {siBuffer, + toUcharPtr(reinterpret_cast<uint8_t*>(&oaepParams)), + static_cast<unsigned int>(sizeof(oaepParams))}; + // Decrypt. + std::vector<uint8_t> decrypted(PR_MAX(1, vec.ct.size())); + unsigned int decrypted_len = 0; + rv = PK11_PrivDecrypt(priv_key.get(), CKM_RSA_PKCS_OAEP, ¶ms_item, + decrypted.data(), &decrypted_len, decrypted.size(), + vec.ct.data(), vec.ct.size()); + + if (vec.valid) { + EXPECT_EQ(SECSuccess, rv); + decrypted.resize(decrypted_len); + EXPECT_EQ(vec.msg, decrypted); + } else { + EXPECT_EQ(SECFailure, rv); + } + }; + + private: + inline CK_MECHANISM_TYPE HashOidToHashMech(SECOidTag hash_oid) { + switch (hash_oid) { + case SEC_OID_SHA1: + return CKM_SHA_1; + case SEC_OID_SHA224: + return CKM_SHA224; + case SEC_OID_SHA256: + return CKM_SHA256; + case SEC_OID_SHA384: + return CKM_SHA384; + case SEC_OID_SHA512: + return CKM_SHA512; + default: + ADD_FAILURE(); + } + return CKM_INVALID_MECHANISM; + } +}; + +TEST_P(RsaOaepWycheproofTest, OaepDecrypt) { TestDecrypt(GetParam()); } + +INSTANTIATE_TEST_SUITE_P( + WycheproofRsa2048Sha1OaepTest, RsaOaepWycheproofTest, + ::testing::ValuesIn(kRsaOaep2048Sha1WycheproofVectors)); + +INSTANTIATE_TEST_SUITE_P( + WycheproofOaep2048Sha256Sha1Test, RsaOaepWycheproofTest, + ::testing::ValuesIn(kRsaOaep2048Sha256Mgf1Sha1WycheproofVectors)); + +INSTANTIATE_TEST_SUITE_P( + WycheproofOaep2048Sha256Sha256Test, RsaOaepWycheproofTest, + ::testing::ValuesIn(kRsaOaep2048Sha256Mgf1Sha256WycheproofVectors)); + +INSTANTIATE_TEST_SUITE_P( + WycheproofOaep2048Sha384Sha1Test, RsaOaepWycheproofTest, + ::testing::ValuesIn(kRsaOaep2048Sha384Mgf1Sha1WycheproofVectors)); + +INSTANTIATE_TEST_SUITE_P( + WycheproofOaep2048Sha384Sha384Test, RsaOaepWycheproofTest, + ::testing::ValuesIn(kRsaOaep2048Sha384Mgf1Sha384WycheproofVectors)); + +INSTANTIATE_TEST_SUITE_P( + WycheproofOaep2048Sha512Sha1Test, RsaOaepWycheproofTest, + ::testing::ValuesIn(kRsaOaep2048Sha512Mgf1Sha1WycheproofVectors)); + +INSTANTIATE_TEST_SUITE_P( + WycheproofOaep2048Sha512Sha512Test, RsaOaepWycheproofTest, + ::testing::ValuesIn(kRsaOaep2048Sha512Mgf1Sha512WycheproofVectors)); + +TEST(Pkcs11RsaOaepTest, TestOaepWrapUnwrap) { + const size_t kRsaKeyBits = 2048; + const size_t kwrappedBufLen = 4096; + + SECStatus rv = SECFailure; + + ScopedSECKEYPrivateKey priv; + ScopedSECKEYPublicKey pub; + PK11RSAGenParams rsa_params; + rsa_params.keySizeInBits = kRsaKeyBits; + rsa_params.pe = 65537; + + ScopedPK11SlotInfo slot(PK11_GetInternalSlot()); + ASSERT_NE(slot, nullptr); + + SECKEYPublicKey* p_pub_tmp = nullptr; + priv.reset(PK11_GenerateKeyPair(slot.get(), CKM_RSA_PKCS_KEY_PAIR_GEN, + &rsa_params, &p_pub_tmp, false, false, + nullptr)); + pub.reset(p_pub_tmp); + + ASSERT_NE(priv.get(), nullptr); + ASSERT_NE(pub.get(), nullptr); + + ScopedPK11SymKey to_wrap( + PK11_KeyGen(slot.get(), CKM_AES_CBC, nullptr, 16, nullptr)); + + CK_RSA_PKCS_OAEP_PARAMS oaep_params = {CKM_SHA256, CKG_MGF1_SHA256, + CKZ_DATA_SPECIFIED, NULL, 0}; + + SECItem param = {siBuffer, (unsigned char*)&oaep_params, sizeof(oaep_params)}; + + ScopedSECItem wrapped(SECITEM_AllocItem(nullptr, nullptr, kwrappedBufLen)); + rv = PK11_PubWrapSymKeyWithMechanism(pub.get(), CKM_RSA_PKCS_OAEP, ¶m, + to_wrap.get(), wrapped.get()); + ASSERT_EQ(rv, SECSuccess); + + PK11SymKey* p_unwrapped_tmp = nullptr; + + // Extract key's value in order to validate decryption worked. + rv = PK11_ExtractKeyValue(to_wrap.get()); + ASSERT_EQ(rv, SECSuccess); + + // References owned by PKCS#11 layer; no need to scope and free. + SECItem* expectedItem = PK11_GetKeyData(to_wrap.get()); + + // This assumes CKM_RSA_PKCS and doesn't understand OAEP. + // CKM_RSA_PKCS cannot safely return errors, however, as it can lead + // to Bleichenbacher-like attacks. To solve this there's a new definition + // that generates fake key material based on the message and private key. + // This returned key material will not be the key we were expecting, so + // make sure that's the case: + p_unwrapped_tmp = PK11_PubUnwrapSymKey(priv.get(), wrapped.get(), CKM_AES_CBC, + CKA_DECRYPT, 16); + // As long as the wrapped data is the same length as the key + // (which it should be), then CKM_RSA_PKCS should not fail. + ASSERT_NE(p_unwrapped_tmp, nullptr); + ScopedPK11SymKey fakeUnwrapped; + fakeUnwrapped.reset(p_unwrapped_tmp); + rv = PK11_ExtractKeyValue(fakeUnwrapped.get()); + ASSERT_EQ(rv, SECSuccess); + + // References owned by PKCS#11 layer; no need to scope and free. + SECItem* fakeItem = PK11_GetKeyData(fakeUnwrapped.get()); + ASSERT_NE(SECITEM_CompareItem(fakeItem, expectedItem), 0); + + ScopedPK11SymKey unwrapped; + p_unwrapped_tmp = PK11_PubUnwrapSymKeyWithMechanism( + priv.get(), CKM_RSA_PKCS_OAEP, ¶m, wrapped.get(), CKM_AES_CBC, + CKA_DECRYPT, 16); + ASSERT_NE(p_unwrapped_tmp, nullptr); + + unwrapped.reset(p_unwrapped_tmp); + + rv = PK11_ExtractKeyValue(unwrapped.get()); + ASSERT_EQ(rv, SECSuccess); + + // References owned by PKCS#11 layer; no need to scope and free. + SECItem* actualItem = PK11_GetKeyData(unwrapped.get()); + + ASSERT_EQ(SECITEM_CompareItem(actualItem, expectedItem), 0); +} +} // namespace nss_test diff --git a/security/nss/gtests/pk11_gtest/pk11_rsapkcs1_unittest.cc b/security/nss/gtests/pk11_gtest/pk11_rsapkcs1_unittest.cc new file mode 100644 index 0000000000..db31f0dacb --- /dev/null +++ b/security/nss/gtests/pk11_gtest/pk11_rsapkcs1_unittest.cc @@ -0,0 +1,251 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include <stdint.h> +#include <memory> +#include "cryptohi.h" +#include "cpputil.h" +#include "databuffer.h" +#include "gtest/gtest.h" +#include "nss.h" +#include "nss_scoped_ptrs.h" +#include "pk11pub.h" +#include "secerr.h" +#include "sechash.h" + +#include "testvectors/rsa_signature_2048_sha224-vectors.h" +#include "testvectors/rsa_signature_2048_sha256-vectors.h" +#include "testvectors/rsa_signature_2048_sha512-vectors.h" +#include "testvectors/rsa_signature_3072_sha256-vectors.h" +#include "testvectors/rsa_signature_3072_sha384-vectors.h" +#include "testvectors/rsa_signature_3072_sha512-vectors.h" +#include "testvectors/rsa_signature_4096_sha384-vectors.h" +#include "testvectors/rsa_signature_4096_sha512-vectors.h" +#include "testvectors/rsa_signature-vectors.h" + +namespace nss_test { + +class Pkcs11RsaPkcs1WycheproofTest + : public ::testing::TestWithParam<RsaSignatureTestVector> { + protected: + void Derive(const RsaSignatureTestVector vec) { + SECItem spki_item = {siBuffer, toUcharPtr(vec.public_key.data()), + static_cast<unsigned int>(vec.public_key.size())}; + + ScopedCERTSubjectPublicKeyInfo cert_spki( + SECKEY_DecodeDERSubjectPublicKeyInfo(&spki_item)); + ASSERT_TRUE(cert_spki); + + ScopedSECKEYPublicKey pub_key(SECKEY_ExtractPublicKey(cert_spki.get())); + ASSERT_TRUE(pub_key); + + DataBuffer hash; + hash.Allocate(static_cast<size_t>(HASH_ResultLenByOidTag(vec.hash_oid))); + SECStatus rv = PK11_HashBuf(vec.hash_oid, toUcharPtr(hash.data()), + toUcharPtr(vec.msg.data()), vec.msg.size()); + ASSERT_EQ(rv, SECSuccess); + + // Verify. + SECItem hash_item = {siBuffer, toUcharPtr(hash.data()), + static_cast<unsigned int>(hash.len())}; + SECItem sig_item = {siBuffer, toUcharPtr(vec.sig.data()), + static_cast<unsigned int>(vec.sig.size())}; + + rv = VFY_VerifyDigestDirect(&hash_item, pub_key.get(), &sig_item, + SEC_OID_PKCS1_RSA_ENCRYPTION, vec.hash_oid, + nullptr); + EXPECT_EQ(rv, vec.valid ? SECSuccess : SECFailure); + }; +}; + +/* Test that PKCS #1 v1.5 verification requires a minimum of 8B + * of padding, per-RFC3447. The padding formula is + * `pad_len = em_len - t_len - 3`, where em_len is the octet length + * of the RSA modulus and t_len is the length of the `DigestInfo || + * Hash(message)` sequence. For SHA512, t_len is 83. We'll tweak the + * modulus size to test with a pad_len of 8 (valid) and 6 (invalid): + * em_len = `8 + 83 + 3` = `94*8` = 752b + * em_len = `6 + 83 + 3` = `92*8` = 736b + * Use 6 as the invalid value since modLen % 16 must be zero. + */ +TEST(RsaPkcs1Test, Pkcs1MinimumPadding) { + const size_t kRsaShortKeyBits = 736; + const size_t kRsaKeyBits = 752; + static const std::vector<uint8_t> kMsg{'T', 'E', 'S', 'T'}; + static const std::vector<uint8_t> kSha512DigestInfo{ + 0x30, 0x51, 0x30, 0x0D, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, + 0x65, 0x03, 0x04, 0x02, 0x03, 0x05, 0x00, 0x04, 0x40}; + static const std::vector<uint8_t> kMsgSha512{ + 0x7B, 0xFA, 0x95, 0xA6, 0x88, 0x92, 0x4C, 0x47, 0xC7, 0xD2, 0x23, + 0x81, 0xF2, 0x0C, 0xC9, 0x26, 0xF5, 0x24, 0xBE, 0xAC, 0xB1, 0x3F, + 0x84, 0xE2, 0x03, 0xD4, 0xBD, 0x8C, 0xB6, 0xBA, 0x2F, 0xCE, 0x81, + 0xC5, 0x7A, 0x5F, 0x05, 0x9B, 0xF3, 0xD5, 0x09, 0x92, 0x64, 0x87, + 0xBD, 0xE9, 0x25, 0xB3, 0xBC, 0xEE, 0x06, 0x35, 0xE4, 0xF7, 0xBA, + 0xEB, 0xA0, 0x54, 0xE5, 0xDB, 0xA6, 0x96, 0xB2, 0xBF}; + + ScopedSECKEYPrivateKey short_priv, good_priv; + ScopedSECKEYPublicKey short_pub, good_pub; + PK11RSAGenParams rsa_params; + rsa_params.keySizeInBits = kRsaShortKeyBits; + rsa_params.pe = 65537; + + ScopedPK11SlotInfo slot(PK11_GetInternalSlot()); + ASSERT_TRUE(slot); + SECKEYPublicKey* p_pub_tmp = nullptr; + short_priv.reset(PK11_GenerateKeyPair(slot.get(), CKM_RSA_PKCS_KEY_PAIR_GEN, + &rsa_params, &p_pub_tmp, false, false, + nullptr)); + short_pub.reset(p_pub_tmp); + + rsa_params.keySizeInBits = kRsaKeyBits; + good_priv.reset(PK11_GenerateKeyPair(slot.get(), CKM_RSA_PKCS_KEY_PAIR_GEN, + &rsa_params, &p_pub_tmp, false, false, + nullptr)); + good_pub.reset(p_pub_tmp); + + size_t em_len = kRsaShortKeyBits / 8; + size_t t_len = kSha512DigestInfo.size() + kMsgSha512.size(); + size_t pad_len = em_len - t_len - 3; + ASSERT_EQ(6U, pad_len); + + std::vector<uint8_t> invalid_pkcs; + invalid_pkcs.push_back(0x00); + invalid_pkcs.push_back(0x01); + invalid_pkcs.insert(invalid_pkcs.end(), pad_len, 0xff); + invalid_pkcs.insert(invalid_pkcs.end(), 1, 0x00); + invalid_pkcs.insert(invalid_pkcs.end(), kSha512DigestInfo.begin(), + kSha512DigestInfo.end()); + invalid_pkcs.insert(invalid_pkcs.end(), kMsgSha512.begin(), kMsgSha512.end()); + ASSERT_EQ(em_len, invalid_pkcs.size()); + + // Sign it indirectly. Signing functions check for a proper pad_len. + std::vector<uint8_t> sig(em_len); + uint32_t sig_len; + SECStatus rv = + PK11_PubDecryptRaw(short_priv.get(), sig.data(), &sig_len, sig.size(), + invalid_pkcs.data(), invalid_pkcs.size()); + EXPECT_EQ(SECSuccess, rv); + + // Verify it. + DataBuffer hash; + hash.Allocate(static_cast<size_t>(HASH_ResultLenByOidTag(SEC_OID_SHA512))); + rv = PK11_HashBuf(SEC_OID_SHA512, toUcharPtr(hash.data()), + toUcharPtr(kMsg.data()), kMsg.size()); + ASSERT_EQ(rv, SECSuccess); + SECItem hash_item = {siBuffer, toUcharPtr(hash.data()), + static_cast<unsigned int>(hash.len())}; + SECItem sig_item = {siBuffer, toUcharPtr(sig.data()), sig_len}; + rv = VFY_VerifyDigestDirect(&hash_item, short_pub.get(), &sig_item, + SEC_OID_PKCS1_RSA_ENCRYPTION, SEC_OID_SHA512, + nullptr); + EXPECT_EQ(SECFailure, rv); + EXPECT_EQ(SEC_ERROR_BAD_SIGNATURE, PORT_GetError()); + + // Repeat the test with the sufficiently-long key. + em_len = kRsaKeyBits / 8; + t_len = kSha512DigestInfo.size() + kMsgSha512.size(); + pad_len = em_len - t_len - 3; + ASSERT_EQ(8U, pad_len); + + std::vector<uint8_t> valid_pkcs; + valid_pkcs.push_back(0x00); + valid_pkcs.push_back(0x01); + valid_pkcs.insert(valid_pkcs.end(), pad_len, 0xff); + valid_pkcs.insert(valid_pkcs.end(), 1, 0x00); + valid_pkcs.insert(valid_pkcs.end(), kSha512DigestInfo.begin(), + kSha512DigestInfo.end()); + valid_pkcs.insert(valid_pkcs.end(), kMsgSha512.begin(), kMsgSha512.end()); + ASSERT_EQ(em_len, valid_pkcs.size()); + + // Sign it the same way as above (even though we could use sign APIs now). + sig.resize(em_len); + rv = PK11_PubDecryptRaw(good_priv.get(), sig.data(), &sig_len, sig.size(), + valid_pkcs.data(), valid_pkcs.size()); + EXPECT_EQ(SECSuccess, rv); + + // Verify it. + sig_item = {siBuffer, toUcharPtr(sig.data()), sig_len}; + rv = VFY_VerifyDigestDirect(&hash_item, good_pub.get(), &sig_item, + SEC_OID_PKCS1_RSA_ENCRYPTION, SEC_OID_SHA512, + nullptr); + EXPECT_EQ(SECSuccess, rv); +} + +TEST(RsaPkcs1Test, RequireNullParameter) { + // The test vectors may be verified with: + // + // openssl rsautl -keyform der -pubin -inkey spki.bin -in sig.bin | der2ascii + // openssl rsautl -keyform der -pubin -inkey spki.bin -in sig2.bin | der2ascii + + // Import public key. + SECItem spki_item = {siBuffer, toUcharPtr(kSpki), sizeof(kSpki)}; + ScopedCERTSubjectPublicKeyInfo cert_spki( + SECKEY_DecodeDERSubjectPublicKeyInfo(&spki_item)); + ASSERT_TRUE(cert_spki); + ScopedSECKEYPublicKey pub_key(SECKEY_ExtractPublicKey(cert_spki.get())); + ASSERT_TRUE(pub_key); + + SECItem hash = {siBuffer, toUcharPtr(kHash), sizeof(kHash)}; + + // kSignature is a valid signature. + SECItem sig_item = {siBuffer, toUcharPtr(kSignature), sizeof(kSignature)}; + SECStatus rv = VFY_VerifyDigestDirect(&hash, pub_key.get(), &sig_item, + SEC_OID_PKCS1_RSA_ENCRYPTION, + SEC_OID_SHA256, nullptr); + EXPECT_EQ(SECSuccess, rv); + + // kSignatureInvalid is not. + sig_item = {siBuffer, toUcharPtr(kSignatureInvalid), + sizeof(kSignatureInvalid)}; + rv = VFY_VerifyDigestDirect(&hash, pub_key.get(), &sig_item, + SEC_OID_PKCS1_RSA_ENCRYPTION, SEC_OID_SHA256, + nullptr); +#ifdef NSS_PKCS1_AllowMissingParameters + EXPECT_EQ(SECSuccess, rv); +#else + EXPECT_EQ(SECFailure, rv); +#endif +} + +TEST_P(Pkcs11RsaPkcs1WycheproofTest, Verify) { Derive(GetParam()); } + +INSTANTIATE_TEST_SUITE_P( + Wycheproof2048RsaSignatureSha224Test, Pkcs11RsaPkcs1WycheproofTest, + ::testing::ValuesIn(kRsaSignature2048Sha224WycheproofVectors)); + +INSTANTIATE_TEST_SUITE_P( + Wycheproof2048RsaSignatureSha256Test, Pkcs11RsaPkcs1WycheproofTest, + ::testing::ValuesIn(kRsaSignature2048Sha256WycheproofVectors)); + +INSTANTIATE_TEST_SUITE_P( + Wycheproof2048RsaSignatureSha512Test, Pkcs11RsaPkcs1WycheproofTest, + ::testing::ValuesIn(kRsaSignature2048Sha512WycheproofVectors)); + +INSTANTIATE_TEST_SUITE_P( + Wycheproof3072RsaSignatureSha256Test, Pkcs11RsaPkcs1WycheproofTest, + ::testing::ValuesIn(kRsaSignature3072Sha256WycheproofVectors)); + +INSTANTIATE_TEST_SUITE_P( + Wycheproof3072RsaSignatureSha384Test, Pkcs11RsaPkcs1WycheproofTest, + ::testing::ValuesIn(kRsaSignature3072Sha384WycheproofVectors)); + +INSTANTIATE_TEST_SUITE_P( + Wycheproof3072RsaSignatureSha512Test, Pkcs11RsaPkcs1WycheproofTest, + ::testing::ValuesIn(kRsaSignature3072Sha512WycheproofVectors)); + +INSTANTIATE_TEST_SUITE_P( + Wycheproof4096RsaSignatureSha384Test, Pkcs11RsaPkcs1WycheproofTest, + ::testing::ValuesIn(kRsaSignature4096Sha384WycheproofVectors)); + +INSTANTIATE_TEST_SUITE_P( + Wycheproof4096RsaSignatureSha512Test, Pkcs11RsaPkcs1WycheproofTest, + ::testing::ValuesIn(kRsaSignature4096Sha512WycheproofVectors)); + +INSTANTIATE_TEST_SUITE_P(WycheproofRsaSignatureTest, + Pkcs11RsaPkcs1WycheproofTest, + ::testing::ValuesIn(kRsaSignatureWycheproofVectors)); + +} // namespace nss_test diff --git a/security/nss/gtests/pk11_gtest/pk11_rsapss_unittest.cc b/security/nss/gtests/pk11_gtest/pk11_rsapss_unittest.cc new file mode 100644 index 0000000000..06c3ae32a6 --- /dev/null +++ b/security/nss/gtests/pk11_gtest/pk11_rsapss_unittest.cc @@ -0,0 +1,259 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include <memory> +#include "nss.h" +#include "pk11pub.h" +#include "sechash.h" + +#include "cpputil.h" +#include "databuffer.h" + +#include "gtest/gtest.h" +#include "nss_scoped_ptrs.h" + +#include "pk11_signature_test.h" +#include "pk11_rsapss_vectors.h" + +#include "testvectors/rsa_pss_2048_sha256_mgf1_32-vectors.h" +#include "testvectors/rsa_pss_2048_sha1_mgf1_20-vectors.h" +#include "testvectors/rsa_pss_2048_sha256_mgf1_0-vectors.h" +#include "testvectors/rsa_pss_3072_sha256_mgf1_32-vectors.h" +#include "testvectors/rsa_pss_4096_sha256_mgf1_32-vectors.h" +#include "testvectors/rsa_pss_4096_sha512_mgf1_32-vectors.h" +#include "testvectors/rsa_pss_misc-vectors.h" + +namespace nss_test { + +class Pkcs11RsaPssTestWycheproof + : public ::testing::TestWithParam<RsaPssTestVector> { + protected: + void TestPss(const RsaPssTestVector& vec) { + SECItem spki_item = {siBuffer, toUcharPtr(vec.public_key.data()), + static_cast<unsigned int>(vec.public_key.size())}; + + ScopedCERTSubjectPublicKeyInfo cert_spki( + SECKEY_DecodeDERSubjectPublicKeyInfo(&spki_item)); + ASSERT_TRUE(cert_spki); + + ScopedSECKEYPublicKey pub_key(SECKEY_ExtractPublicKey(cert_spki.get())); + ASSERT_TRUE(pub_key); + + DataBuffer hash; + hash.Allocate(static_cast<size_t>(HASH_ResultLenByOidTag(vec.hash_oid))); + SECStatus rv = PK11_HashBuf(vec.hash_oid, toUcharPtr(hash.data()), + toUcharPtr(vec.msg.data()), vec.msg.size()); + ASSERT_EQ(rv, SECSuccess); + + // Verify. + SECItem hash_item = {siBuffer, toUcharPtr(hash.data()), + static_cast<unsigned int>(hash.len())}; + SECItem sig_item = {siBuffer, toUcharPtr(vec.sig.data()), + static_cast<unsigned int>(vec.sig.size())}; + CK_MECHANISM_TYPE hash_mech = 0; + switch (vec.hash_oid) { + case SEC_OID_SHA1: + hash_mech = CKM_SHA_1; + break; + case SEC_OID_SHA224: + hash_mech = CKM_SHA224; + break; + case SEC_OID_SHA256: + hash_mech = CKM_SHA256; + break; + case SEC_OID_SHA384: + hash_mech = CKM_SHA384; + break; + case SEC_OID_SHA512: + hash_mech = CKM_SHA512; + break; + default: + ASSERT_TRUE(hash_mech); + return; + } + + CK_RSA_PKCS_PSS_PARAMS pss_params = {hash_mech, vec.mgf_hash, vec.sLen}; + SECItem params = {siBuffer, reinterpret_cast<unsigned char*>(&pss_params), + sizeof(pss_params)}; + + rv = PK11_VerifyWithMechanism(pub_key.get(), CKM_RSA_PKCS_PSS, ¶ms, + &sig_item, &hash_item, nullptr); + EXPECT_EQ(vec.valid ? SECSuccess : SECFailure, rv); + }; +}; + +class Pkcs11RsaPssTest : public Pk11SignatureTest { + public: + Pkcs11RsaPssTest() : Pk11SignatureTest(CKM_RSA_PKCS_PSS, SEC_OID_SHA1) { + pss_params_.hashAlg = CKM_SHA_1; + pss_params_.mgf = CKG_MGF1_SHA1; + pss_params_.sLen = HASH_ResultLenByOidTag(SEC_OID_SHA1); + + params_.type = siBuffer; + params_.data = reinterpret_cast<unsigned char*>(&pss_params_); + params_.len = sizeof(pss_params_); + } + + protected: + const SECItem* parameters() const { return ¶ms_; } + + private: + CK_RSA_PKCS_PSS_PARAMS pss_params_; + SECItem params_; +}; + +TEST_F(Pkcs11RsaPssTest, GenerateAndSignAndVerify) { + // Sign data with a 1024-bit RSA key, using PSS/SHA-256. + SECOidTag hashOid = SEC_OID_SHA256; + CK_MECHANISM_TYPE hash_mech = CKM_SHA256; + CK_RSA_PKCS_MGF_TYPE mgf = CKG_MGF1_SHA256; + PK11RSAGenParams rsaGenParams = {1024, 0x10001}; + + // Generate RSA key pair. + ScopedPK11SlotInfo slot(PK11_GetInternalSlot()); + SECKEYPublicKey* pub_keyRaw = nullptr; + ScopedSECKEYPrivateKey privKey( + PK11_GenerateKeyPair(slot.get(), CKM_RSA_PKCS_KEY_PAIR_GEN, &rsaGenParams, + &pub_keyRaw, false, false, nullptr)); + ASSERT_TRUE(!!privKey && pub_keyRaw); + ScopedSECKEYPublicKey pub_key(pub_keyRaw); + + // Generate random data to sign. + uint8_t dataBuf[50]; + SECItem data = {siBuffer, dataBuf, sizeof(dataBuf)}; + unsigned int hLen = HASH_ResultLenByOidTag(hashOid); + SECStatus rv = PK11_GenerateRandomOnSlot(slot.get(), data.data, data.len); + EXPECT_EQ(rv, SECSuccess); + + // Allocate memory for the signature. + std::vector<uint8_t> sigBuf(PK11_SignatureLen(privKey.get())); + SECItem sig = {siBuffer, &sigBuf[0], + static_cast<unsigned int>(sigBuf.size())}; + + // Set up PSS parameters. + CK_RSA_PKCS_PSS_PARAMS pss_params = {hash_mech, mgf, hLen}; + SECItem params = {siBuffer, reinterpret_cast<unsigned char*>(&pss_params), + sizeof(pss_params)}; + + // Sign. + rv = PK11_SignWithMechanism(privKey.get(), mechanism(), ¶ms, &sig, &data); + EXPECT_EQ(rv, SECSuccess); + + // Verify. + rv = PK11_VerifyWithMechanism(pub_key.get(), mechanism(), ¶ms, &sig, + &data, nullptr); + EXPECT_EQ(rv, SECSuccess); + + // Verification with modified data must fail. + data.data[0] ^= 0xff; + rv = PK11_VerifyWithMechanism(pub_key.get(), mechanism(), ¶ms, &sig, + &data, nullptr); + EXPECT_EQ(rv, SECFailure); + + // Verification with original data but the wrong signature must fail. + data.data[0] ^= 0xff; // Revert previous changes. + sig.data[0] ^= 0xff; + rv = PK11_VerifyWithMechanism(pub_key.get(), mechanism(), ¶ms, &sig, + &data, nullptr); + EXPECT_EQ(rv, SECFailure); +} + +TEST_F(Pkcs11RsaPssTest, NoLeakWithInvalidExponent) { + // Attempt to generate an RSA key with a public exponent of 1. This should + // fail, but it shouldn't leak memory. + PK11RSAGenParams rsaGenParams = {1024, 0x01}; + + // Generate RSA key pair. + ScopedPK11SlotInfo slot(PK11_GetInternalSlot()); + SECKEYPublicKey* pub_key = nullptr; + SECKEYPrivateKey* privKey = + PK11_GenerateKeyPair(slot.get(), CKM_RSA_PKCS_KEY_PAIR_GEN, &rsaGenParams, + &pub_key, false, false, nullptr); + EXPECT_FALSE(privKey); + EXPECT_FALSE(pub_key); +} +class Pkcs11RsaPssVectorTest + : public Pkcs11RsaPssTest, + public ::testing::WithParamInterface<Pkcs11SignatureTestParams> {}; + +TEST_P(Pkcs11RsaPssVectorTest, Verify) { Verify(GetParam()); } + +TEST_P(Pkcs11RsaPssVectorTest, SignAndVerify) { SignAndVerify(GetParam()); } + +#define VECTOR(pkcs8, spki, data, sig) \ + { \ + DataBuffer(pkcs8, sizeof(pkcs8)), DataBuffer(spki, sizeof(spki)), \ + DataBuffer(data, sizeof(data)), DataBuffer(sig, sizeof(sig)) \ + } +#define VECTOR_N(n) \ + VECTOR(kTestVector##n##Pkcs8, kTestVector##n##Spki, kTestVector##n##Data, \ + kTestVector##n##Sig) + +static const Pkcs11SignatureTestParams kRsaPssVectors[] = { + // RSA-PSS test vectors, pss-vect.txt, Example 1.1: A 1024-bit RSA Key Pair + // <ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-1/pkcs-1v2-1-vec.zip> + VECTOR_N(1), + // RSA-PSS test vectors, pss-vect.txt, Example 2.1: A 1025-bit RSA Key Pair + // <ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-1/pkcs-1v2-1-vec.zip> + VECTOR_N(2), + // RSA-PSS test vectors, pss-vect.txt, Example 3.1: A 1026-bit RSA Key Pair + // <ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-1/pkcs-1v2-1-vec.zip> + VECTOR_N(3), + // RSA-PSS test vectors, pss-vect.txt, Example 4.1: A 1027-bit RSA Key Pair + // <ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-1/pkcs-1v2-1-vec.zip> + VECTOR_N(4), + // RSA-PSS test vectors, pss-vect.txt, Example 5.1: A 1028-bit RSA Key Pair + // <ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-1/pkcs-1v2-1-vec.zip> + VECTOR_N(5), + // RSA-PSS test vectors, pss-vect.txt, Example 6.1: A 1029-bit RSA Key Pair + // <ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-1/pkcs-1v2-1-vec.zip> + VECTOR_N(6), + // RSA-PSS test vectors, pss-vect.txt, Example 7.1: A 1030-bit RSA Key Pair + // <ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-1/pkcs-1v2-1-vec.zip> + VECTOR_N(7), + // RSA-PSS test vectors, pss-vect.txt, Example 8.1: A 1031-bit RSA Key Pair + // <ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-1/pkcs-1v2-1-vec.zip> + VECTOR_N(8), + // RSA-PSS test vectors, pss-vect.txt, Example 9.1: A 1536-bit RSA Key Pair + // <ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-1/pkcs-1v2-1-vec.zip> + VECTOR_N(9), + // RSA-PSS test vectors, pss-vect.txt, Example 10.1: A 2048-bit RSA Key Pair + // <ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-1/pkcs-1v2-1-vec.zip> + VECTOR_N(10)}; + +INSTANTIATE_TEST_SUITE_P(RsaPssSignVerify, Pkcs11RsaPssVectorTest, + ::testing::ValuesIn(kRsaPssVectors)); + +TEST_P(Pkcs11RsaPssTestWycheproof, Verify) { TestPss(GetParam()); } + +INSTANTIATE_TEST_SUITE_P( + Wycheproof2048RsaPssSha120Test, Pkcs11RsaPssTestWycheproof, + ::testing::ValuesIn(kRsaPss2048Sha120WycheproofVectors)); + +INSTANTIATE_TEST_SUITE_P( + Wycheproof2048RsaPssSha25632Test, Pkcs11RsaPssTestWycheproof, + ::testing::ValuesIn(kRsaPss2048Sha25632WycheproofVectors)); + +INSTANTIATE_TEST_SUITE_P( + Wycheproof2048RsaPssSha2560Test, Pkcs11RsaPssTestWycheproof, + ::testing::ValuesIn(kRsaPss2048Sha2560WycheproofVectors)); + +INSTANTIATE_TEST_SUITE_P( + Wycheproof3072RsaPssSha25632Test, Pkcs11RsaPssTestWycheproof, + ::testing::ValuesIn(kRsaPss3072Sha25632WycheproofVectors)); + +INSTANTIATE_TEST_SUITE_P( + Wycheproof4096RsaPssSha25632Test, Pkcs11RsaPssTestWycheproof, + ::testing::ValuesIn(kRsaPss4096Sha25632WycheproofVectors)); + +INSTANTIATE_TEST_SUITE_P( + Wycheproof4096RsaPssSha51232Test, Pkcs11RsaPssTestWycheproof, + ::testing::ValuesIn(kRsaPss4096Sha51232WycheproofVectors)); + +INSTANTIATE_TEST_SUITE_P(WycheproofRsaPssMiscTest, Pkcs11RsaPssTestWycheproof, + ::testing::ValuesIn(kRsaPssMiscWycheproofVectors)); + +} // namespace nss_test diff --git a/security/nss/gtests/pk11_gtest/pk11_rsapss_vectors.h b/security/nss/gtests/pk11_gtest/pk11_rsapss_vectors.h new file mode 100644 index 0000000000..2af1044598 --- /dev/null +++ b/security/nss/gtests/pk11_gtest/pk11_rsapss_vectors.h @@ -0,0 +1,1083 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +namespace nss_test { + +// RSA-PSS test vectors, pss-vect.txt, Example 1: A 1024-bit RSA Key Pair +// <ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-1/pkcs-1v2-1-vec.zip> +const uint8_t kTestVector1Pkcs8[] = { + 0x30, 0x82, 0x02, 0x72, 0x02, 0x01, 0x00, 0x30, 0x0d, 0x06, 0x09, 0x2a, + 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x04, 0x82, + 0x02, 0x5c, 0x30, 0x82, 0x02, 0x58, 0x02, 0x01, 0x00, 0x02, 0x81, 0x80, + 0xa5, 0x6e, 0x4a, 0x0e, 0x70, 0x10, 0x17, 0x58, 0x9a, 0x51, 0x87, 0xdc, + 0x7e, 0xa8, 0x41, 0xd1, 0x56, 0xf2, 0xec, 0x0e, 0x36, 0xad, 0x52, 0xa4, + 0x4d, 0xfe, 0xb1, 0xe6, 0x1f, 0x7a, 0xd9, 0x91, 0xd8, 0xc5, 0x10, 0x56, + 0xff, 0xed, 0xb1, 0x62, 0xb4, 0xc0, 0xf2, 0x83, 0xa1, 0x2a, 0x88, 0xa3, + 0x94, 0xdf, 0xf5, 0x26, 0xab, 0x72, 0x91, 0xcb, 0xb3, 0x07, 0xce, 0xab, + 0xfc, 0xe0, 0xb1, 0xdf, 0xd5, 0xcd, 0x95, 0x08, 0x09, 0x6d, 0x5b, 0x2b, + 0x8b, 0x6d, 0xf5, 0xd6, 0x71, 0xef, 0x63, 0x77, 0xc0, 0x92, 0x1c, 0xb2, + 0x3c, 0x27, 0x0a, 0x70, 0xe2, 0x59, 0x8e, 0x6f, 0xf8, 0x9d, 0x19, 0xf1, + 0x05, 0xac, 0xc2, 0xd3, 0xf0, 0xcb, 0x35, 0xf2, 0x92, 0x80, 0xe1, 0x38, + 0x6b, 0x6f, 0x64, 0xc4, 0xef, 0x22, 0xe1, 0xe1, 0xf2, 0x0d, 0x0c, 0xe8, + 0xcf, 0xfb, 0x22, 0x49, 0xbd, 0x9a, 0x21, 0x37, 0x02, 0x03, 0x01, 0x00, + 0x01, 0x02, 0x81, 0x80, 0x33, 0xa5, 0x04, 0x2a, 0x90, 0xb2, 0x7d, 0x4f, + 0x54, 0x51, 0xca, 0x9b, 0xbb, 0xd0, 0xb4, 0x47, 0x71, 0xa1, 0x01, 0xaf, + 0x88, 0x43, 0x40, 0xae, 0xf9, 0x88, 0x5f, 0x2a, 0x4b, 0xbe, 0x92, 0xe8, + 0x94, 0xa7, 0x24, 0xac, 0x3c, 0x56, 0x8c, 0x8f, 0x97, 0x85, 0x3a, 0xd0, + 0x7c, 0x02, 0x66, 0xc8, 0xc6, 0xa3, 0xca, 0x09, 0x29, 0xf1, 0xe8, 0xf1, + 0x12, 0x31, 0x88, 0x44, 0x29, 0xfc, 0x4d, 0x9a, 0xe5, 0x5f, 0xee, 0x89, + 0x6a, 0x10, 0xce, 0x70, 0x7c, 0x3e, 0xd7, 0xe7, 0x34, 0xe4, 0x47, 0x27, + 0xa3, 0x95, 0x74, 0x50, 0x1a, 0x53, 0x26, 0x83, 0x10, 0x9c, 0x2a, 0xba, + 0xca, 0xba, 0x28, 0x3c, 0x31, 0xb4, 0xbd, 0x2f, 0x53, 0xc3, 0xee, 0x37, + 0xe3, 0x52, 0xce, 0xe3, 0x4f, 0x9e, 0x50, 0x3b, 0xd8, 0x0c, 0x06, 0x22, + 0xad, 0x79, 0xc6, 0xdc, 0xee, 0x88, 0x35, 0x47, 0xc6, 0xa3, 0xb3, 0x25, + 0x02, 0x40, 0xe7, 0xe8, 0x94, 0x27, 0x20, 0xa8, 0x77, 0x51, 0x72, 0x73, + 0xa3, 0x56, 0x05, 0x3e, 0xa2, 0xa1, 0xbc, 0x0c, 0x94, 0xaa, 0x72, 0xd5, + 0x5c, 0x6e, 0x86, 0x29, 0x6b, 0x2d, 0xfc, 0x96, 0x79, 0x48, 0xc0, 0xa7, + 0x2c, 0xbc, 0xcc, 0xa7, 0xea, 0xcb, 0x35, 0x70, 0x6e, 0x09, 0xa1, 0xdf, + 0x55, 0xa1, 0x53, 0x5b, 0xd9, 0xb3, 0xcc, 0x34, 0x16, 0x0b, 0x3b, 0x6d, + 0xcd, 0x3e, 0xda, 0x8e, 0x64, 0x43, 0x02, 0x40, 0xb6, 0x9d, 0xca, 0x1c, + 0xf7, 0xd4, 0xd7, 0xec, 0x81, 0xe7, 0x5b, 0x90, 0xfc, 0xca, 0x87, 0x4a, + 0xbc, 0xde, 0x12, 0x3f, 0xd2, 0x70, 0x01, 0x80, 0xaa, 0x90, 0x47, 0x9b, + 0x6e, 0x48, 0xde, 0x8d, 0x67, 0xed, 0x24, 0xf9, 0xf1, 0x9d, 0x85, 0xba, + 0x27, 0x58, 0x74, 0xf5, 0x42, 0xcd, 0x20, 0xdc, 0x72, 0x3e, 0x69, 0x63, + 0x36, 0x4a, 0x1f, 0x94, 0x25, 0x45, 0x2b, 0x26, 0x9a, 0x67, 0x99, 0xfd, + 0x02, 0x40, 0x28, 0xfa, 0x13, 0x93, 0x86, 0x55, 0xbe, 0x1f, 0x8a, 0x15, + 0x9c, 0xba, 0xca, 0x5a, 0x72, 0xea, 0x19, 0x0c, 0x30, 0x08, 0x9e, 0x19, + 0xcd, 0x27, 0x4a, 0x55, 0x6f, 0x36, 0xc4, 0xf6, 0xe1, 0x9f, 0x55, 0x4b, + 0x34, 0xc0, 0x77, 0x79, 0x04, 0x27, 0xbb, 0xdd, 0x8d, 0xd3, 0xed, 0xe2, + 0x44, 0x83, 0x28, 0xf3, 0x85, 0xd8, 0x1b, 0x30, 0xe8, 0xe4, 0x3b, 0x2f, + 0xff, 0xa0, 0x27, 0x86, 0x19, 0x79, 0x02, 0x40, 0x1a, 0x8b, 0x38, 0xf3, + 0x98, 0xfa, 0x71, 0x20, 0x49, 0x89, 0x8d, 0x7f, 0xb7, 0x9e, 0xe0, 0xa7, + 0x76, 0x68, 0x79, 0x12, 0x99, 0xcd, 0xfa, 0x09, 0xef, 0xc0, 0xe5, 0x07, + 0xac, 0xb2, 0x1e, 0xd7, 0x43, 0x01, 0xef, 0x5b, 0xfd, 0x48, 0xbe, 0x45, + 0x5e, 0xae, 0xb6, 0xe1, 0x67, 0x82, 0x55, 0x82, 0x75, 0x80, 0xa8, 0xe4, + 0xe8, 0xe1, 0x41, 0x51, 0xd1, 0x51, 0x0a, 0x82, 0xa3, 0xf2, 0xe7, 0x29, + 0x02, 0x40, 0x27, 0x15, 0x6a, 0xba, 0x41, 0x26, 0xd2, 0x4a, 0x81, 0xf3, + 0xa5, 0x28, 0xcb, 0xfb, 0x27, 0xf5, 0x68, 0x86, 0xf8, 0x40, 0xa9, 0xf6, + 0xe8, 0x6e, 0x17, 0xa4, 0x4b, 0x94, 0xfe, 0x93, 0x19, 0x58, 0x4b, 0x8e, + 0x22, 0xfd, 0xde, 0x1e, 0x5a, 0x2e, 0x3b, 0xd8, 0xaa, 0x5b, 0xa8, 0xd8, + 0x58, 0x41, 0x94, 0xeb, 0x21, 0x90, 0xac, 0xf8, 0x32, 0xb8, 0x47, 0xf1, + 0x3a, 0x3d, 0x24, 0xa7, 0x9f, 0x4d}; +const uint8_t kTestVector1Spki[] = { + 0x30, 0x81, 0x9f, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, + 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x81, 0x8d, 0x00, 0x30, 0x81, + 0x89, 0x02, 0x81, 0x81, 0x00, 0xa5, 0x6e, 0x4a, 0x0e, 0x70, 0x10, 0x17, + 0x58, 0x9a, 0x51, 0x87, 0xdc, 0x7e, 0xa8, 0x41, 0xd1, 0x56, 0xf2, 0xec, + 0x0e, 0x36, 0xad, 0x52, 0xa4, 0x4d, 0xfe, 0xb1, 0xe6, 0x1f, 0x7a, 0xd9, + 0x91, 0xd8, 0xc5, 0x10, 0x56, 0xff, 0xed, 0xb1, 0x62, 0xb4, 0xc0, 0xf2, + 0x83, 0xa1, 0x2a, 0x88, 0xa3, 0x94, 0xdf, 0xf5, 0x26, 0xab, 0x72, 0x91, + 0xcb, 0xb3, 0x07, 0xce, 0xab, 0xfc, 0xe0, 0xb1, 0xdf, 0xd5, 0xcd, 0x95, + 0x08, 0x09, 0x6d, 0x5b, 0x2b, 0x8b, 0x6d, 0xf5, 0xd6, 0x71, 0xef, 0x63, + 0x77, 0xc0, 0x92, 0x1c, 0xb2, 0x3c, 0x27, 0x0a, 0x70, 0xe2, 0x59, 0x8e, + 0x6f, 0xf8, 0x9d, 0x19, 0xf1, 0x05, 0xac, 0xc2, 0xd3, 0xf0, 0xcb, 0x35, + 0xf2, 0x92, 0x80, 0xe1, 0x38, 0x6b, 0x6f, 0x64, 0xc4, 0xef, 0x22, 0xe1, + 0xe1, 0xf2, 0x0d, 0x0c, 0xe8, 0xcf, 0xfb, 0x22, 0x49, 0xbd, 0x9a, 0x21, + 0x37, 0x02, 0x03, 0x01, 0x00, 0x01}; +// RSA-PSS test vectors, pss-vect.txt, Example 1.1 +const uint8_t kTestVector1Data[] = { + 0xcd, 0xc8, 0x7d, 0xa2, 0x23, 0xd7, 0x86, 0xdf, 0x3b, 0x45, 0xe0, 0xbb, + 0xbc, 0x72, 0x13, 0x26, 0xd1, 0xee, 0x2a, 0xf8, 0x06, 0xcc, 0x31, 0x54, + 0x75, 0xcc, 0x6f, 0x0d, 0x9c, 0x66, 0xe1, 0xb6, 0x23, 0x71, 0xd4, 0x5c, + 0xe2, 0x39, 0x2e, 0x1a, 0xc9, 0x28, 0x44, 0xc3, 0x10, 0x10, 0x2f, 0x15, + 0x6a, 0x0d, 0x8d, 0x52, 0xc1, 0xf4, 0xc4, 0x0b, 0xa3, 0xaa, 0x65, 0x09, + 0x57, 0x86, 0xcb, 0x76, 0x97, 0x57, 0xa6, 0x56, 0x3b, 0xa9, 0x58, 0xfe, + 0xd0, 0xbc, 0xc9, 0x84, 0xe8, 0xb5, 0x17, 0xa3, 0xd5, 0xf5, 0x15, 0xb2, + 0x3b, 0x8a, 0x41, 0xe7, 0x4a, 0xa8, 0x67, 0x69, 0x3f, 0x90, 0xdf, 0xb0, + 0x61, 0xa6, 0xe8, 0x6d, 0xfa, 0xae, 0xe6, 0x44, 0x72, 0xc0, 0x0e, 0x5f, + 0x20, 0x94, 0x57, 0x29, 0xcb, 0xeb, 0xe7, 0x7f, 0x06, 0xce, 0x78, 0xe0, + 0x8f, 0x40, 0x98, 0xfb, 0xa4, 0x1f, 0x9d, 0x61, 0x93, 0xc0, 0x31, 0x7e, + 0x8b, 0x60, 0xd4, 0xb6, 0x08, 0x4a, 0xcb, 0x42, 0xd2, 0x9e, 0x38, 0x08, + 0xa3, 0xbc, 0x37, 0x2d, 0x85, 0xe3, 0x31, 0x17, 0x0f, 0xcb, 0xf7, 0xcc, + 0x72, 0xd0, 0xb7, 0x1c, 0x29, 0x66, 0x48, 0xb3, 0xa4, 0xd1, 0x0f, 0x41, + 0x62, 0x95, 0xd0, 0x80, 0x7a, 0xa6, 0x25, 0xca, 0xb2, 0x74, 0x4f, 0xd9, + 0xea, 0x8f, 0xd2, 0x23, 0xc4, 0x25, 0x37, 0x02, 0x98, 0x28, 0xbd, 0x16, + 0xbe, 0x02, 0x54, 0x6f, 0x13, 0x0f, 0xd2, 0xe3, 0x3b, 0x93, 0x6d, 0x26, + 0x76, 0xe0, 0x8a, 0xed, 0x1b, 0x73, 0x31, 0x8b, 0x75, 0x0a, 0x01, 0x67, + 0xd0}; +const uint8_t kTestVector1Sig[] = { + 0x90, 0x74, 0x30, 0x8f, 0xb5, 0x98, 0xe9, 0x70, 0x1b, 0x22, 0x94, 0x38, + 0x8e, 0x52, 0xf9, 0x71, 0xfa, 0xac, 0x2b, 0x60, 0xa5, 0x14, 0x5a, 0xf1, + 0x85, 0xdf, 0x52, 0x87, 0xb5, 0xed, 0x28, 0x87, 0xe5, 0x7c, 0xe7, 0xfd, + 0x44, 0xdc, 0x86, 0x34, 0xe4, 0x07, 0xc8, 0xe0, 0xe4, 0x36, 0x0b, 0xc2, + 0x26, 0xf3, 0xec, 0x22, 0x7f, 0x9d, 0x9e, 0x54, 0x63, 0x8e, 0x8d, 0x31, + 0xf5, 0x05, 0x12, 0x15, 0xdf, 0x6e, 0xbb, 0x9c, 0x2f, 0x95, 0x79, 0xaa, + 0x77, 0x59, 0x8a, 0x38, 0xf9, 0x14, 0xb5, 0xb9, 0xc1, 0xbd, 0x83, 0xc4, + 0xe2, 0xf9, 0xf3, 0x82, 0xa0, 0xd0, 0xaa, 0x35, 0x42, 0xff, 0xee, 0x65, + 0x98, 0x4a, 0x60, 0x1b, 0xc6, 0x9e, 0xb2, 0x8d, 0xeb, 0x27, 0xdc, 0xa1, + 0x2c, 0x82, 0xc2, 0xd4, 0xc3, 0xf6, 0x6c, 0xd5, 0x00, 0xf1, 0xff, 0x2b, + 0x99, 0x4d, 0x8a, 0x4e, 0x30, 0xcb, 0xb3, 0x3c}; + +// RSA-PSS test vectors, pss-vect.txt, Example 2: A 1025-bit RSA Key Pair +// <ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-1/pkcs-1v2-1-vec.zip> +const uint8_t kTestVector2Pkcs8[] = { + 0x30, 0x82, 0x02, 0x75, 0x02, 0x01, 0x00, 0x30, 0x0d, 0x06, 0x09, 0x2a, + 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x04, 0x82, + 0x02, 0x5f, 0x30, 0x82, 0x02, 0x5b, 0x02, 0x01, 0x00, 0x02, 0x81, 0x81, + 0x01, 0xd4, 0x0c, 0x1b, 0xcf, 0x97, 0xa6, 0x8a, 0xe7, 0xcd, 0xbd, 0x8a, + 0x7b, 0xf3, 0xe3, 0x4f, 0xa1, 0x9d, 0xcc, 0xa4, 0xef, 0x75, 0xa4, 0x74, + 0x54, 0x37, 0x5f, 0x94, 0x51, 0x4d, 0x88, 0xfe, 0xd0, 0x06, 0xfb, 0x82, + 0x9f, 0x84, 0x19, 0xff, 0x87, 0xd6, 0x31, 0x5d, 0xa6, 0x8a, 0x1f, 0xf3, + 0xa0, 0x93, 0x8e, 0x9a, 0xbb, 0x34, 0x64, 0x01, 0x1c, 0x30, 0x3a, 0xd9, + 0x91, 0x99, 0xcf, 0x0c, 0x7c, 0x7a, 0x8b, 0x47, 0x7d, 0xce, 0x82, 0x9e, + 0x88, 0x44, 0xf6, 0x25, 0xb1, 0x15, 0xe5, 0xe9, 0xc4, 0xa5, 0x9c, 0xf8, + 0xf8, 0x11, 0x3b, 0x68, 0x34, 0x33, 0x6a, 0x2f, 0xd2, 0x68, 0x9b, 0x47, + 0x2c, 0xbb, 0x5e, 0x5c, 0xab, 0xe6, 0x74, 0x35, 0x0c, 0x59, 0xb6, 0xc1, + 0x7e, 0x17, 0x68, 0x74, 0xfb, 0x42, 0xf8, 0xfc, 0x3d, 0x17, 0x6a, 0x01, + 0x7e, 0xdc, 0x61, 0xfd, 0x32, 0x6c, 0x4b, 0x33, 0xc9, 0x02, 0x03, 0x01, + 0x00, 0x01, 0x02, 0x81, 0x80, 0x02, 0x7d, 0x14, 0x7e, 0x46, 0x73, 0x05, + 0x73, 0x77, 0xfd, 0x1e, 0xa2, 0x01, 0x56, 0x57, 0x72, 0x17, 0x6a, 0x7d, + 0xc3, 0x83, 0x58, 0xd3, 0x76, 0x04, 0x56, 0x85, 0xa2, 0xe7, 0x87, 0xc2, + 0x3c, 0x15, 0x57, 0x6b, 0xc1, 0x6b, 0x9f, 0x44, 0x44, 0x02, 0xd6, 0xbf, + 0xc5, 0xd9, 0x8a, 0x3e, 0x88, 0xea, 0x13, 0xef, 0x67, 0xc3, 0x53, 0xec, + 0xa0, 0xc0, 0xdd, 0xba, 0x92, 0x55, 0xbd, 0x7b, 0x8b, 0xb5, 0x0a, 0x64, + 0x4a, 0xfd, 0xfd, 0x1d, 0xd5, 0x16, 0x95, 0xb2, 0x52, 0xd2, 0x2e, 0x73, + 0x18, 0xd1, 0xb6, 0x68, 0x7a, 0x1c, 0x10, 0xff, 0x75, 0x54, 0x5f, 0x3d, + 0xb0, 0xfe, 0x60, 0x2d, 0x5f, 0x2b, 0x7f, 0x29, 0x4e, 0x36, 0x01, 0xea, + 0xb7, 0xb9, 0xd1, 0xce, 0xcd, 0x76, 0x7f, 0x64, 0x69, 0x2e, 0x3e, 0x53, + 0x6c, 0xa2, 0x84, 0x6c, 0xb0, 0xc2, 0xdd, 0x48, 0x6a, 0x39, 0xfa, 0x75, + 0xb1, 0x02, 0x41, 0x01, 0x66, 0x01, 0xe9, 0x26, 0xa0, 0xf8, 0xc9, 0xe2, + 0x6e, 0xca, 0xb7, 0x69, 0xea, 0x65, 0xa5, 0xe7, 0xc5, 0x2c, 0xc9, 0xe0, + 0x80, 0xef, 0x51, 0x94, 0x57, 0xc6, 0x44, 0xda, 0x68, 0x91, 0xc5, 0xa1, + 0x04, 0xd3, 0xea, 0x79, 0x55, 0x92, 0x9a, 0x22, 0xe7, 0xc6, 0x8a, 0x7a, + 0xf9, 0xfc, 0xad, 0x77, 0x7c, 0x3c, 0xcc, 0x2b, 0x9e, 0x3d, 0x36, 0x50, + 0xbc, 0xe4, 0x04, 0x39, 0x9b, 0x7e, 0x59, 0xd1, 0x02, 0x41, 0x01, 0x4e, + 0xaf, 0xa1, 0xd4, 0xd0, 0x18, 0x4d, 0xa7, 0xe3, 0x1f, 0x87, 0x7d, 0x12, + 0x81, 0xdd, 0xda, 0x62, 0x56, 0x64, 0x86, 0x9e, 0x83, 0x79, 0xe6, 0x7a, + 0xd3, 0xb7, 0x5e, 0xae, 0x74, 0xa5, 0x80, 0xe9, 0x82, 0x7a, 0xbd, 0x6e, + 0xb7, 0xa0, 0x02, 0xcb, 0x54, 0x11, 0xf5, 0x26, 0x67, 0x97, 0x76, 0x8f, + 0xb8, 0xe9, 0x5a, 0xe4, 0x0e, 0x3e, 0x8a, 0x01, 0xf3, 0x5f, 0xf8, 0x9e, + 0x56, 0xc0, 0x79, 0x02, 0x40, 0xe2, 0x47, 0xcc, 0xe5, 0x04, 0x93, 0x9b, + 0x8f, 0x0a, 0x36, 0x09, 0x0d, 0xe2, 0x00, 0x93, 0x87, 0x55, 0xe2, 0x44, + 0x4b, 0x29, 0x53, 0x9a, 0x7d, 0xa7, 0xa9, 0x02, 0xf6, 0x05, 0x68, 0x35, + 0xc0, 0xdb, 0x7b, 0x52, 0x55, 0x94, 0x97, 0xcf, 0xe2, 0xc6, 0x1a, 0x80, + 0x86, 0xd0, 0x21, 0x3c, 0x47, 0x2c, 0x78, 0x85, 0x18, 0x00, 0xb1, 0x71, + 0xf6, 0x40, 0x1d, 0xe2, 0xe9, 0xc2, 0x75, 0x6f, 0x31, 0x02, 0x40, 0xb1, + 0x2f, 0xba, 0x75, 0x78, 0x55, 0xe5, 0x86, 0xe4, 0x6f, 0x64, 0xc3, 0x8a, + 0x70, 0xc6, 0x8b, 0x3f, 0x54, 0x8d, 0x93, 0xd7, 0x87, 0xb3, 0x99, 0x99, + 0x9d, 0x4c, 0x8f, 0x0b, 0xbd, 0x25, 0x81, 0xc2, 0x1e, 0x19, 0xed, 0x00, + 0x18, 0xa6, 0xd5, 0xd3, 0xdf, 0x86, 0x42, 0x4b, 0x3a, 0xbc, 0xad, 0x40, + 0x19, 0x9d, 0x31, 0x49, 0x5b, 0x61, 0x30, 0x9f, 0x27, 0xc1, 0xbf, 0x55, + 0xd4, 0x87, 0xc1, 0x02, 0x40, 0x56, 0x4b, 0x1e, 0x1f, 0xa0, 0x03, 0xbd, + 0xa9, 0x1e, 0x89, 0x09, 0x04, 0x25, 0xaa, 0xc0, 0x5b, 0x91, 0xda, 0x9e, + 0xe2, 0x50, 0x61, 0xe7, 0x62, 0x8d, 0x5f, 0x51, 0x30, 0x4a, 0x84, 0x99, + 0x2f, 0xdc, 0x33, 0x76, 0x2b, 0xd3, 0x78, 0xa5, 0x9f, 0x03, 0x0a, 0x33, + 0x4d, 0x53, 0x2b, 0xd0, 0xda, 0xe8, 0xf2, 0x98, 0xea, 0x9e, 0xd8, 0x44, + 0x63, 0x6a, 0xd5, 0xfb, 0x8c, 0xbd, 0xc0, 0x3c, 0xad}; +const uint8_t kTestVector2Spki[] = { + 0x30, 0x81, 0x9f, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, + 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x81, 0x8d, 0x00, 0x30, 0x81, + 0x89, 0x02, 0x81, 0x81, 0x01, 0xd4, 0x0c, 0x1b, 0xcf, 0x97, 0xa6, 0x8a, + 0xe7, 0xcd, 0xbd, 0x8a, 0x7b, 0xf3, 0xe3, 0x4f, 0xa1, 0x9d, 0xcc, 0xa4, + 0xef, 0x75, 0xa4, 0x74, 0x54, 0x37, 0x5f, 0x94, 0x51, 0x4d, 0x88, 0xfe, + 0xd0, 0x06, 0xfb, 0x82, 0x9f, 0x84, 0x19, 0xff, 0x87, 0xd6, 0x31, 0x5d, + 0xa6, 0x8a, 0x1f, 0xf3, 0xa0, 0x93, 0x8e, 0x9a, 0xbb, 0x34, 0x64, 0x01, + 0x1c, 0x30, 0x3a, 0xd9, 0x91, 0x99, 0xcf, 0x0c, 0x7c, 0x7a, 0x8b, 0x47, + 0x7d, 0xce, 0x82, 0x9e, 0x88, 0x44, 0xf6, 0x25, 0xb1, 0x15, 0xe5, 0xe9, + 0xc4, 0xa5, 0x9c, 0xf8, 0xf8, 0x11, 0x3b, 0x68, 0x34, 0x33, 0x6a, 0x2f, + 0xd2, 0x68, 0x9b, 0x47, 0x2c, 0xbb, 0x5e, 0x5c, 0xab, 0xe6, 0x74, 0x35, + 0x0c, 0x59, 0xb6, 0xc1, 0x7e, 0x17, 0x68, 0x74, 0xfb, 0x42, 0xf8, 0xfc, + 0x3d, 0x17, 0x6a, 0x01, 0x7e, 0xdc, 0x61, 0xfd, 0x32, 0x6c, 0x4b, 0x33, + 0xc9, 0x02, 0x03, 0x01, 0x00, 0x01}; +// RSA-PSS test vectors, pss-vect.txt, Example 2.1 +const uint8_t kTestVector2Data[] = { + 0xda, 0xba, 0x03, 0x20, 0x66, 0x26, 0x3f, 0xae, 0xdb, 0x65, 0x98, + 0x48, 0x11, 0x52, 0x78, 0xa5, 0x2c, 0x44, 0xfa, 0xa3, 0xa7, 0x6f, + 0x37, 0x51, 0x5e, 0xd3, 0x36, 0x32, 0x10, 0x72, 0xc4, 0x0a, 0x9d, + 0x9b, 0x53, 0xbc, 0x05, 0x01, 0x40, 0x78, 0xad, 0xf5, 0x20, 0x87, + 0x51, 0x46, 0xaa, 0xe7, 0x0f, 0xf0, 0x60, 0x22, 0x6d, 0xcb, 0x7b, + 0x1f, 0x1f, 0xc2, 0x7e, 0x93, 0x60}; +const uint8_t kTestVector2Sig[] = { + 0x01, 0x4c, 0x5b, 0xa5, 0x33, 0x83, 0x28, 0xcc, 0xc6, 0xe7, 0xa9, 0x0b, + 0xf1, 0xc0, 0xab, 0x3f, 0xd6, 0x06, 0xff, 0x47, 0x96, 0xd3, 0xc1, 0x2e, + 0x4b, 0x63, 0x9e, 0xd9, 0x13, 0x6a, 0x5f, 0xec, 0x6c, 0x16, 0xd8, 0x88, + 0x4b, 0xdd, 0x99, 0xcf, 0xdc, 0x52, 0x14, 0x56, 0xb0, 0x74, 0x2b, 0x73, + 0x68, 0x68, 0xcf, 0x90, 0xde, 0x09, 0x9a, 0xdb, 0x8d, 0x5f, 0xfd, 0x1d, + 0xef, 0xf3, 0x9b, 0xa4, 0x00, 0x7a, 0xb7, 0x46, 0xce, 0xfd, 0xb2, 0x2d, + 0x7d, 0xf0, 0xe2, 0x25, 0xf5, 0x46, 0x27, 0xdc, 0x65, 0x46, 0x61, 0x31, + 0x72, 0x1b, 0x90, 0xaf, 0x44, 0x53, 0x63, 0xa8, 0x35, 0x8b, 0x9f, 0x60, + 0x76, 0x42, 0xf7, 0x8f, 0xab, 0x0a, 0xb0, 0xf4, 0x3b, 0x71, 0x68, 0xd6, + 0x4b, 0xae, 0x70, 0xd8, 0x82, 0x78, 0x48, 0xd8, 0xef, 0x1e, 0x42, 0x1c, + 0x57, 0x54, 0xdd, 0xf4, 0x2c, 0x25, 0x89, 0xb5, 0xb3}; + +// RSA-PSS test vectors, pss-vect.txt, Example 3: A 1026-bit RSA Key Pair +// <ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-1/pkcs-1v2-1-vec.zip> +const uint8_t kTestVector3Pkcs8[] = { + 0x30, 0x82, 0x02, 0x76, 0x02, 0x01, 0x00, 0x30, 0x0d, 0x06, 0x09, 0x2a, + 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x04, 0x82, + 0x02, 0x60, 0x30, 0x82, 0x02, 0x5c, 0x02, 0x01, 0x00, 0x02, 0x81, 0x81, + 0x02, 0xf2, 0x46, 0xef, 0x45, 0x1e, 0xd3, 0xee, 0xbb, 0x9a, 0x31, 0x02, + 0x00, 0xcc, 0x25, 0x85, 0x9c, 0x04, 0x8e, 0x4b, 0xe7, 0x98, 0x30, 0x29, + 0x91, 0x11, 0x2e, 0xb6, 0x8c, 0xe6, 0xdb, 0x67, 0x4e, 0x28, 0x0d, 0xa2, + 0x1f, 0xed, 0xed, 0x1a, 0xe7, 0x48, 0x80, 0xca, 0x52, 0x2b, 0x18, 0xdb, + 0x24, 0x93, 0x85, 0x01, 0x28, 0x27, 0xc5, 0x15, 0xf0, 0xe4, 0x66, 0xa1, + 0xff, 0xa6, 0x91, 0xd9, 0x81, 0x70, 0x57, 0x4e, 0x9d, 0x0e, 0xad, 0xb0, + 0x87, 0x58, 0x6c, 0xa4, 0x89, 0x33, 0xda, 0x3c, 0xc9, 0x53, 0xd9, 0x5b, + 0xd0, 0xed, 0x50, 0xde, 0x10, 0xdd, 0xcb, 0x67, 0x36, 0x10, 0x7d, 0x6c, + 0x83, 0x1c, 0x7f, 0x66, 0x3e, 0x83, 0x3c, 0xa4, 0xc0, 0x97, 0xe7, 0x00, + 0xce, 0x0f, 0xb9, 0x45, 0xf8, 0x8f, 0xb8, 0x5f, 0xe8, 0xe5, 0xa7, 0x73, + 0x17, 0x25, 0x65, 0xb9, 0x14, 0xa4, 0x71, 0xa4, 0x43, 0x02, 0x03, 0x01, + 0x00, 0x01, 0x02, 0x81, 0x80, 0x65, 0x14, 0x51, 0x73, 0x3b, 0x56, 0xde, + 0x5a, 0xc0, 0xa6, 0x89, 0xa4, 0xae, 0xb6, 0xe6, 0x89, 0x4a, 0x69, 0x01, + 0x4e, 0x07, 0x6c, 0x88, 0xdd, 0x7a, 0x66, 0x7e, 0xab, 0x32, 0x32, 0xbb, + 0xcc, 0xd2, 0xfc, 0x44, 0xba, 0x2f, 0xa9, 0xc3, 0x1d, 0xb4, 0x6f, 0x21, + 0xed, 0xd1, 0xfd, 0xb2, 0x3c, 0x5c, 0x12, 0x8a, 0x5d, 0xa5, 0xba, 0xb9, + 0x1e, 0x7f, 0x95, 0x2b, 0x67, 0x75, 0x9c, 0x7c, 0xff, 0x70, 0x54, 0x15, + 0xac, 0x9f, 0xa0, 0x90, 0x7c, 0x7c, 0xa6, 0x17, 0x8f, 0x66, 0x8f, 0xb9, + 0x48, 0xd8, 0x69, 0xda, 0x4c, 0xc3, 0xb7, 0x35, 0x6f, 0x40, 0x08, 0xdf, + 0xd5, 0x44, 0x9d, 0x32, 0xee, 0x02, 0xd9, 0xa4, 0x77, 0xeb, 0x69, 0xfc, + 0x29, 0x26, 0x6e, 0x5d, 0x90, 0x70, 0x51, 0x23, 0x75, 0xa5, 0x0f, 0xbb, + 0xcc, 0x27, 0xe2, 0x38, 0xad, 0x98, 0x42, 0x5f, 0x6e, 0xbb, 0xf8, 0x89, + 0x91, 0x02, 0x41, 0x01, 0xbd, 0x36, 0xe1, 0x8e, 0xce, 0x4b, 0x0f, 0xdb, + 0x2e, 0x9c, 0x9d, 0x54, 0x8b, 0xd1, 0xa7, 0xd6, 0xe2, 0xc2, 0x1c, 0x6f, + 0xdc, 0x35, 0x07, 0x4a, 0x1d, 0x05, 0xb1, 0xc6, 0xc8, 0xb3, 0xd5, 0x58, + 0xea, 0x26, 0x39, 0xc9, 0xa9, 0xa4, 0x21, 0x68, 0x01, 0x69, 0x31, 0x72, + 0x52, 0x55, 0x8b, 0xd1, 0x48, 0xad, 0x21, 0x5a, 0xac, 0x55, 0x0e, 0x2d, + 0xcf, 0x12, 0xa8, 0x2d, 0x0e, 0xbf, 0xe8, 0x53, 0x02, 0x41, 0x01, 0xb1, + 0xb6, 0x56, 0xad, 0x86, 0xd8, 0xe1, 0x9d, 0x5d, 0xc8, 0x62, 0x92, 0xb3, + 0xa1, 0x92, 0xfd, 0xf6, 0xe0, 0xdd, 0x37, 0x87, 0x7b, 0xad, 0x14, 0x82, + 0x2f, 0xa0, 0x01, 0x90, 0xca, 0xb2, 0x65, 0xf9, 0x0d, 0x3f, 0x02, 0x05, + 0x7b, 0x6f, 0x54, 0xd6, 0xec, 0xb1, 0x44, 0x91, 0xe5, 0xad, 0xea, 0xce, + 0xbc, 0x48, 0xbf, 0x0e, 0xbd, 0x2a, 0x2a, 0xd2, 0x6d, 0x40, 0x2e, 0x54, + 0xf6, 0x16, 0x51, 0x02, 0x40, 0x1f, 0x27, 0x79, 0xfd, 0x2e, 0x3e, 0x5e, + 0x6b, 0xae, 0x05, 0x53, 0x95, 0x18, 0xfb, 0xa0, 0xcd, 0x0e, 0xad, 0x1a, + 0xa4, 0x51, 0x3a, 0x7c, 0xba, 0x18, 0xf1, 0xcf, 0x10, 0xe3, 0xf6, 0x81, + 0x95, 0x69, 0x3d, 0x27, 0x8a, 0x0f, 0x0e, 0xe7, 0x2f, 0x89, 0xf9, 0xbc, + 0x76, 0x0d, 0x80, 0xe2, 0xf9, 0xd0, 0x26, 0x1d, 0x51, 0x65, 0x01, 0xc6, + 0xae, 0x39, 0xf1, 0x4a, 0x47, 0x6c, 0xe2, 0xcc, 0xf5, 0x02, 0x41, 0x01, + 0x1a, 0x0d, 0x36, 0x79, 0x4b, 0x04, 0xa8, 0x54, 0xaa, 0xb4, 0xb2, 0x46, + 0x2d, 0x43, 0x9a, 0x50, 0x46, 0xc9, 0x1d, 0x94, 0x0b, 0x2b, 0xc6, 0xf7, + 0x5b, 0x62, 0x95, 0x6f, 0xef, 0x35, 0xa2, 0xa6, 0xe6, 0x3c, 0x53, 0x09, + 0x81, 0x7f, 0x30, 0x7b, 0xbf, 0xf9, 0xd5, 0x9e, 0x7e, 0x33, 0x1b, 0xd3, + 0x63, 0xf6, 0xd6, 0x68, 0x49, 0xb1, 0x83, 0x46, 0xad, 0xea, 0x16, 0x9f, + 0x0a, 0xe9, 0xae, 0xc1, 0x02, 0x40, 0x0b, 0x30, 0xf0, 0xec, 0xf5, 0x58, + 0x75, 0x2f, 0xb3, 0xa6, 0xce, 0x4b, 0xa2, 0xb8, 0xc6, 0x75, 0xf6, 0x59, + 0xeb, 0xa6, 0xc3, 0x76, 0x58, 0x5a, 0x1b, 0x39, 0x71, 0x2d, 0x03, 0x8a, + 0xe3, 0xd2, 0xb4, 0x6f, 0xcb, 0x41, 0x8a, 0xe1, 0x5d, 0x09, 0x05, 0xda, + 0x64, 0x40, 0xe1, 0x51, 0x3a, 0x30, 0xb9, 0xb7, 0xd6, 0x66, 0x8f, 0xbc, + 0x5e, 0x88, 0xe5, 0xab, 0x7a, 0x17, 0x5e, 0x73, 0xba, 0x35}; +const uint8_t kTestVector3Spki[] = { + 0x30, 0x81, 0x9f, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, + 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x81, 0x8d, 0x00, 0x30, 0x81, + 0x89, 0x02, 0x81, 0x81, 0x02, 0xf2, 0x46, 0xef, 0x45, 0x1e, 0xd3, 0xee, + 0xbb, 0x9a, 0x31, 0x02, 0x00, 0xcc, 0x25, 0x85, 0x9c, 0x04, 0x8e, 0x4b, + 0xe7, 0x98, 0x30, 0x29, 0x91, 0x11, 0x2e, 0xb6, 0x8c, 0xe6, 0xdb, 0x67, + 0x4e, 0x28, 0x0d, 0xa2, 0x1f, 0xed, 0xed, 0x1a, 0xe7, 0x48, 0x80, 0xca, + 0x52, 0x2b, 0x18, 0xdb, 0x24, 0x93, 0x85, 0x01, 0x28, 0x27, 0xc5, 0x15, + 0xf0, 0xe4, 0x66, 0xa1, 0xff, 0xa6, 0x91, 0xd9, 0x81, 0x70, 0x57, 0x4e, + 0x9d, 0x0e, 0xad, 0xb0, 0x87, 0x58, 0x6c, 0xa4, 0x89, 0x33, 0xda, 0x3c, + 0xc9, 0x53, 0xd9, 0x5b, 0xd0, 0xed, 0x50, 0xde, 0x10, 0xdd, 0xcb, 0x67, + 0x36, 0x10, 0x7d, 0x6c, 0x83, 0x1c, 0x7f, 0x66, 0x3e, 0x83, 0x3c, 0xa4, + 0xc0, 0x97, 0xe7, 0x00, 0xce, 0x0f, 0xb9, 0x45, 0xf8, 0x8f, 0xb8, 0x5f, + 0xe8, 0xe5, 0xa7, 0x73, 0x17, 0x25, 0x65, 0xb9, 0x14, 0xa4, 0x71, 0xa4, + 0x43, 0x02, 0x03, 0x01, 0x00, 0x01}; +// RSA-PSS test vectors, pss-vect.txt, Example 3.1 +const uint8_t kTestVector3Data[] = { + 0x59, 0x4b, 0x37, 0x33, 0x3b, 0xbb, 0x2c, 0x84, 0x52, 0x4a, + 0x87, 0xc1, 0xa0, 0x1f, 0x75, 0xfc, 0xec, 0x0e, 0x32, 0x56, + 0xf1, 0x08, 0xe3, 0x8d, 0xca, 0x36, 0xd7, 0x0d, 0x00, 0x57}; +const uint8_t kTestVector3Sig[] = { + 0x00, 0x88, 0xb1, 0x35, 0xfb, 0x17, 0x94, 0xb6, 0xb9, 0x6c, 0x4a, 0x3e, + 0x67, 0x81, 0x97, 0xf8, 0xca, 0xc5, 0x2b, 0x64, 0xb2, 0xfe, 0x90, 0x7d, + 0x6f, 0x27, 0xde, 0x76, 0x11, 0x24, 0x96, 0x4a, 0x99, 0xa0, 0x1a, 0x88, + 0x27, 0x40, 0xec, 0xfa, 0xed, 0x6c, 0x01, 0xa4, 0x74, 0x64, 0xbb, 0x05, + 0x18, 0x23, 0x13, 0xc0, 0x13, 0x38, 0xa8, 0xcd, 0x09, 0x72, 0x14, 0xcd, + 0x68, 0xca, 0x10, 0x3b, 0xd5, 0x7d, 0x3b, 0xc9, 0xe8, 0x16, 0x21, 0x3e, + 0x61, 0xd7, 0x84, 0xf1, 0x82, 0x46, 0x7a, 0xbf, 0x8a, 0x01, 0xcf, 0x25, + 0x3e, 0x99, 0xa1, 0x56, 0xea, 0xa8, 0xe3, 0xe1, 0xf9, 0x0e, 0x3c, 0x6e, + 0x4e, 0x3a, 0xa2, 0xd8, 0x3e, 0xd0, 0x34, 0x5b, 0x89, 0xfa, 0xfc, 0x9c, + 0x26, 0x07, 0x7c, 0x14, 0xb6, 0xac, 0x51, 0x45, 0x4f, 0xa2, 0x6e, 0x44, + 0x6e, 0x3a, 0x2f, 0x15, 0x3b, 0x2b, 0x16, 0x79, 0x7f}; + +// RSA-PSS test vectors, pss-vect.txt, Example 4: A 1027-bit RSA Key Pair +// <ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-1/pkcs-1v2-1-vec.zip> +const uint8_t kTestVector4Pkcs8[] = { + 0x30, 0x82, 0x02, 0x78, 0x02, 0x01, 0x00, 0x30, 0x0d, 0x06, 0x09, 0x2a, + 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x04, 0x82, + 0x02, 0x62, 0x30, 0x82, 0x02, 0x5e, 0x02, 0x01, 0x00, 0x02, 0x81, 0x81, + 0x05, 0x4a, 0xdb, 0x78, 0x86, 0x44, 0x7e, 0xfe, 0x6f, 0x57, 0xe0, 0x36, + 0x8f, 0x06, 0xcf, 0x52, 0xb0, 0xa3, 0x37, 0x07, 0x60, 0xd1, 0x61, 0xce, + 0xf1, 0x26, 0xb9, 0x1b, 0xe7, 0xf8, 0x9c, 0x42, 0x1b, 0x62, 0xa6, 0xec, + 0x1d, 0xa3, 0xc3, 0x11, 0xd7, 0x5e, 0xd5, 0x0e, 0x0a, 0xb5, 0xff, 0xf3, + 0xfd, 0x33, 0x8a, 0xcc, 0x3a, 0xa8, 0xa4, 0xe7, 0x7e, 0xe2, 0x63, 0x69, + 0xac, 0xb8, 0x1b, 0xa9, 0x00, 0xfa, 0x83, 0xf5, 0x30, 0x0c, 0xf9, 0xbb, + 0x6c, 0x53, 0xad, 0x1d, 0xc8, 0xa1, 0x78, 0xb8, 0x15, 0xdb, 0x42, 0x35, + 0xa9, 0xa9, 0xda, 0x0c, 0x06, 0xde, 0x4e, 0x61, 0x5e, 0xa1, 0x27, 0x7c, + 0xe5, 0x59, 0xe9, 0xc1, 0x08, 0xde, 0x58, 0xc1, 0x4a, 0x81, 0xaa, 0x77, + 0xf5, 0xa6, 0xf8, 0xd1, 0x33, 0x54, 0x94, 0x49, 0x88, 0x48, 0xc8, 0xb9, + 0x59, 0x40, 0x74, 0x0b, 0xe7, 0xbf, 0x7c, 0x37, 0x05, 0x02, 0x03, 0x01, + 0x00, 0x01, 0x02, 0x81, 0x80, 0xfa, 0x04, 0x1f, 0x8c, 0xd9, 0x69, 0x7c, + 0xee, 0xd3, 0x8e, 0xc8, 0xca, 0xa2, 0x75, 0x52, 0x3b, 0x4d, 0xd7, 0x2b, + 0x09, 0xa3, 0x01, 0xd3, 0x54, 0x1d, 0x72, 0xf5, 0xd3, 0x1c, 0x05, 0xcb, + 0xce, 0x2d, 0x69, 0x83, 0xb3, 0x61, 0x83, 0xaf, 0x10, 0x69, 0x0b, 0xd4, + 0x6c, 0x46, 0x13, 0x1e, 0x35, 0x78, 0x94, 0x31, 0xa5, 0x56, 0x77, 0x1d, + 0xd0, 0x04, 0x9b, 0x57, 0x46, 0x1b, 0xf0, 0x60, 0xc1, 0xf6, 0x84, 0x72, + 0xe8, 0xa6, 0x7c, 0x25, 0xf3, 0x57, 0xe5, 0xb6, 0xb4, 0x73, 0x8f, 0xa5, + 0x41, 0xa7, 0x30, 0x34, 0x6b, 0x4a, 0x07, 0x64, 0x9a, 0x2d, 0xfa, 0x80, + 0x6a, 0x69, 0xc9, 0x75, 0xb6, 0xab, 0xa6, 0x46, 0x78, 0xac, 0xc7, 0xf5, + 0x91, 0x3e, 0x89, 0xc6, 0x22, 0xf2, 0xd8, 0xab, 0xb1, 0xe3, 0xe3, 0x25, + 0x54, 0xe3, 0x9d, 0xf9, 0x4b, 0xa6, 0x0c, 0x00, 0x2e, 0x38, 0x7d, 0x90, + 0x11, 0x02, 0x41, 0x02, 0x92, 0x32, 0x33, 0x6d, 0x28, 0x38, 0x94, 0x5d, + 0xba, 0x9d, 0xd7, 0x72, 0x3f, 0x4e, 0x62, 0x4a, 0x05, 0xf7, 0x37, 0x5b, + 0x92, 0x7a, 0x87, 0xab, 0xe6, 0xa8, 0x93, 0xa1, 0x65, 0x8f, 0xd4, 0x9f, + 0x47, 0xf6, 0xc7, 0xb0, 0xfa, 0x59, 0x6c, 0x65, 0xfa, 0x68, 0xa2, 0x3f, + 0x0a, 0xb4, 0x32, 0x96, 0x2d, 0x18, 0xd4, 0x34, 0x3b, 0xd6, 0xfd, 0x67, + 0x1a, 0x5e, 0xa8, 0xd1, 0x48, 0x41, 0x39, 0x95, 0x02, 0x41, 0x02, 0x0e, + 0xf5, 0xef, 0xe7, 0xc5, 0x39, 0x4a, 0xed, 0x22, 0x72, 0xf7, 0xe8, 0x1a, + 0x74, 0xf4, 0xc0, 0x2d, 0x14, 0x58, 0x94, 0xcb, 0x1b, 0x3c, 0xab, 0x23, + 0xa9, 0xa0, 0x71, 0x0a, 0x2a, 0xfc, 0x7e, 0x33, 0x29, 0xac, 0xbb, 0x74, + 0x3d, 0x01, 0xf6, 0x80, 0xc4, 0xd0, 0x2a, 0xfb, 0x4c, 0x8f, 0xde, 0x7e, + 0x20, 0x93, 0x08, 0x11, 0xbb, 0x2b, 0x99, 0x57, 0x88, 0xb5, 0xe8, 0x72, + 0xc2, 0x0b, 0xb1, 0x02, 0x41, 0x02, 0x6e, 0x7e, 0x28, 0x01, 0x0e, 0xcf, + 0x24, 0x12, 0xd9, 0x52, 0x3a, 0xd7, 0x04, 0x64, 0x7f, 0xb4, 0xfe, 0x9b, + 0x66, 0xb1, 0xa6, 0x81, 0x58, 0x1b, 0x0e, 0x15, 0x55, 0x3a, 0x89, 0xb1, + 0x54, 0x28, 0x28, 0x89, 0x8f, 0x27, 0x24, 0x3e, 0xba, 0xb4, 0x5f, 0xf5, + 0xe1, 0xac, 0xb9, 0xd4, 0xdf, 0x1b, 0x05, 0x1f, 0xbc, 0x62, 0x82, 0x4d, + 0xbc, 0x6f, 0x6c, 0x93, 0x26, 0x1a, 0x78, 0xb9, 0xa7, 0x59, 0x02, 0x41, + 0x01, 0x2d, 0xdc, 0xc8, 0x6e, 0xf6, 0x55, 0x99, 0x8c, 0x39, 0xdd, 0xae, + 0x11, 0x71, 0x86, 0x69, 0xe5, 0xe4, 0x6c, 0xf1, 0x49, 0x5b, 0x07, 0xe1, + 0x3b, 0x10, 0x14, 0xcd, 0x69, 0xb3, 0xaf, 0x68, 0x30, 0x4a, 0xd2, 0xa6, + 0xb6, 0x43, 0x21, 0xe7, 0x8b, 0xf3, 0xbb, 0xca, 0x9b, 0xb4, 0x94, 0xe9, + 0x1d, 0x45, 0x17, 0x17, 0xe2, 0xd9, 0x75, 0x64, 0xc6, 0x54, 0x94, 0x65, + 0xd0, 0x20, 0x5c, 0xf4, 0x21, 0x02, 0x41, 0x01, 0x06, 0x00, 0xc4, 0xc2, + 0x18, 0x47, 0x45, 0x9f, 0xe5, 0x76, 0x70, 0x3e, 0x2e, 0xbe, 0xca, 0xe8, + 0xa5, 0x09, 0x4e, 0xe6, 0x3f, 0x53, 0x6b, 0xf4, 0xac, 0x68, 0xd3, 0xc1, + 0x3e, 0x5e, 0x4f, 0x12, 0xac, 0x5c, 0xc1, 0x0a, 0xb6, 0xa2, 0xd0, 0x5a, + 0x19, 0x92, 0x14, 0xd1, 0x82, 0x47, 0x47, 0xd5, 0x51, 0x90, 0x96, 0x36, + 0xb7, 0x74, 0xc2, 0x2c, 0xac, 0x0b, 0x83, 0x75, 0x99, 0xab, 0xcc, 0x75}; +const uint8_t kTestVector4Spki[] = { + 0x30, 0x81, 0x9f, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, + 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x81, 0x8d, 0x00, 0x30, 0x81, + 0x89, 0x02, 0x81, 0x81, 0x05, 0x4a, 0xdb, 0x78, 0x86, 0x44, 0x7e, 0xfe, + 0x6f, 0x57, 0xe0, 0x36, 0x8f, 0x06, 0xcf, 0x52, 0xb0, 0xa3, 0x37, 0x07, + 0x60, 0xd1, 0x61, 0xce, 0xf1, 0x26, 0xb9, 0x1b, 0xe7, 0xf8, 0x9c, 0x42, + 0x1b, 0x62, 0xa6, 0xec, 0x1d, 0xa3, 0xc3, 0x11, 0xd7, 0x5e, 0xd5, 0x0e, + 0x0a, 0xb5, 0xff, 0xf3, 0xfd, 0x33, 0x8a, 0xcc, 0x3a, 0xa8, 0xa4, 0xe7, + 0x7e, 0xe2, 0x63, 0x69, 0xac, 0xb8, 0x1b, 0xa9, 0x00, 0xfa, 0x83, 0xf5, + 0x30, 0x0c, 0xf9, 0xbb, 0x6c, 0x53, 0xad, 0x1d, 0xc8, 0xa1, 0x78, 0xb8, + 0x15, 0xdb, 0x42, 0x35, 0xa9, 0xa9, 0xda, 0x0c, 0x06, 0xde, 0x4e, 0x61, + 0x5e, 0xa1, 0x27, 0x7c, 0xe5, 0x59, 0xe9, 0xc1, 0x08, 0xde, 0x58, 0xc1, + 0x4a, 0x81, 0xaa, 0x77, 0xf5, 0xa6, 0xf8, 0xd1, 0x33, 0x54, 0x94, 0x49, + 0x88, 0x48, 0xc8, 0xb9, 0x59, 0x40, 0x74, 0x0b, 0xe7, 0xbf, 0x7c, 0x37, + 0x05, 0x02, 0x03, 0x01, 0x00, 0x01}; +// RSA-PSS test vectors, pss-vect.txt, Example 4.1 +const uint8_t kTestVector4Data[] = {0x9f, 0xb0, 0x3b, 0x82, + 0x7c, 0x82, 0x17, 0xd9}; +const uint8_t kTestVector4Sig[] = { + 0x03, 0x23, 0xd5, 0xb7, 0xbf, 0x20, 0xba, 0x45, 0x39, 0x28, 0x9a, 0xe4, + 0x52, 0xae, 0x42, 0x97, 0x08, 0x0f, 0xef, 0xf4, 0x51, 0x84, 0x23, 0xff, + 0x48, 0x11, 0xa8, 0x17, 0x83, 0x7e, 0x7d, 0x82, 0xf1, 0x83, 0x6c, 0xdf, + 0xab, 0x54, 0x51, 0x4f, 0xf0, 0x88, 0x7b, 0xdd, 0xee, 0xbf, 0x40, 0xbf, + 0x99, 0xb0, 0x47, 0xab, 0xc3, 0xec, 0xfa, 0x6a, 0x37, 0xa3, 0xef, 0x00, + 0xf4, 0xa0, 0xc4, 0xa8, 0x8a, 0xae, 0x09, 0x04, 0xb7, 0x45, 0xc8, 0x46, + 0xc4, 0x10, 0x7e, 0x87, 0x97, 0x72, 0x3e, 0x8a, 0xc8, 0x10, 0xd9, 0xe3, + 0xd9, 0x5d, 0xfa, 0x30, 0xff, 0x49, 0x66, 0xf4, 0xd7, 0x5d, 0x13, 0x76, + 0x8d, 0x20, 0x85, 0x7f, 0x2b, 0x14, 0x06, 0xf2, 0x64, 0xcf, 0xe7, 0x5e, + 0x27, 0xd7, 0x65, 0x2f, 0x4b, 0x5e, 0xd3, 0x57, 0x5f, 0x28, 0xa7, 0x02, + 0xf8, 0xc4, 0xed, 0x9c, 0xf9, 0xb2, 0xd4, 0x49, 0x48}; + +// RSA-PSS test vectors, pss-vect.txt, Example 5: A 1028-bit RSA Key Pair +// <ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-1/pkcs-1v2-1-vec.zip> +const uint8_t kTestVector5Pkcs8[] = { + 0x30, 0x82, 0x02, 0x78, 0x02, 0x01, 0x00, 0x30, 0x0d, 0x06, 0x09, 0x2a, + 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x04, 0x82, + 0x02, 0x62, 0x30, 0x82, 0x02, 0x5e, 0x02, 0x01, 0x00, 0x02, 0x81, 0x81, + 0x0d, 0x10, 0xf6, 0x61, 0xf2, 0x99, 0x40, 0xf5, 0xed, 0x39, 0xaa, 0x26, + 0x09, 0x66, 0xde, 0xb4, 0x78, 0x43, 0x67, 0x9d, 0x2b, 0x6f, 0xb2, 0x5b, + 0x3d, 0xe3, 0x70, 0xf3, 0xac, 0x7c, 0x19, 0x91, 0x63, 0x91, 0xfd, 0x25, + 0xfb, 0x52, 0x7e, 0xbf, 0xa6, 0xa4, 0xb4, 0xdf, 0x45, 0xa1, 0x75, 0x9d, + 0x99, 0x6c, 0x4b, 0xb4, 0xeb, 0xd1, 0x88, 0x28, 0xc4, 0x4f, 0xc5, 0x2d, + 0x01, 0x91, 0x87, 0x17, 0x40, 0x52, 0x5f, 0x47, 0xa4, 0xb0, 0xcc, 0x8d, + 0xa3, 0x25, 0xed, 0x8a, 0xa6, 0x76, 0xb0, 0xd0, 0xf6, 0x26, 0xe0, 0xa7, + 0x7f, 0x07, 0x69, 0x21, 0x70, 0xac, 0xac, 0x80, 0x82, 0xf4, 0x2f, 0xaa, + 0x7d, 0xc7, 0xcd, 0x12, 0x3e, 0x73, 0x0e, 0x31, 0xa8, 0x79, 0x85, 0x20, + 0x4c, 0xab, 0xcb, 0xe6, 0x67, 0x0d, 0x43, 0xa2, 0xdd, 0x2b, 0x2d, 0xde, + 0xf5, 0xe0, 0x53, 0x92, 0xfc, 0x21, 0x3b, 0xc5, 0x07, 0x02, 0x03, 0x01, + 0x00, 0x01, 0x02, 0x81, 0x81, 0x03, 0xce, 0x08, 0xb1, 0x04, 0xff, 0xf3, + 0x96, 0xa9, 0x79, 0xbd, 0x3e, 0x4e, 0x46, 0x92, 0x5b, 0x63, 0x19, 0xdd, + 0xb6, 0x3a, 0xcb, 0xcf, 0xd8, 0x19, 0xf1, 0x7d, 0x16, 0xb8, 0x07, 0x7b, + 0x3a, 0x87, 0x10, 0x1f, 0xf3, 0x4b, 0x77, 0xfe, 0x48, 0xb8, 0xb2, 0x05, + 0xa9, 0x6e, 0x91, 0x51, 0xba, 0x8e, 0xce, 0xa6, 0x4d, 0x0c, 0xce, 0x7b, + 0x23, 0xc3, 0xe6, 0xa6, 0xb8, 0x30, 0x58, 0xbc, 0x49, 0xda, 0xe8, 0x16, + 0xae, 0x73, 0x6d, 0xb5, 0xa4, 0x70, 0x8e, 0x2a, 0xd4, 0x35, 0x23, 0x2b, + 0x56, 0x7f, 0x90, 0x96, 0xce, 0x59, 0xff, 0x28, 0x06, 0x1e, 0x79, 0xab, + 0x1c, 0x02, 0xd7, 0x17, 0xe6, 0xb2, 0x3c, 0xea, 0x6d, 0xb8, 0xeb, 0x51, + 0x92, 0xfa, 0x7c, 0x1e, 0xab, 0x22, 0x7d, 0xba, 0x74, 0x62, 0x1c, 0x45, + 0x60, 0x18, 0x96, 0xee, 0xf1, 0x37, 0x92, 0xc8, 0x44, 0x0b, 0xeb, 0x15, + 0xaa, 0xc1, 0x02, 0x41, 0x03, 0xf2, 0xf3, 0x31, 0xf4, 0x14, 0x2d, 0x4f, + 0x24, 0xb4, 0x3a, 0xa1, 0x02, 0x79, 0xa8, 0x96, 0x52, 0xd4, 0xe7, 0x53, + 0x72, 0x21, 0xa1, 0xa7, 0xb2, 0xa2, 0x5d, 0xeb, 0x55, 0x1e, 0x5d, 0xe9, + 0xac, 0x49, 0x74, 0x11, 0xc2, 0x27, 0xa9, 0x4e, 0x45, 0xf9, 0x1c, 0x2d, + 0x1c, 0x13, 0xcc, 0x04, 0x6c, 0xf4, 0xce, 0x14, 0xe3, 0x2d, 0x05, 0x87, + 0x34, 0x21, 0x0d, 0x44, 0xa8, 0x7e, 0xe1, 0xb7, 0x3f, 0x02, 0x41, 0x03, + 0x4f, 0x09, 0x0d, 0x73, 0xb5, 0x58, 0x03, 0x03, 0x0c, 0xf0, 0x36, 0x1a, + 0x5d, 0x80, 0x81, 0xbf, 0xb7, 0x9f, 0x85, 0x15, 0x23, 0xfe, 0xac, 0x0a, + 0x21, 0x24, 0xd0, 0x8d, 0x40, 0x13, 0xff, 0x08, 0x48, 0x77, 0x71, 0xa8, + 0x70, 0xd0, 0x47, 0x9d, 0xc0, 0x68, 0x6c, 0x62, 0xf7, 0x71, 0x8d, 0xfe, + 0xcf, 0x02, 0x4b, 0x17, 0xc9, 0x26, 0x76, 0x78, 0x05, 0x91, 0x71, 0x33, + 0x9c, 0xc0, 0x08, 0x39, 0x02, 0x41, 0x02, 0xaa, 0x66, 0x3a, 0xdb, 0xf5, + 0x1a, 0xb8, 0x87, 0xa0, 0x18, 0xcb, 0x42, 0x6e, 0x78, 0xbc, 0x2f, 0xe1, + 0x82, 0xdc, 0xb2, 0xf7, 0xbc, 0xb5, 0x04, 0x41, 0xd1, 0x7f, 0xdf, 0x0f, + 0x06, 0x79, 0x8b, 0x50, 0x71, 0xc6, 0xe2, 0xf5, 0xfe, 0xb4, 0xd5, 0x4a, + 0xd8, 0x18, 0x23, 0x11, 0xc1, 0xef, 0x62, 0xd4, 0xc4, 0x9f, 0x18, 0xd1, + 0xf5, 0x1f, 0x54, 0xb2, 0xd2, 0xcf, 0xfb, 0xa4, 0xda, 0x1b, 0xe5, 0x02, + 0x41, 0x02, 0xbb, 0xe7, 0x06, 0x07, 0x8b, 0x5c, 0x0b, 0x39, 0x15, 0x12, + 0xd4, 0x11, 0xdb, 0x1b, 0x19, 0x9b, 0x5a, 0x56, 0x64, 0xb8, 0x40, 0x42, + 0xea, 0xd3, 0x7f, 0xe9, 0x94, 0xae, 0x72, 0xb9, 0x53, 0x2d, 0xfb, 0xfb, + 0x3e, 0x9e, 0x69, 0x81, 0xa0, 0xfb, 0xb8, 0x06, 0x51, 0x31, 0x41, 0xb7, + 0xc2, 0x16, 0x3f, 0xe5, 0x6c, 0x39, 0x5e, 0x4b, 0xfa, 0xee, 0x57, 0xe3, + 0x83, 0x3f, 0x9b, 0x91, 0x8d, 0xf9, 0x02, 0x40, 0x02, 0x42, 0xb6, 0xcd, + 0x00, 0xd3, 0x0a, 0x76, 0x7a, 0xee, 0x9a, 0x89, 0x8e, 0xad, 0x45, 0x3c, + 0x8e, 0xae, 0xa6, 0x3d, 0x50, 0x0b, 0x7d, 0x1e, 0x00, 0x71, 0x3e, 0xda, + 0xe5, 0x1c, 0xe3, 0x6b, 0x23, 0xb6, 0x64, 0xdf, 0x26, 0xe6, 0x3e, 0x26, + 0x6e, 0xc8, 0xf7, 0x6e, 0x6e, 0x63, 0xed, 0x1b, 0xa4, 0x1e, 0xb0, 0x33, + 0xb1, 0x20, 0xf7, 0xea, 0x52, 0x12, 0xae, 0x21, 0xa9, 0x8f, 0xbc, 0x16}; +const uint8_t kTestVector5Spki[] = { + 0x30, 0x81, 0x9f, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, + 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x81, 0x8d, 0x00, 0x30, 0x81, + 0x89, 0x02, 0x81, 0x81, 0x0d, 0x10, 0xf6, 0x61, 0xf2, 0x99, 0x40, 0xf5, + 0xed, 0x39, 0xaa, 0x26, 0x09, 0x66, 0xde, 0xb4, 0x78, 0x43, 0x67, 0x9d, + 0x2b, 0x6f, 0xb2, 0x5b, 0x3d, 0xe3, 0x70, 0xf3, 0xac, 0x7c, 0x19, 0x91, + 0x63, 0x91, 0xfd, 0x25, 0xfb, 0x52, 0x7e, 0xbf, 0xa6, 0xa4, 0xb4, 0xdf, + 0x45, 0xa1, 0x75, 0x9d, 0x99, 0x6c, 0x4b, 0xb4, 0xeb, 0xd1, 0x88, 0x28, + 0xc4, 0x4f, 0xc5, 0x2d, 0x01, 0x91, 0x87, 0x17, 0x40, 0x52, 0x5f, 0x47, + 0xa4, 0xb0, 0xcc, 0x8d, 0xa3, 0x25, 0xed, 0x8a, 0xa6, 0x76, 0xb0, 0xd0, + 0xf6, 0x26, 0xe0, 0xa7, 0x7f, 0x07, 0x69, 0x21, 0x70, 0xac, 0xac, 0x80, + 0x82, 0xf4, 0x2f, 0xaa, 0x7d, 0xc7, 0xcd, 0x12, 0x3e, 0x73, 0x0e, 0x31, + 0xa8, 0x79, 0x85, 0x20, 0x4c, 0xab, 0xcb, 0xe6, 0x67, 0x0d, 0x43, 0xa2, + 0xdd, 0x2b, 0x2d, 0xde, 0xf5, 0xe0, 0x53, 0x92, 0xfc, 0x21, 0x3b, 0xc5, + 0x07, 0x02, 0x03, 0x01, 0x00, 0x01}; +// RSA-PSS test vectors, pss-vect.txt, Example 5.1 +const uint8_t kTestVector5Data[] = { + 0x30, 0xc7, 0xd5, 0x57, 0x45, 0x8b, 0x43, 0x6d, 0xec, 0xfd, 0xc1, 0x4d, + 0x06, 0xcb, 0x7b, 0x96, 0xb0, 0x67, 0x18, 0xc4, 0x8d, 0x7d, 0xe5, 0x74, + 0x82, 0xa8, 0x68, 0xae, 0x7f, 0x06, 0x58, 0x70, 0xa6, 0x21, 0x65, 0x06, + 0xd1, 0x1b, 0x77, 0x93, 0x23, 0xdf, 0xdf, 0x04, 0x6c, 0xf5, 0x77, 0x51, + 0x29, 0x13, 0x4b, 0x4d, 0x56, 0x89, 0xe4, 0xd9, 0xc0, 0xce, 0x1e, 0x12, + 0xd7, 0xd4, 0xb0, 0x6c, 0xb5, 0xfc, 0x58, 0x20, 0xde, 0xcf, 0xa4, 0x1b, + 0xaf, 0x59, 0xbf, 0x25, 0x7b, 0x32, 0xf0, 0x25, 0xb7, 0x67, 0x9b, 0x44, + 0x5b, 0x94, 0x99, 0xc9, 0x25, 0x55, 0x14, 0x58, 0x85, 0x99, 0x2f, 0x1b, + 0x76, 0xf8, 0x48, 0x91, 0xee, 0x4d, 0x3b, 0xe0, 0xf5, 0x15, 0x0f, 0xd5, + 0x90, 0x1e, 0x3a, 0x4c, 0x8e, 0xd4, 0x3f, 0xd3, 0x6b, 0x61, 0xd0, 0x22, + 0xe6, 0x5a, 0xd5, 0x00, 0x8d, 0xbf, 0x33, 0x29, 0x3c, 0x22, 0xbf, 0xbf, + 0xd0, 0x73, 0x21, 0xf0, 0xf1, 0xd5, 0xfa, 0x9f, 0xdf, 0x00, 0x14, 0xc2, + 0xfc, 0xb0, 0x35, 0x8a, 0xad, 0x0e, 0x35, 0x4b, 0x0d, 0x29}; +const uint8_t kTestVector5Sig[] = { + 0x0b, 0xa3, 0x73, 0xf7, 0x6e, 0x09, 0x21, 0xb7, 0x0a, 0x8f, 0xbf, 0xe6, + 0x22, 0xf0, 0xbf, 0x77, 0xb2, 0x8a, 0x3d, 0xb9, 0x8e, 0x36, 0x10, 0x51, + 0xc3, 0xd7, 0xcb, 0x92, 0xad, 0x04, 0x52, 0x91, 0x5a, 0x4d, 0xe9, 0xc0, + 0x17, 0x22, 0xf6, 0x82, 0x3e, 0xeb, 0x6a, 0xdf, 0x7e, 0x0c, 0xa8, 0x29, + 0x0f, 0x5d, 0xe3, 0xe5, 0x49, 0x89, 0x0a, 0xc2, 0xa3, 0xc5, 0x95, 0x0a, + 0xb2, 0x17, 0xba, 0x58, 0x59, 0x08, 0x94, 0x95, 0x2d, 0xe9, 0x6f, 0x8d, + 0xf1, 0x11, 0xb2, 0x57, 0x52, 0x15, 0xda, 0x6c, 0x16, 0x15, 0x90, 0xc7, + 0x45, 0xbe, 0x61, 0x24, 0x76, 0xee, 0x57, 0x8e, 0xd3, 0x84, 0xab, 0x33, + 0xe3, 0xec, 0xe9, 0x74, 0x81, 0xa2, 0x52, 0xf5, 0xc7, 0x9a, 0x98, 0xb5, + 0x53, 0x2a, 0xe0, 0x0c, 0xdd, 0x62, 0xf2, 0xec, 0xc0, 0xcd, 0x1b, 0xae, + 0xfe, 0x80, 0xd8, 0x0b, 0x96, 0x21, 0x93, 0xec, 0x1d}; + +// RSA-PSS test vectors, pss-vect.txt, Example 6: A 1029-bit RSA Key Pair +// <ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-1/pkcs-1v2-1-vec.zip> +const uint8_t kTestVector6Pkcs8[] = { + 0x30, 0x82, 0x02, 0x79, 0x02, 0x01, 0x00, 0x30, 0x0d, 0x06, 0x09, 0x2a, + 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x04, 0x82, + 0x02, 0x63, 0x30, 0x82, 0x02, 0x5f, 0x02, 0x01, 0x00, 0x02, 0x81, 0x81, + 0x16, 0x4c, 0xa3, 0x1c, 0xff, 0x60, 0x9f, 0x3a, 0x0e, 0x71, 0x01, 0xb0, + 0x39, 0xf2, 0xe4, 0xfe, 0x6d, 0xd3, 0x75, 0x19, 0xab, 0x98, 0x59, 0x8d, + 0x17, 0x9e, 0x17, 0x49, 0x96, 0x59, 0x80, 0x71, 0xf4, 0x7d, 0x3a, 0x04, + 0x55, 0x91, 0x58, 0xd7, 0xbe, 0x37, 0x3c, 0xf1, 0xaa, 0x53, 0xf0, 0xaa, + 0x6e, 0xf0, 0x90, 0x39, 0xe5, 0x67, 0x8c, 0x2a, 0x4c, 0x63, 0x90, 0x05, + 0x14, 0xc8, 0xc4, 0xf8, 0xaa, 0xed, 0x5d, 0xe1, 0x2a, 0x5f, 0x10, 0xb0, + 0x9c, 0x31, 0x1a, 0xf8, 0xc0, 0xff, 0xb5, 0xb7, 0xa2, 0x97, 0xf2, 0xef, + 0xc6, 0x3b, 0x8d, 0x6b, 0x05, 0x10, 0x93, 0x1f, 0x0b, 0x98, 0xe4, 0x8b, + 0xf5, 0xfc, 0x6e, 0xc4, 0xe7, 0xb8, 0xdb, 0x1f, 0xfa, 0xeb, 0x08, 0xc3, + 0x8e, 0x02, 0xad, 0xb8, 0xf0, 0x3a, 0x48, 0x22, 0x9c, 0x99, 0xe9, 0x69, + 0x43, 0x1f, 0x61, 0xcb, 0x8c, 0x4d, 0xc6, 0x98, 0xd1, 0x02, 0x03, 0x01, + 0x00, 0x01, 0x02, 0x81, 0x81, 0x03, 0xb6, 0x64, 0xee, 0x3b, 0x75, 0x66, + 0x72, 0x3f, 0xc6, 0xea, 0xf2, 0x8a, 0xbb, 0x43, 0x0a, 0x39, 0x80, 0xf1, + 0x12, 0x6c, 0x81, 0xde, 0x8a, 0xd7, 0x09, 0xea, 0xb3, 0x9a, 0xc9, 0xdc, + 0xd0, 0xb1, 0x55, 0x0b, 0x37, 0x29, 0xd8, 0x70, 0x68, 0xe9, 0x52, 0x00, + 0x9d, 0xf5, 0x44, 0x53, 0x4c, 0x1f, 0x50, 0x82, 0x9a, 0x78, 0xf4, 0x59, + 0x1e, 0xb8, 0xfd, 0x57, 0x14, 0x04, 0x26, 0xa6, 0xbb, 0x04, 0x05, 0xb6, + 0xa6, 0xf5, 0x1a, 0x57, 0xd9, 0x26, 0x7b, 0x7b, 0xbc, 0x65, 0x33, 0x91, + 0xa6, 0x99, 0xa2, 0xa9, 0x0d, 0xac, 0x8a, 0xe2, 0x26, 0xbc, 0xc6, 0x0f, + 0xa8, 0xcd, 0x93, 0x4c, 0x73, 0xc7, 0xb0, 0x3b, 0x1f, 0x6b, 0x81, 0x81, + 0x58, 0x63, 0x18, 0x38, 0xa8, 0x61, 0x2e, 0x6e, 0x6e, 0xa9, 0x2b, 0xe2, + 0x4f, 0x83, 0x24, 0xfa, 0xf5, 0xb1, 0xfd, 0x85, 0x87, 0x22, 0x52, 0x67, + 0xba, 0x6f, 0x02, 0x41, 0x04, 0xf0, 0x54, 0x8c, 0x96, 0x26, 0xab, 0x1e, + 0xbf, 0x12, 0x44, 0x93, 0x47, 0x41, 0xd9, 0x9a, 0x06, 0x22, 0x0e, 0xfa, + 0x2a, 0x58, 0x56, 0xaa, 0x0e, 0x75, 0x73, 0x0b, 0x2e, 0xc9, 0x6a, 0xdc, + 0x86, 0xbe, 0x89, 0x4f, 0xa2, 0x80, 0x3b, 0x53, 0xa5, 0xe8, 0x5d, 0x27, + 0x6a, 0xcb, 0xd2, 0x9a, 0xb8, 0x23, 0xf8, 0x0a, 0x73, 0x91, 0xbb, 0x54, + 0xa5, 0x05, 0x16, 0x72, 0xfb, 0x04, 0xee, 0xb5, 0x43, 0x02, 0x41, 0x04, + 0x83, 0xe0, 0xae, 0x47, 0x91, 0x55, 0x87, 0x74, 0x3f, 0xf3, 0x45, 0x36, + 0x2b, 0x55, 0x5d, 0x39, 0x62, 0xd9, 0x8b, 0xb6, 0xf1, 0x5f, 0x84, 0x8b, + 0x4c, 0x92, 0xb1, 0x77, 0x1c, 0xa8, 0xed, 0x10, 0x7d, 0x8d, 0x3e, 0xe6, + 0x5e, 0xc4, 0x45, 0x17, 0xdd, 0x0f, 0xaa, 0x48, 0x1a, 0x38, 0x7e, 0x90, + 0x2f, 0x7a, 0x2e, 0x74, 0x7c, 0x26, 0x9e, 0x7e, 0xa4, 0x44, 0x80, 0xbc, + 0x53, 0x8b, 0x8e, 0x5b, 0x02, 0x41, 0x03, 0xa8, 0xe8, 0xae, 0xa9, 0x92, + 0x0c, 0x1a, 0xa3, 0xb2, 0xf0, 0xd8, 0x46, 0xe4, 0xb8, 0x50, 0xd8, 0x1c, + 0xa3, 0x06, 0xa5, 0x1c, 0x83, 0x54, 0x4f, 0x94, 0x9f, 0x64, 0xf9, 0x0d, + 0xcf, 0x3f, 0x8e, 0x26, 0x61, 0xf0, 0x7e, 0x56, 0x12, 0x20, 0xa1, 0x80, + 0x38, 0x8f, 0xbe, 0x27, 0x3e, 0x70, 0xe2, 0xe5, 0xdc, 0xa8, 0x3a, 0x0e, + 0x13, 0x48, 0xdd, 0x64, 0x90, 0xc7, 0x31, 0xd6, 0xec, 0xe1, 0xab, 0x02, + 0x41, 0x01, 0x35, 0xbd, 0xcd, 0xb6, 0x0b, 0xf2, 0x19, 0x7c, 0x43, 0x6e, + 0xd3, 0x4b, 0x32, 0xcd, 0x8b, 0x4f, 0xc7, 0x77, 0x78, 0x83, 0x2b, 0xa7, + 0x67, 0x03, 0x55, 0x1f, 0xb2, 0x42, 0xb3, 0x01, 0x69, 0x95, 0x93, 0xaf, + 0x77, 0xfd, 0x8f, 0xc3, 0x94, 0xa8, 0x52, 0x6a, 0xd2, 0x3c, 0xc4, 0x1a, + 0x03, 0x80, 0x6b, 0xd8, 0x97, 0xfe, 0x4b, 0x0e, 0xa6, 0x46, 0x55, 0x8a, + 0xad, 0xdc, 0xc9, 0x9e, 0x8a, 0x25, 0x02, 0x41, 0x03, 0x04, 0xc0, 0x3d, + 0x9c, 0x73, 0x65, 0x03, 0xa9, 0x84, 0xab, 0xbd, 0x9b, 0xa2, 0x23, 0x01, + 0x40, 0x7c, 0x4a, 0x2a, 0xb1, 0xdd, 0x85, 0x76, 0x64, 0x81, 0xb6, 0x0d, + 0x45, 0x40, 0x11, 0x52, 0xe6, 0x92, 0xbe, 0x14, 0xf4, 0x12, 0x1d, 0x9a, + 0xa3, 0xfd, 0x6e, 0x0b, 0x4d, 0x1d, 0x3a, 0x97, 0x35, 0x38, 0xa3, 0x1d, + 0x42, 0xee, 0x6e, 0x1e, 0x5e, 0xf6, 0x20, 0x23, 0x1a, 0x2b, 0xba, 0xf3, + 0x5f}; +const uint8_t kTestVector6Spki[] = { + 0x30, 0x81, 0x9f, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, + 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x81, 0x8d, 0x00, 0x30, 0x81, + 0x89, 0x02, 0x81, 0x81, 0x16, 0x4c, 0xa3, 0x1c, 0xff, 0x60, 0x9f, 0x3a, + 0x0e, 0x71, 0x01, 0xb0, 0x39, 0xf2, 0xe4, 0xfe, 0x6d, 0xd3, 0x75, 0x19, + 0xab, 0x98, 0x59, 0x8d, 0x17, 0x9e, 0x17, 0x49, 0x96, 0x59, 0x80, 0x71, + 0xf4, 0x7d, 0x3a, 0x04, 0x55, 0x91, 0x58, 0xd7, 0xbe, 0x37, 0x3c, 0xf1, + 0xaa, 0x53, 0xf0, 0xaa, 0x6e, 0xf0, 0x90, 0x39, 0xe5, 0x67, 0x8c, 0x2a, + 0x4c, 0x63, 0x90, 0x05, 0x14, 0xc8, 0xc4, 0xf8, 0xaa, 0xed, 0x5d, 0xe1, + 0x2a, 0x5f, 0x10, 0xb0, 0x9c, 0x31, 0x1a, 0xf8, 0xc0, 0xff, 0xb5, 0xb7, + 0xa2, 0x97, 0xf2, 0xef, 0xc6, 0x3b, 0x8d, 0x6b, 0x05, 0x10, 0x93, 0x1f, + 0x0b, 0x98, 0xe4, 0x8b, 0xf5, 0xfc, 0x6e, 0xc4, 0xe7, 0xb8, 0xdb, 0x1f, + 0xfa, 0xeb, 0x08, 0xc3, 0x8e, 0x02, 0xad, 0xb8, 0xf0, 0x3a, 0x48, 0x22, + 0x9c, 0x99, 0xe9, 0x69, 0x43, 0x1f, 0x61, 0xcb, 0x8c, 0x4d, 0xc6, 0x98, + 0xd1, 0x02, 0x03, 0x01, 0x00, 0x01}; +// RSA-PSS test vectors, pss-vect.txt, Example 6.1 +const uint8_t kTestVector6Data[] = { + 0x0a, 0x20, 0xb7, 0x74, 0xad, 0xdc, 0x2f, 0xa5, 0x12, 0x45, 0xed, + 0x7c, 0xb9, 0xda, 0x60, 0x9e, 0x50, 0xca, 0xc6, 0x63, 0x6a, 0x52, + 0x54, 0x3f, 0x97, 0x45, 0x8e, 0xed, 0x73, 0x40, 0xf8, 0xd5, 0x3f, + 0xfc, 0x64, 0x91, 0x8f, 0x94, 0x90, 0x78, 0xee, 0x03, 0xef, 0x60, + 0xd4, 0x2b, 0x5f, 0xec, 0x24, 0x60, 0x50, 0xbd, 0x55, 0x05, 0xcd, + 0x8c, 0xb5, 0x97, 0xba, 0xd3, 0xc4, 0xe7, 0x13, 0xb0, 0xef, 0x30, + 0x64, 0x4e, 0x76, 0xad, 0xab, 0xb0, 0xde, 0x01, 0xa1, 0x56, 0x1e, + 0xfb, 0x25, 0x51, 0x58, 0xc7, 0x4f, 0xc8, 0x01, 0xe6, 0xe9, 0x19, + 0xe5, 0x81, 0xb4, 0x6f, 0x0f, 0x0d, 0xdd, 0x08, 0xe4, 0xf3, 0x4c, + 0x78, 0x10, 0xb5, 0xed, 0x83, 0x18, 0xf9, 0x1d, 0x7c, 0x8c}; +const uint8_t kTestVector6Sig[] = { + 0x04, 0xc0, 0xcf, 0xac, 0xec, 0x04, 0xe5, 0xba, 0xdb, 0xec, 0xe1, 0x59, + 0xa5, 0xa1, 0x10, 0x3f, 0x69, 0xb3, 0xf3, 0x2b, 0xa5, 0x93, 0xcb, 0x4c, + 0xc4, 0xb1, 0xb7, 0xab, 0x45, 0x59, 0x16, 0xa9, 0x6a, 0x27, 0xcd, 0x26, + 0x78, 0xea, 0x0f, 0x46, 0xba, 0x37, 0xf7, 0xfc, 0x9c, 0x86, 0x32, 0x5f, + 0x29, 0x73, 0x3b, 0x38, 0x9f, 0x1d, 0x97, 0xf4, 0x3e, 0x72, 0x01, 0xc0, + 0xf3, 0x48, 0xfc, 0x45, 0xfe, 0x42, 0x89, 0x23, 0x35, 0x36, 0x2e, 0xee, + 0x01, 0x8b, 0x5b, 0x16, 0x1f, 0x2f, 0x93, 0x93, 0x03, 0x12, 0x25, 0xc7, + 0x13, 0x01, 0x2a, 0x57, 0x6b, 0xc8, 0x8e, 0x23, 0x05, 0x24, 0x89, 0x86, + 0x8d, 0x90, 0x10, 0xcb, 0xf0, 0x33, 0xec, 0xc5, 0x68, 0xe8, 0xbc, 0x15, + 0x2b, 0xdc, 0x59, 0xd5, 0x60, 0xe4, 0x12, 0x91, 0x91, 0x5d, 0x28, 0x56, + 0x52, 0x08, 0xe2, 0x2a, 0xee, 0xc9, 0xef, 0x85, 0xd1}; + +// RSA-PSS test vectors, pss-vect.txt, Example 7: A 1030-bit RSA Key Pair +// <ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-1/pkcs-1v2-1-vec.zip> +const uint8_t kTestVector7Pkcs8[] = { + 0x30, 0x82, 0x02, 0x77, 0x02, 0x01, 0x00, 0x30, 0x0d, 0x06, 0x09, 0x2a, + 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x04, 0x82, + 0x02, 0x61, 0x30, 0x82, 0x02, 0x5d, 0x02, 0x01, 0x00, 0x02, 0x81, 0x81, + 0x37, 0xc9, 0xda, 0x4a, 0x66, 0xc8, 0xc4, 0x08, 0xb8, 0xda, 0x27, 0xd0, + 0xc9, 0xd7, 0x9f, 0x8c, 0xcb, 0x1e, 0xaf, 0xc1, 0xd2, 0xfe, 0x48, 0x74, + 0x6d, 0x94, 0x0b, 0x7c, 0x4e, 0xf5, 0xde, 0xe1, 0x8a, 0xd1, 0x26, 0x47, + 0xce, 0xfa, 0xa0, 0xc4, 0xb3, 0x18, 0x8b, 0x22, 0x1c, 0x51, 0x53, 0x86, + 0x75, 0x9b, 0x93, 0xf0, 0x20, 0x24, 0xb2, 0x5a, 0xb9, 0x24, 0x2f, 0x83, + 0x57, 0xd8, 0xf3, 0xfd, 0x49, 0x64, 0x0e, 0xe5, 0xe6, 0x43, 0xea, 0xf6, + 0xc6, 0x4d, 0xee, 0xfa, 0x70, 0x89, 0x72, 0x7c, 0x8f, 0xf0, 0x39, 0x93, + 0x33, 0x39, 0x15, 0xc6, 0xef, 0x21, 0xbf, 0x59, 0x75, 0xb6, 0xe5, 0x0d, + 0x11, 0x8b, 0x51, 0x00, 0x8e, 0xc3, 0x3e, 0x9f, 0x01, 0xa0, 0xa5, 0x45, + 0xa1, 0x0a, 0x83, 0x6a, 0x43, 0xdd, 0xbc, 0xa9, 0xd8, 0xb5, 0xc5, 0xd3, + 0x54, 0x80, 0x22, 0xd7, 0x06, 0x4e, 0xa2, 0x9a, 0xb3, 0x02, 0x03, 0x01, + 0x00, 0x01, 0x02, 0x81, 0x80, 0x3b, 0xed, 0x99, 0x90, 0x52, 0xd9, 0x57, + 0xbc, 0x06, 0xd6, 0x51, 0xee, 0xf6, 0xe3, 0xa9, 0x80, 0x94, 0xb1, 0x62, + 0x1b, 0xd3, 0x8b, 0x54, 0x49, 0xbd, 0x6c, 0x4a, 0xea, 0x3d, 0xe7, 0xe0, + 0x84, 0x67, 0x9a, 0x44, 0x84, 0xde, 0xd2, 0x5b, 0xe0, 0xf0, 0x82, 0x6c, + 0xf3, 0x37, 0x78, 0x25, 0x41, 0x4b, 0x14, 0xd4, 0xd6, 0x1d, 0xb1, 0x4d, + 0xe6, 0x26, 0xfb, 0xb8, 0x0e, 0x5f, 0x4f, 0xae, 0xc9, 0x56, 0xf9, 0xa0, + 0xa2, 0xd2, 0x4f, 0x99, 0x57, 0x63, 0x80, 0xf0, 0x84, 0xeb, 0x62, 0xe4, + 0x6a, 0x57, 0xd5, 0x54, 0x27, 0x8b, 0x53, 0x56, 0x26, 0x19, 0x3c, 0xe0, + 0x20, 0x60, 0x57, 0x5e, 0xb6, 0x6c, 0x57, 0x98, 0xd3, 0x6f, 0x6c, 0x5d, + 0x40, 0xfb, 0x00, 0xd8, 0x09, 0xb4, 0x2a, 0x73, 0x10, 0x2c, 0x1c, 0x74, + 0xee, 0x95, 0xbd, 0x71, 0x42, 0x0f, 0xff, 0xef, 0x63, 0x18, 0xb5, 0x2c, + 0x29, 0x02, 0x41, 0x07, 0xee, 0xfb, 0x42, 0x4b, 0x0e, 0x3a, 0x40, 0xe4, + 0x20, 0x8e, 0xe5, 0xaf, 0xb2, 0x80, 0xb2, 0x23, 0x17, 0x30, 0x81, 0x14, + 0xdd, 0xe0, 0xb4, 0xb6, 0x4f, 0x73, 0x01, 0x84, 0xec, 0x68, 0xda, 0x6c, + 0xe2, 0x86, 0x7a, 0x9f, 0x48, 0xed, 0x77, 0x26, 0xd5, 0xe2, 0x61, 0x4e, + 0xd0, 0x4a, 0x54, 0x10, 0x73, 0x6c, 0x8c, 0x71, 0x4e, 0xe7, 0x02, 0x47, + 0x42, 0x98, 0xc6, 0x29, 0x2a, 0xf0, 0x75, 0x35, 0x02, 0x41, 0x07, 0x08, + 0x30, 0xdb, 0xf9, 0x47, 0xea, 0xc0, 0x22, 0x8d, 0xe2, 0x63, 0x14, 0xb5, + 0x9b, 0x66, 0x99, 0x4c, 0xc6, 0x0e, 0x83, 0x60, 0xe7, 0x5d, 0x38, 0x76, + 0x29, 0x8f, 0x8f, 0x8a, 0x7d, 0x14, 0x1d, 0xa0, 0x64, 0xe5, 0xca, 0x02, + 0x6a, 0x97, 0x3e, 0x28, 0xf2, 0x54, 0x73, 0x8c, 0xee, 0x66, 0x9c, 0x72, + 0x1b, 0x03, 0x4c, 0xb5, 0xf8, 0xe2, 0x44, 0xda, 0xdd, 0x7c, 0xd1, 0xe1, + 0x59, 0xd5, 0x47, 0x02, 0x41, 0x05, 0x24, 0xd2, 0x0c, 0x3d, 0x95, 0xcf, + 0xf7, 0x5a, 0xf2, 0x31, 0x34, 0x83, 0x22, 0x7d, 0x87, 0x02, 0x71, 0x7a, + 0xa5, 0x76, 0xde, 0x15, 0x5f, 0x96, 0x05, 0x15, 0x50, 0x1a, 0xdb, 0x1d, + 0x70, 0xe1, 0xc0, 0x4d, 0xe9, 0x1b, 0x75, 0xb1, 0x61, 0xdb, 0xf0, 0x39, + 0x83, 0x56, 0x12, 0x7e, 0xde, 0xda, 0x7b, 0xbc, 0x19, 0xa3, 0x2d, 0xc1, + 0x62, 0x1c, 0xc9, 0xf5, 0x3c, 0x26, 0x5d, 0x0c, 0xe3, 0x31, 0x02, 0x41, + 0x05, 0xf9, 0x84, 0xa1, 0xf2, 0x3c, 0x93, 0x8d, 0x6a, 0x0e, 0x89, 0x72, + 0x4b, 0xcf, 0x3d, 0xd9, 0x3f, 0x99, 0x46, 0x92, 0x60, 0x37, 0xfe, 0x7c, + 0x6b, 0x13, 0xa2, 0x9e, 0x52, 0x84, 0x85, 0x5f, 0x89, 0x08, 0x95, 0x91, + 0xd4, 0x40, 0x97, 0x56, 0x27, 0xbf, 0x5c, 0x9e, 0x3a, 0x8b, 0x5c, 0xa7, + 0x9c, 0x77, 0x2a, 0xd2, 0x73, 0xe4, 0x0d, 0x32, 0x1a, 0xf4, 0xa6, 0xc9, + 0x7d, 0xfd, 0xed, 0x78, 0xd3, 0x02, 0x40, 0xdd, 0xd9, 0x18, 0xad, 0xad, + 0xa2, 0x9d, 0xca, 0xb9, 0x81, 0xff, 0x9a, 0xcb, 0xa4, 0x25, 0x70, 0x23, + 0xc0, 0x9a, 0x38, 0x01, 0xcc, 0xce, 0x09, 0x8c, 0xe2, 0x68, 0xf8, 0x55, + 0xd0, 0xdf, 0x57, 0x0c, 0xd6, 0xe7, 0xb9, 0xb1, 0x4b, 0xd9, 0xa5, 0xa9, + 0x25, 0x4c, 0xbc, 0x31, 0x5b, 0xe6, 0xf8, 0xba, 0x1e, 0x25, 0x46, 0xdd, + 0xd5, 0x69, 0xc5, 0xea, 0x19, 0xee, 0xd8, 0x35, 0x3b, 0xde, 0x5e}; +const uint8_t kTestVector7Spki[] = { + 0x30, 0x81, 0x9f, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, + 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x81, 0x8d, 0x00, 0x30, 0x81, + 0x89, 0x02, 0x81, 0x81, 0x37, 0xc9, 0xda, 0x4a, 0x66, 0xc8, 0xc4, 0x08, + 0xb8, 0xda, 0x27, 0xd0, 0xc9, 0xd7, 0x9f, 0x8c, 0xcb, 0x1e, 0xaf, 0xc1, + 0xd2, 0xfe, 0x48, 0x74, 0x6d, 0x94, 0x0b, 0x7c, 0x4e, 0xf5, 0xde, 0xe1, + 0x8a, 0xd1, 0x26, 0x47, 0xce, 0xfa, 0xa0, 0xc4, 0xb3, 0x18, 0x8b, 0x22, + 0x1c, 0x51, 0x53, 0x86, 0x75, 0x9b, 0x93, 0xf0, 0x20, 0x24, 0xb2, 0x5a, + 0xb9, 0x24, 0x2f, 0x83, 0x57, 0xd8, 0xf3, 0xfd, 0x49, 0x64, 0x0e, 0xe5, + 0xe6, 0x43, 0xea, 0xf6, 0xc6, 0x4d, 0xee, 0xfa, 0x70, 0x89, 0x72, 0x7c, + 0x8f, 0xf0, 0x39, 0x93, 0x33, 0x39, 0x15, 0xc6, 0xef, 0x21, 0xbf, 0x59, + 0x75, 0xb6, 0xe5, 0x0d, 0x11, 0x8b, 0x51, 0x00, 0x8e, 0xc3, 0x3e, 0x9f, + 0x01, 0xa0, 0xa5, 0x45, 0xa1, 0x0a, 0x83, 0x6a, 0x43, 0xdd, 0xbc, 0xa9, + 0xd8, 0xb5, 0xc5, 0xd3, 0x54, 0x80, 0x22, 0xd7, 0x06, 0x4e, 0xa2, 0x9a, + 0xb3, 0x02, 0x03, 0x01, 0x00, 0x01}; +// RSA-PSS test vectors, pss-vect.txt, Example 7.1 +const uint8_t kTestVector7Data[] = { + 0x9e, 0xad, 0x0e, 0x01, 0x94, 0x56, 0x40, 0x67, 0x4e, 0xb4, 0x1c, 0xad, + 0x43, 0x5e, 0x23, 0x74, 0xea, 0xef, 0xa8, 0xad, 0x71, 0x97, 0xd9, 0x79, + 0x13, 0xc4, 0x49, 0x57, 0xd8, 0xd8, 0x3f, 0x40, 0xd7, 0x6e, 0xe6, 0x0e, + 0x39, 0xbf, 0x9c, 0x0f, 0x9e, 0xaf, 0x30, 0x21, 0x42, 0x1a, 0x07, 0x4d, + 0x1a, 0xde, 0x96, 0x2c, 0x6e, 0x9d, 0x3d, 0xc3, 0xbb, 0x17, 0x4f, 0xe4, + 0xdf, 0xe6, 0x52, 0xb0, 0x91, 0x15, 0x49, 0x5b, 0x8f, 0xd2, 0x79, 0x41, + 0x74, 0x02, 0x0a, 0x06, 0x02, 0xb5, 0xca, 0x51, 0x84, 0x8c, 0xfc, 0x96, + 0xce, 0x5e, 0xb5, 0x7f, 0xc0, 0xa2, 0xad, 0xc1, 0xdd, 0xa3, 0x6a, 0x7c, + 0xc4, 0x52, 0x64, 0x1a, 0x14, 0x91, 0x1b, 0x37, 0xe4, 0x5b, 0xfa, 0x11, + 0xda, 0xa5, 0xc7, 0xec, 0xdb, 0x74, 0xf6, 0xd0, 0x10, 0x0d, 0x1d, 0x3e, + 0x39, 0xe7, 0x52, 0x80, 0x0e, 0x20, 0x33, 0x97, 0xde, 0x02, 0x33, 0x07, + 0x7b, 0x9a, 0x88, 0x85, 0x55, 0x37, 0xfa, 0xe9, 0x27, 0xf9, 0x24, 0x38, + 0x0d, 0x78, 0x0f, 0x98, 0xe1, 0x8d, 0xcf, 0xf3, 0x9c, 0x5e, 0xa7, 0x41, + 0xb1, 0x7d, 0x6f, 0xdd, 0x18, 0x85, 0xbc, 0x9d, 0x58, 0x14, 0x82, 0xd7, + 0x71, 0xce, 0xb5, 0x62, 0xd7, 0x8a, 0x8b, 0xf8, 0x8f, 0x0c, 0x75, 0xb1, + 0x13, 0x63, 0xe5, 0xe3, 0x6c, 0xd4, 0x79, 0xce, 0xb0, 0x54, 0x5f, 0x9d, + 0xa8, 0x42, 0x03, 0xe0, 0xe6, 0xe5, 0x08, 0x37, 0x5c, 0xc9, 0xe8, 0x44, + 0xb8, 0x8b, 0x7a, 0xc7, 0xa0, 0xa2, 0x01, 0xea, 0x0f, 0x1b, 0xee, 0x9a, + 0x2c, 0x57, 0x79, 0x20, 0xca, 0x02, 0xc0, 0x1b, 0x9d, 0x83, 0x20, 0xe9, + 0x74, 0xa5, 0x6f, 0x4e, 0xfb, 0x57, 0x63, 0xb9, 0x62, 0x55, 0xab, 0xbf, + 0x80, 0x37, 0xbf, 0x18, 0x02, 0xcf, 0x01, 0x8f, 0x56, 0x37, 0x94, 0x93, + 0xe5, 0x69, 0xa9}; +const uint8_t kTestVector7Sig[] = { + 0x18, 0x7f, 0x39, 0x07, 0x23, 0xc8, 0x90, 0x25, 0x91, 0xf0, 0x15, 0x4b, + 0xae, 0x6d, 0x4e, 0xcb, 0xff, 0xe0, 0x67, 0xf0, 0xe8, 0xb7, 0x95, 0x47, + 0x6e, 0xa4, 0xf4, 0xd5, 0x1c, 0xcc, 0x81, 0x05, 0x20, 0xbb, 0x3c, 0xa9, + 0xbc, 0xa7, 0xd0, 0xb1, 0xf2, 0xea, 0x8a, 0x17, 0xd8, 0x73, 0xfa, 0x27, + 0x57, 0x0a, 0xcd, 0x64, 0x2e, 0x38, 0x08, 0x56, 0x1c, 0xb9, 0xe9, 0x75, + 0xcc, 0xfd, 0x80, 0xb2, 0x3d, 0xc5, 0x77, 0x1c, 0xdb, 0x33, 0x06, 0xa5, + 0xf2, 0x31, 0x59, 0xda, 0xcb, 0xd3, 0xaa, 0x2d, 0xb9, 0x3d, 0x46, 0xd7, + 0x66, 0xe0, 0x9e, 0xd1, 0x5d, 0x90, 0x0a, 0xd8, 0x97, 0xa8, 0xd2, 0x74, + 0xdc, 0x26, 0xb4, 0x7e, 0x99, 0x4a, 0x27, 0xe9, 0x7e, 0x22, 0x68, 0xa7, + 0x66, 0x53, 0x3a, 0xe4, 0xb5, 0xe4, 0x2a, 0x2f, 0xca, 0xf7, 0x55, 0xc1, + 0xc4, 0x79, 0x4b, 0x29, 0x4c, 0x60, 0x55, 0x58, 0x23}; + +// RSA-PSS test vectors, pss-vect.txt, Example 8: A 1031-bit RSA Key Pair +// <ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-1/pkcs-1v2-1-vec.zip> +const uint8_t kTestVector8Pkcs8[] = { + 0x30, 0x82, 0x02, 0x78, 0x02, 0x01, 0x00, 0x30, 0x0d, 0x06, 0x09, 0x2a, + 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x04, 0x82, + 0x02, 0x62, 0x30, 0x82, 0x02, 0x5e, 0x02, 0x01, 0x00, 0x02, 0x81, 0x81, + 0x49, 0x53, 0x70, 0xa1, 0xfb, 0x18, 0x54, 0x3c, 0x16, 0xd3, 0x63, 0x1e, + 0x31, 0x63, 0x25, 0x5d, 0xf6, 0x2b, 0xe6, 0xee, 0xe8, 0x90, 0xd5, 0xf2, + 0x55, 0x09, 0xe4, 0xf7, 0x78, 0xa8, 0xea, 0x6f, 0xbb, 0xbc, 0xdf, 0x85, + 0xdf, 0xf6, 0x4e, 0x0d, 0x97, 0x20, 0x03, 0xab, 0x36, 0x81, 0xfb, 0xba, + 0x6d, 0xd4, 0x1f, 0xd5, 0x41, 0x82, 0x9b, 0x2e, 0x58, 0x2d, 0xe9, 0xf2, + 0xa4, 0xa4, 0xe0, 0xa2, 0xd0, 0x90, 0x0b, 0xef, 0x47, 0x53, 0xdb, 0x3c, + 0xee, 0x0e, 0xe0, 0x6c, 0x7d, 0xfa, 0xe8, 0xb1, 0xd5, 0x3b, 0x59, 0x53, + 0x21, 0x8f, 0x9c, 0xce, 0xea, 0x69, 0x5b, 0x08, 0x66, 0x8e, 0xde, 0xaa, + 0xdc, 0xed, 0x94, 0x63, 0xb1, 0xd7, 0x90, 0xd5, 0xeb, 0xf2, 0x7e, 0x91, + 0x15, 0xb4, 0x6c, 0xad, 0x4d, 0x9a, 0x2b, 0x8e, 0xfa, 0xb0, 0x56, 0x1b, + 0x08, 0x10, 0x34, 0x47, 0x39, 0xad, 0xa0, 0x73, 0x3f, 0x02, 0x03, 0x01, + 0x00, 0x01, 0x02, 0x81, 0x80, 0x6c, 0x66, 0xff, 0xe9, 0x89, 0x80, 0xc3, + 0x8f, 0xcd, 0xea, 0xb5, 0x15, 0x98, 0x98, 0x83, 0x61, 0x65, 0xf4, 0xb4, + 0xb8, 0x17, 0xc4, 0xf6, 0xa8, 0xd4, 0x86, 0xee, 0x4e, 0xa9, 0x13, 0x0f, + 0xe9, 0xb9, 0x09, 0x2b, 0xd1, 0x36, 0xd1, 0x84, 0xf9, 0x5f, 0x50, 0x4a, + 0x60, 0x7e, 0xac, 0x56, 0x58, 0x46, 0xd2, 0xfd, 0xd6, 0x59, 0x7a, 0x89, + 0x67, 0xc7, 0x39, 0x6e, 0xf9, 0x5a, 0x6e, 0xee, 0xbb, 0x45, 0x78, 0xa6, + 0x43, 0x96, 0x6d, 0xca, 0x4d, 0x8e, 0xe3, 0xde, 0x84, 0x2d, 0xe6, 0x32, + 0x79, 0xc6, 0x18, 0x15, 0x9c, 0x1a, 0xb5, 0x4a, 0x89, 0x43, 0x7b, 0x6a, + 0x61, 0x20, 0xe4, 0x93, 0x0a, 0xfb, 0x52, 0xa4, 0xba, 0x6c, 0xed, 0x8a, + 0x49, 0x47, 0xac, 0x64, 0xb3, 0x0a, 0x34, 0x97, 0xcb, 0xe7, 0x01, 0xc2, + 0xd6, 0x26, 0x6d, 0x51, 0x72, 0x19, 0xad, 0x0e, 0xc6, 0xd3, 0x47, 0xdb, + 0xe9, 0x02, 0x41, 0x08, 0xda, 0xd7, 0xf1, 0x13, 0x63, 0xfa, 0xa6, 0x23, + 0xd5, 0xd6, 0xd5, 0xe8, 0xa3, 0x19, 0x32, 0x8d, 0x82, 0x19, 0x0d, 0x71, + 0x27, 0xd2, 0x84, 0x6c, 0x43, 0x9b, 0x0a, 0xb7, 0x26, 0x19, 0xb0, 0xa4, + 0x3a, 0x95, 0x32, 0x0e, 0x4e, 0xc3, 0x4f, 0xc3, 0xa9, 0xce, 0xa8, 0x76, + 0x42, 0x23, 0x05, 0xbd, 0x76, 0xc5, 0xba, 0x7b, 0xe9, 0xe2, 0xf4, 0x10, + 0xc8, 0x06, 0x06, 0x45, 0xa1, 0xd2, 0x9e, 0xdb, 0x02, 0x41, 0x08, 0x47, + 0xe7, 0x32, 0x37, 0x6f, 0xc7, 0x90, 0x0f, 0x89, 0x8e, 0xa8, 0x2e, 0xb2, + 0xb0, 0xfc, 0x41, 0x85, 0x65, 0xfd, 0xae, 0x62, 0xf7, 0xd9, 0xec, 0x4c, + 0xe2, 0x21, 0x7b, 0x97, 0x99, 0x0d, 0xd2, 0x72, 0xdb, 0x15, 0x7f, 0x99, + 0xf6, 0x3c, 0x0d, 0xcb, 0xb9, 0xfb, 0xac, 0xdb, 0xd4, 0xc4, 0xda, 0xdb, + 0x6d, 0xf6, 0x77, 0x56, 0x35, 0x8c, 0xa4, 0x17, 0x48, 0x25, 0xb4, 0x8f, + 0x49, 0x70, 0x6d, 0x02, 0x41, 0x05, 0xc2, 0xa8, 0x3c, 0x12, 0x4b, 0x36, + 0x21, 0xa2, 0xaa, 0x57, 0xea, 0x2c, 0x3e, 0xfe, 0x03, 0x5e, 0xff, 0x45, + 0x60, 0xf3, 0x3d, 0xde, 0xbb, 0x7a, 0xda, 0xb8, 0x1f, 0xce, 0x69, 0xa0, + 0xc8, 0xc2, 0xed, 0xc1, 0x65, 0x20, 0xdd, 0xa8, 0x3d, 0x59, 0xa2, 0x3b, + 0xe8, 0x67, 0x96, 0x3a, 0xc6, 0x5f, 0x2c, 0xc7, 0x10, 0xbb, 0xcf, 0xb9, + 0x6e, 0xe1, 0x03, 0xde, 0xb7, 0x71, 0xd1, 0x05, 0xfd, 0x85, 0x02, 0x41, + 0x04, 0xca, 0xe8, 0xaa, 0x0d, 0x9f, 0xaa, 0x16, 0x5c, 0x87, 0xb6, 0x82, + 0xec, 0x14, 0x0b, 0x8e, 0xd3, 0xb5, 0x0b, 0x24, 0x59, 0x4b, 0x7a, 0x3b, + 0x2c, 0x22, 0x0b, 0x36, 0x69, 0xbb, 0x81, 0x9f, 0x98, 0x4f, 0x55, 0x31, + 0x0a, 0x1a, 0xe7, 0x82, 0x36, 0x51, 0xd4, 0xa0, 0x2e, 0x99, 0x44, 0x79, + 0x72, 0x59, 0x51, 0x39, 0x36, 0x34, 0x34, 0xe5, 0xe3, 0x0a, 0x7e, 0x7d, + 0x24, 0x15, 0x51, 0xe1, 0xb9, 0x02, 0x41, 0x07, 0xd3, 0xe4, 0x7b, 0xf6, + 0x86, 0x60, 0x0b, 0x11, 0xac, 0x28, 0x3c, 0xe8, 0x8d, 0xbb, 0x3f, 0x60, + 0x51, 0xe8, 0xef, 0xd0, 0x46, 0x80, 0xe4, 0x4c, 0x17, 0x1e, 0xf5, 0x31, + 0xb8, 0x0b, 0x2b, 0x7c, 0x39, 0xfc, 0x76, 0x63, 0x20, 0xe2, 0xcf, 0x15, + 0xd8, 0xd9, 0x98, 0x20, 0xe9, 0x6f, 0xf3, 0x0d, 0xc6, 0x96, 0x91, 0x83, + 0x9c, 0x4b, 0x40, 0xd7, 0xb0, 0x6e, 0x45, 0x30, 0x7d, 0xc9, 0x1f, 0x3f}; +const uint8_t kTestVector8Spki[] = { + 0x30, 0x81, 0x9f, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, + 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x81, 0x8d, 0x00, 0x30, 0x81, + 0x89, 0x02, 0x81, 0x81, 0x49, 0x53, 0x70, 0xa1, 0xfb, 0x18, 0x54, 0x3c, + 0x16, 0xd3, 0x63, 0x1e, 0x31, 0x63, 0x25, 0x5d, 0xf6, 0x2b, 0xe6, 0xee, + 0xe8, 0x90, 0xd5, 0xf2, 0x55, 0x09, 0xe4, 0xf7, 0x78, 0xa8, 0xea, 0x6f, + 0xbb, 0xbc, 0xdf, 0x85, 0xdf, 0xf6, 0x4e, 0x0d, 0x97, 0x20, 0x03, 0xab, + 0x36, 0x81, 0xfb, 0xba, 0x6d, 0xd4, 0x1f, 0xd5, 0x41, 0x82, 0x9b, 0x2e, + 0x58, 0x2d, 0xe9, 0xf2, 0xa4, 0xa4, 0xe0, 0xa2, 0xd0, 0x90, 0x0b, 0xef, + 0x47, 0x53, 0xdb, 0x3c, 0xee, 0x0e, 0xe0, 0x6c, 0x7d, 0xfa, 0xe8, 0xb1, + 0xd5, 0x3b, 0x59, 0x53, 0x21, 0x8f, 0x9c, 0xce, 0xea, 0x69, 0x5b, 0x08, + 0x66, 0x8e, 0xde, 0xaa, 0xdc, 0xed, 0x94, 0x63, 0xb1, 0xd7, 0x90, 0xd5, + 0xeb, 0xf2, 0x7e, 0x91, 0x15, 0xb4, 0x6c, 0xad, 0x4d, 0x9a, 0x2b, 0x8e, + 0xfa, 0xb0, 0x56, 0x1b, 0x08, 0x10, 0x34, 0x47, 0x39, 0xad, 0xa0, 0x73, + 0x3f, 0x02, 0x03, 0x01, 0x00, 0x01}; +// RSA-PSS test vectors, pss-vect.txt, Example 8.1 +const uint8_t kTestVector8Data[] = { + 0x81, 0x33, 0x2f, 0x4b, 0xe6, 0x29, 0x48, 0x41, 0x5e, 0xa1, 0xd8, 0x99, + 0x79, 0x2e, 0xea, 0xcf, 0x6c, 0x6e, 0x1d, 0xb1, 0xda, 0x8b, 0xe1, 0x3b, + 0x5c, 0xea, 0x41, 0xdb, 0x2f, 0xed, 0x46, 0x70, 0x92, 0xe1, 0xff, 0x39, + 0x89, 0x14, 0xc7, 0x14, 0x25, 0x97, 0x75, 0xf5, 0x95, 0xf8, 0x54, 0x7f, + 0x73, 0x56, 0x92, 0xa5, 0x75, 0xe6, 0x92, 0x3a, 0xf7, 0x8f, 0x22, 0xc6, + 0x99, 0x7d, 0xdb, 0x90, 0xfb, 0x6f, 0x72, 0xd7, 0xbb, 0x0d, 0xd5, 0x74, + 0x4a, 0x31, 0xde, 0xcd, 0x3d, 0xc3, 0x68, 0x58, 0x49, 0x83, 0x6e, 0xd3, + 0x4a, 0xec, 0x59, 0x63, 0x04, 0xad, 0x11, 0x84, 0x3c, 0x4f, 0x88, 0x48, + 0x9f, 0x20, 0x97, 0x35, 0xf5, 0xfb, 0x7f, 0xda, 0xf7, 0xce, 0xc8, 0xad, + 0xdc, 0x58, 0x18, 0x16, 0x8f, 0x88, 0x0a, 0xcb, 0xf4, 0x90, 0xd5, 0x10, + 0x05, 0xb7, 0xa8, 0xe8, 0x4e, 0x43, 0xe5, 0x42, 0x87, 0x97, 0x75, 0x71, + 0xdd, 0x99, 0xee, 0xa4, 0xb1, 0x61, 0xeb, 0x2d, 0xf1, 0xf5, 0x10, 0x8f, + 0x12, 0xa4, 0x14, 0x2a, 0x83, 0x32, 0x2e, 0xdb, 0x05, 0xa7, 0x54, 0x87, + 0xa3, 0x43, 0x5c, 0x9a, 0x78, 0xce, 0x53, 0xed, 0x93, 0xbc, 0x55, 0x08, + 0x57, 0xd7, 0xa9, 0xfb}; +const uint8_t kTestVector8Sig[] = { + 0x02, 0x62, 0xac, 0x25, 0x4b, 0xfa, 0x77, 0xf3, 0xc1, 0xac, 0xa2, 0x2c, + 0x51, 0x79, 0xf8, 0xf0, 0x40, 0x42, 0x2b, 0x3c, 0x5b, 0xaf, 0xd4, 0x0a, + 0x8f, 0x21, 0xcf, 0x0f, 0xa5, 0xa6, 0x67, 0xcc, 0xd5, 0x99, 0x3d, 0x42, + 0xdb, 0xaf, 0xb4, 0x09, 0xc5, 0x20, 0xe2, 0x5f, 0xce, 0x2b, 0x1e, 0xe1, + 0xe7, 0x16, 0x57, 0x7f, 0x1e, 0xfa, 0x17, 0xf3, 0xda, 0x28, 0x05, 0x2f, + 0x40, 0xf0, 0x41, 0x9b, 0x23, 0x10, 0x6d, 0x78, 0x45, 0xaa, 0xf0, 0x11, + 0x25, 0xb6, 0x98, 0xe7, 0xa4, 0xdf, 0xe9, 0x2d, 0x39, 0x67, 0xbb, 0x00, + 0xc4, 0xd0, 0xd3, 0x5b, 0xa3, 0x55, 0x2a, 0xb9, 0xa8, 0xb3, 0xee, 0xf0, + 0x7c, 0x7f, 0xec, 0xdb, 0xc5, 0x42, 0x4a, 0xc4, 0xdb, 0x1e, 0x20, 0xcb, + 0x37, 0xd0, 0xb2, 0x74, 0x47, 0x69, 0x94, 0x0e, 0xa9, 0x07, 0xe1, 0x7f, + 0xbb, 0xca, 0x67, 0x3b, 0x20, 0x52, 0x23, 0x80, 0xc5}; + +// RSA-PSS test vectors, pss-vect.txt, Example 9: A 1536-bit RSA Key Pair +// <ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-1/pkcs-1v2-1-vec.zip> +const uint8_t kTestVector9Pkcs8[] = { + 0x30, 0x82, 0x03, 0x92, 0x02, 0x01, 0x00, 0x30, 0x0d, 0x06, 0x09, 0x2a, + 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x04, 0x82, + 0x03, 0x7c, 0x30, 0x82, 0x03, 0x78, 0x02, 0x01, 0x00, 0x02, 0x81, 0xc0, + 0xe6, 0xbd, 0x69, 0x2a, 0xc9, 0x66, 0x45, 0x79, 0x04, 0x03, 0xfd, 0xd0, + 0xf5, 0xbe, 0xb8, 0xb9, 0xbf, 0x92, 0xed, 0x10, 0x00, 0x7f, 0xc3, 0x65, + 0x04, 0x64, 0x19, 0xdd, 0x06, 0xc0, 0x5c, 0x5b, 0x5b, 0x2f, 0x48, 0xec, + 0xf9, 0x89, 0xe4, 0xce, 0x26, 0x91, 0x09, 0x97, 0x9c, 0xbb, 0x40, 0xb4, + 0xa0, 0xad, 0x24, 0xd2, 0x24, 0x83, 0xd1, 0xee, 0x31, 0x5a, 0xd4, 0xcc, + 0xb1, 0x53, 0x42, 0x68, 0x35, 0x26, 0x91, 0xc5, 0x24, 0xf6, 0xdd, 0x8e, + 0x6c, 0x29, 0xd2, 0x24, 0xcf, 0x24, 0x69, 0x73, 0xae, 0xc8, 0x6c, 0x5b, + 0xf6, 0xb1, 0x40, 0x1a, 0x85, 0x0d, 0x1b, 0x9a, 0xd1, 0xbb, 0x8c, 0xbc, + 0xec, 0x47, 0xb0, 0x6f, 0x0f, 0x8c, 0x7f, 0x45, 0xd3, 0xfc, 0x8f, 0x31, + 0x92, 0x99, 0xc5, 0x43, 0x3d, 0xdb, 0xc2, 0xb3, 0x05, 0x3b, 0x47, 0xde, + 0xd2, 0xec, 0xd4, 0xa4, 0xca, 0xef, 0xd6, 0x14, 0x83, 0x3d, 0xc8, 0xbb, + 0x62, 0x2f, 0x31, 0x7e, 0xd0, 0x76, 0xb8, 0x05, 0x7f, 0xe8, 0xde, 0x3f, + 0x84, 0x48, 0x0a, 0xd5, 0xe8, 0x3e, 0x4a, 0x61, 0x90, 0x4a, 0x4f, 0x24, + 0x8f, 0xb3, 0x97, 0x02, 0x73, 0x57, 0xe1, 0xd3, 0x0e, 0x46, 0x31, 0x39, + 0x81, 0x5c, 0x6f, 0xd4, 0xfd, 0x5a, 0xc5, 0xb8, 0x17, 0x2a, 0x45, 0x23, + 0x0e, 0xcb, 0x63, 0x18, 0xa0, 0x4f, 0x14, 0x55, 0xd8, 0x4e, 0x5a, 0x8b, + 0x02, 0x03, 0x01, 0x00, 0x01, 0x02, 0x81, 0xc0, 0x6a, 0x7f, 0xd8, 0x4f, + 0xb8, 0x5f, 0xad, 0x07, 0x3b, 0x34, 0x40, 0x6d, 0xb7, 0x4f, 0x8d, 0x61, + 0xa6, 0xab, 0xc1, 0x21, 0x96, 0xa9, 0x61, 0xdd, 0x79, 0x56, 0x5e, 0x9d, + 0xa6, 0xe5, 0x18, 0x7b, 0xce, 0x2d, 0x98, 0x02, 0x50, 0xf7, 0x35, 0x95, + 0x75, 0x35, 0x92, 0x70, 0xd9, 0x15, 0x90, 0xbb, 0x0e, 0x42, 0x7c, 0x71, + 0x46, 0x0b, 0x55, 0xd5, 0x14, 0x10, 0xb1, 0x91, 0xbc, 0xf3, 0x09, 0xfe, + 0xa1, 0x31, 0xa9, 0x2c, 0x8e, 0x70, 0x27, 0x38, 0xfa, 0x71, 0x9f, 0x1e, + 0x00, 0x41, 0xf5, 0x2e, 0x40, 0xe9, 0x1f, 0x22, 0x9f, 0x4d, 0x96, 0xa1, + 0xe6, 0xf1, 0x72, 0xe1, 0x55, 0x96, 0xb4, 0x51, 0x0a, 0x6d, 0xae, 0xc2, + 0x61, 0x05, 0xf2, 0xbe, 0xbc, 0x53, 0x31, 0x6b, 0x87, 0xbd, 0xf2, 0x13, + 0x11, 0x66, 0x60, 0x70, 0xe8, 0xdf, 0xee, 0x69, 0xd5, 0x2c, 0x71, 0xa9, + 0x76, 0xca, 0xae, 0x79, 0xc7, 0x2b, 0x68, 0xd2, 0x85, 0x80, 0xdc, 0x68, + 0x6d, 0x9f, 0x51, 0x29, 0xd2, 0x25, 0xf8, 0x2b, 0x3d, 0x61, 0x55, 0x13, + 0xa8, 0x82, 0xb3, 0xdb, 0x91, 0x41, 0x6b, 0x48, 0xce, 0x08, 0x88, 0x82, + 0x13, 0xe3, 0x7e, 0xeb, 0x9a, 0xf8, 0x00, 0xd8, 0x1c, 0xab, 0x32, 0x8c, + 0xe4, 0x20, 0x68, 0x99, 0x03, 0xc0, 0x0c, 0x7b, 0x5f, 0xd3, 0x1b, 0x75, + 0x50, 0x3a, 0x6d, 0x41, 0x96, 0x84, 0xd6, 0x29, 0x02, 0x60, 0xf8, 0xeb, + 0x97, 0xe9, 0x8d, 0xf1, 0x26, 0x64, 0xee, 0xfd, 0xb7, 0x61, 0x59, 0x6a, + 0x69, 0xdd, 0xcd, 0x0e, 0x76, 0xda, 0xec, 0xe6, 0xed, 0x4b, 0xf5, 0xa1, + 0xb5, 0x0a, 0xc0, 0x86, 0xf7, 0x92, 0x8a, 0x4d, 0x2f, 0x87, 0x26, 0xa7, + 0x7e, 0x51, 0x5b, 0x74, 0xda, 0x41, 0x98, 0x8f, 0x22, 0x0b, 0x1c, 0xc8, + 0x7a, 0xa1, 0xfc, 0x81, 0x0c, 0xe9, 0x9a, 0x82, 0xf2, 0xd1, 0xce, 0x82, + 0x1e, 0xdc, 0xed, 0x79, 0x4c, 0x69, 0x41, 0xf4, 0x2c, 0x7a, 0x1a, 0x0b, + 0x8c, 0x4d, 0x28, 0xc7, 0x5e, 0xc6, 0x0b, 0x65, 0x22, 0x79, 0xf6, 0x15, + 0x4a, 0x76, 0x2a, 0xed, 0x16, 0x5d, 0x47, 0xde, 0xe3, 0x67, 0x02, 0x60, + 0xed, 0x4d, 0x71, 0xd0, 0xa6, 0xe2, 0x4b, 0x93, 0xc2, 0xe5, 0xf6, 0xb4, + 0xbb, 0xe0, 0x5f, 0x5f, 0xb0, 0xaf, 0xa0, 0x42, 0xd2, 0x04, 0xfe, 0x33, + 0x78, 0xd3, 0x65, 0xc2, 0xf2, 0x88, 0xb6, 0xa8, 0xda, 0xd7, 0xef, 0xe4, + 0x5d, 0x15, 0x3e, 0xef, 0x40, 0xca, 0xcc, 0x7b, 0x81, 0xff, 0x93, 0x40, + 0x02, 0xd1, 0x08, 0x99, 0x4b, 0x94, 0xa5, 0xe4, 0x72, 0x8c, 0xd9, 0xc9, + 0x63, 0x37, 0x5a, 0xe4, 0x99, 0x65, 0xbd, 0xa5, 0x5c, 0xbf, 0x0e, 0xfe, + 0xd8, 0xd6, 0x55, 0x3b, 0x40, 0x27, 0xf2, 0xd8, 0x62, 0x08, 0xa6, 0xe6, + 0xb4, 0x89, 0xc1, 0x76, 0x12, 0x80, 0x92, 0xd6, 0x29, 0xe4, 0x9d, 0x3d, + 0x02, 0x60, 0x2b, 0xb6, 0x8b, 0xdd, 0xfb, 0x0c, 0x4f, 0x56, 0xc8, 0x55, + 0x8b, 0xff, 0xaf, 0x89, 0x2d, 0x80, 0x43, 0x03, 0x78, 0x41, 0xe7, 0xfa, + 0x81, 0xcf, 0xa6, 0x1a, 0x38, 0xc5, 0xe3, 0x9b, 0x90, 0x1c, 0x8e, 0xe7, + 0x11, 0x22, 0xa5, 0xda, 0x22, 0x27, 0xbd, 0x6c, 0xde, 0xeb, 0x48, 0x14, + 0x52, 0xc1, 0x2a, 0xd3, 0xd6, 0x1d, 0x5e, 0x4f, 0x77, 0x6a, 0x0a, 0xb5, + 0x56, 0x59, 0x1b, 0xef, 0xe3, 0xe5, 0x9e, 0x5a, 0x7f, 0xdd, 0xb8, 0x34, + 0x5e, 0x1f, 0x2f, 0x35, 0xb9, 0xf4, 0xce, 0xe5, 0x7c, 0x32, 0x41, 0x4c, + 0x08, 0x6a, 0xec, 0x99, 0x3e, 0x93, 0x53, 0xe4, 0x80, 0xd9, 0xee, 0xc6, + 0x28, 0x9f, 0x02, 0x60, 0x4f, 0xf8, 0x97, 0x70, 0x9f, 0xad, 0x07, 0x97, + 0x46, 0x49, 0x45, 0x78, 0xe7, 0x0f, 0xd8, 0x54, 0x61, 0x30, 0xee, 0xab, + 0x56, 0x27, 0xc4, 0x9b, 0x08, 0x0f, 0x05, 0xee, 0x4a, 0xd9, 0xf3, 0xe4, + 0xb7, 0xcb, 0xa9, 0xd6, 0xa5, 0xdf, 0xf1, 0x13, 0xa4, 0x1c, 0x34, 0x09, + 0x33, 0x68, 0x33, 0xf1, 0x90, 0x81, 0x6d, 0x8a, 0x6b, 0xc4, 0x2e, 0x9b, + 0xec, 0x56, 0xb7, 0x56, 0x7d, 0x0f, 0x3c, 0x9c, 0x69, 0x6d, 0xb6, 0x19, + 0xb2, 0x45, 0xd9, 0x01, 0xdd, 0x85, 0x6d, 0xb7, 0xc8, 0x09, 0x2e, 0x77, + 0xe9, 0xa1, 0xcc, 0xcd, 0x56, 0xee, 0x4d, 0xba, 0x42, 0xc5, 0xfd, 0xb6, + 0x1a, 0xec, 0x26, 0x69, 0x02, 0x60, 0x77, 0xb9, 0xd1, 0x13, 0x7b, 0x50, + 0x40, 0x4a, 0x98, 0x27, 0x29, 0x31, 0x6e, 0xfa, 0xfc, 0x7d, 0xfe, 0x66, + 0xd3, 0x4e, 0x5a, 0x18, 0x26, 0x00, 0xd5, 0xf3, 0x0a, 0x0a, 0x85, 0x12, + 0x05, 0x1c, 0x56, 0x0d, 0x08, 0x1d, 0x4d, 0x0a, 0x18, 0x35, 0xec, 0x3d, + 0x25, 0xa6, 0x0f, 0x4e, 0x4d, 0x6a, 0xa9, 0x48, 0xb2, 0xbf, 0x3d, 0xbb, + 0x5b, 0x12, 0x4c, 0xbb, 0xc3, 0x48, 0x92, 0x55, 0xa3, 0xa9, 0x48, 0x37, + 0x2f, 0x69, 0x78, 0x49, 0x67, 0x45, 0xf9, 0x43, 0xe1, 0xdb, 0x4f, 0x18, + 0x38, 0x2c, 0xea, 0xa5, 0x05, 0xdf, 0xc6, 0x57, 0x57, 0xbb, 0x3f, 0x85, + 0x7a, 0x58, 0xdc, 0xe5, 0x21, 0x56}; +const uint8_t kTestVector9Spki[] = { + 0x30, 0x81, 0xdf, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, + 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x81, 0xcd, 0x00, 0x30, 0x81, + 0xc9, 0x02, 0x81, 0xc1, 0x00, 0xe6, 0xbd, 0x69, 0x2a, 0xc9, 0x66, 0x45, + 0x79, 0x04, 0x03, 0xfd, 0xd0, 0xf5, 0xbe, 0xb8, 0xb9, 0xbf, 0x92, 0xed, + 0x10, 0x00, 0x7f, 0xc3, 0x65, 0x04, 0x64, 0x19, 0xdd, 0x06, 0xc0, 0x5c, + 0x5b, 0x5b, 0x2f, 0x48, 0xec, 0xf9, 0x89, 0xe4, 0xce, 0x26, 0x91, 0x09, + 0x97, 0x9c, 0xbb, 0x40, 0xb4, 0xa0, 0xad, 0x24, 0xd2, 0x24, 0x83, 0xd1, + 0xee, 0x31, 0x5a, 0xd4, 0xcc, 0xb1, 0x53, 0x42, 0x68, 0x35, 0x26, 0x91, + 0xc5, 0x24, 0xf6, 0xdd, 0x8e, 0x6c, 0x29, 0xd2, 0x24, 0xcf, 0x24, 0x69, + 0x73, 0xae, 0xc8, 0x6c, 0x5b, 0xf6, 0xb1, 0x40, 0x1a, 0x85, 0x0d, 0x1b, + 0x9a, 0xd1, 0xbb, 0x8c, 0xbc, 0xec, 0x47, 0xb0, 0x6f, 0x0f, 0x8c, 0x7f, + 0x45, 0xd3, 0xfc, 0x8f, 0x31, 0x92, 0x99, 0xc5, 0x43, 0x3d, 0xdb, 0xc2, + 0xb3, 0x05, 0x3b, 0x47, 0xde, 0xd2, 0xec, 0xd4, 0xa4, 0xca, 0xef, 0xd6, + 0x14, 0x83, 0x3d, 0xc8, 0xbb, 0x62, 0x2f, 0x31, 0x7e, 0xd0, 0x76, 0xb8, + 0x05, 0x7f, 0xe8, 0xde, 0x3f, 0x84, 0x48, 0x0a, 0xd5, 0xe8, 0x3e, 0x4a, + 0x61, 0x90, 0x4a, 0x4f, 0x24, 0x8f, 0xb3, 0x97, 0x02, 0x73, 0x57, 0xe1, + 0xd3, 0x0e, 0x46, 0x31, 0x39, 0x81, 0x5c, 0x6f, 0xd4, 0xfd, 0x5a, 0xc5, + 0xb8, 0x17, 0x2a, 0x45, 0x23, 0x0e, 0xcb, 0x63, 0x18, 0xa0, 0x4f, 0x14, + 0x55, 0xd8, 0x4e, 0x5a, 0x8b, 0x02, 0x03, 0x01, 0x00, 0x01}; +// RSA-PSS test vectors, pss-vect.txt, Example 9.1 +const uint8_t kTestVector9Data[] = { + 0xa8, 0x8e, 0x26, 0x58, 0x55, 0xe9, 0xd7, 0xca, 0x36, 0xc6, 0x87, 0x95, + 0xf0, 0xb3, 0x1b, 0x59, 0x1c, 0xd6, 0x58, 0x7c, 0x71, 0xd0, 0x60, 0xa0, + 0xb3, 0xf7, 0xf3, 0xea, 0xef, 0x43, 0x79, 0x59, 0x22, 0x02, 0x8b, 0xc2, + 0xb6, 0xad, 0x46, 0x7c, 0xfc, 0x2d, 0x7f, 0x65, 0x9c, 0x53, 0x85, 0xaa, + 0x70, 0xba, 0x36, 0x72, 0xcd, 0xde, 0x4c, 0xfe, 0x49, 0x70, 0xcc, 0x79, + 0x04, 0x60, 0x1b, 0x27, 0x88, 0x72, 0xbf, 0x51, 0x32, 0x1c, 0x4a, 0x97, + 0x2f, 0x3c, 0x95, 0x57, 0x0f, 0x34, 0x45, 0xd4, 0xf5, 0x79, 0x80, 0xe0, + 0xf2, 0x0d, 0xf5, 0x48, 0x46, 0xe6, 0xa5, 0x2c, 0x66, 0x8f, 0x12, 0x88, + 0xc0, 0x3f, 0x95, 0x00, 0x6e, 0xa3, 0x2f, 0x56, 0x2d, 0x40, 0xd5, 0x2a, + 0xf9, 0xfe, 0xb3, 0x2f, 0x0f, 0xa0, 0x6d, 0xb6, 0x5b, 0x58, 0x8a, 0x23, + 0x7b, 0x34, 0xe5, 0x92, 0xd5, 0x5c, 0xf9, 0x79, 0xf9, 0x03, 0xa6, 0x42, + 0xef, 0x64, 0xd2, 0xed, 0x54, 0x2a, 0xa8, 0xc7, 0x7d, 0xc1, 0xdd, 0x76, + 0x2f, 0x45, 0xa5, 0x93, 0x03, 0xed, 0x75, 0xe5, 0x41, 0xca, 0x27, 0x1e, + 0x2b, 0x60, 0xca, 0x70, 0x9e, 0x44, 0xfa, 0x06, 0x61, 0x13, 0x1e, 0x8d, + 0x5d, 0x41, 0x63, 0xfd, 0x8d, 0x39, 0x85, 0x66, 0xce, 0x26, 0xde, 0x87, + 0x30, 0xe7, 0x2f, 0x9c, 0xca, 0x73, 0x76, 0x41, 0xc2, 0x44, 0x15, 0x94, + 0x20, 0x63, 0x70, 0x28, 0xdf, 0x0a, 0x18, 0x07, 0x9d, 0x62, 0x08, 0xea, + 0x8b, 0x47, 0x11, 0xa2, 0xc7, 0x50, 0xf5}; +const uint8_t kTestVector9Sig[] = { + 0x58, 0x61, 0x07, 0x22, 0x6c, 0x3c, 0xe0, 0x13, 0xa7, 0xc8, 0xf0, 0x4d, + 0x1a, 0x6a, 0x29, 0x59, 0xbb, 0x4b, 0x8e, 0x20, 0x5b, 0xa4, 0x3a, 0x27, + 0xb5, 0x0f, 0x12, 0x41, 0x11, 0xbc, 0x35, 0xef, 0x58, 0x9b, 0x03, 0x9f, + 0x59, 0x32, 0x18, 0x7c, 0xb6, 0x96, 0xd7, 0xd9, 0xa3, 0x2c, 0x0c, 0x38, + 0x30, 0x0a, 0x5c, 0xdd, 0xa4, 0x83, 0x4b, 0x62, 0xd2, 0xeb, 0x24, 0x0a, + 0xf3, 0x3f, 0x79, 0xd1, 0x3d, 0xfb, 0xf0, 0x95, 0xbf, 0x59, 0x9e, 0x0d, + 0x96, 0x86, 0x94, 0x8c, 0x19, 0x64, 0x74, 0x7b, 0x67, 0xe8, 0x9c, 0x9a, + 0xba, 0x5c, 0xd8, 0x50, 0x16, 0x23, 0x6f, 0x56, 0x6c, 0xc5, 0x80, 0x2c, + 0xb1, 0x3e, 0xad, 0x51, 0xbc, 0x7c, 0xa6, 0xbe, 0xf3, 0xb9, 0x4d, 0xcb, + 0xdb, 0xb1, 0xd5, 0x70, 0x46, 0x97, 0x71, 0xdf, 0x0e, 0x00, 0xb1, 0xa8, + 0xa0, 0x67, 0x77, 0x47, 0x2d, 0x23, 0x16, 0x27, 0x9e, 0xda, 0xe8, 0x64, + 0x74, 0x66, 0x8d, 0x4e, 0x1e, 0xff, 0xf9, 0x5f, 0x1d, 0xe6, 0x1c, 0x60, + 0x20, 0xda, 0x32, 0xae, 0x92, 0xbb, 0xf1, 0x65, 0x20, 0xfe, 0xf3, 0xcf, + 0x4d, 0x88, 0xf6, 0x11, 0x21, 0xf2, 0x4b, 0xbd, 0x9f, 0xe9, 0x1b, 0x59, + 0xca, 0xf1, 0x23, 0x5b, 0x2a, 0x93, 0xff, 0x81, 0xfc, 0x40, 0x3a, 0xdd, + 0xf4, 0xeb, 0xde, 0xa8, 0x49, 0x34, 0xa9, 0xcd, 0xaf, 0x8e, 0x1a, 0x9e}; + +// RSA-PSS test vectors, pss-vect.txt, Example 10: A 2048-bit RSA Key Pair +// <ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-1/pkcs-1v2-1-vec.zip> +const uint8_t kTestVector10Pkcs8[] = { + 0x30, 0x82, 0x04, 0xb9, 0x02, 0x01, 0x00, 0x30, 0x0d, 0x06, 0x09, 0x2a, + 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x04, 0x82, + 0x04, 0xa3, 0x30, 0x82, 0x04, 0x9f, 0x02, 0x01, 0x00, 0x02, 0x82, 0x01, + 0x00, 0xa5, 0xdd, 0x86, 0x7a, 0xc4, 0xcb, 0x02, 0xf9, 0x0b, 0x94, 0x57, + 0xd4, 0x8c, 0x14, 0xa7, 0x70, 0xef, 0x99, 0x1c, 0x56, 0xc3, 0x9c, 0x0e, + 0xc6, 0x5f, 0xd1, 0x1a, 0xfa, 0x89, 0x37, 0xce, 0xa5, 0x7b, 0x9b, 0xe7, + 0xac, 0x73, 0xb4, 0x5c, 0x00, 0x17, 0x61, 0x5b, 0x82, 0xd6, 0x22, 0xe3, + 0x18, 0x75, 0x3b, 0x60, 0x27, 0xc0, 0xfd, 0x15, 0x7b, 0xe1, 0x2f, 0x80, + 0x90, 0xfe, 0xe2, 0xa7, 0xad, 0xcd, 0x0e, 0xef, 0x75, 0x9f, 0x88, 0xba, + 0x49, 0x97, 0xc7, 0xa4, 0x2d, 0x58, 0xc9, 0xaa, 0x12, 0xcb, 0x99, 0xae, + 0x00, 0x1f, 0xe5, 0x21, 0xc1, 0x3b, 0xb5, 0x43, 0x14, 0x45, 0xa8, 0xd5, + 0xae, 0x4f, 0x5e, 0x4c, 0x7e, 0x94, 0x8a, 0xc2, 0x27, 0xd3, 0x60, 0x40, + 0x71, 0xf2, 0x0e, 0x57, 0x7e, 0x90, 0x5f, 0xbe, 0xb1, 0x5d, 0xfa, 0xf0, + 0x6d, 0x1d, 0xe5, 0xae, 0x62, 0x53, 0xd6, 0x3a, 0x6a, 0x21, 0x20, 0xb3, + 0x1a, 0x5d, 0xa5, 0xda, 0xbc, 0x95, 0x50, 0x60, 0x0e, 0x20, 0xf2, 0x7d, + 0x37, 0x39, 0xe2, 0x62, 0x79, 0x25, 0xfe, 0xa3, 0xcc, 0x50, 0x9f, 0x21, + 0xdf, 0xf0, 0x4e, 0x6e, 0xea, 0x45, 0x49, 0xc5, 0x40, 0xd6, 0x80, 0x9f, + 0xf9, 0x30, 0x7e, 0xed, 0xe9, 0x1f, 0xff, 0x58, 0x73, 0x3d, 0x83, 0x85, + 0xa2, 0x37, 0xd6, 0xd3, 0x70, 0x5a, 0x33, 0xe3, 0x91, 0x90, 0x09, 0x92, + 0x07, 0x0d, 0xf7, 0xad, 0xf1, 0x35, 0x7c, 0xf7, 0xe3, 0x70, 0x0c, 0xe3, + 0x66, 0x7d, 0xe8, 0x3f, 0x17, 0xb8, 0xdf, 0x17, 0x78, 0xdb, 0x38, 0x1d, + 0xce, 0x09, 0xcb, 0x4a, 0xd0, 0x58, 0xa5, 0x11, 0x00, 0x1a, 0x73, 0x81, + 0x98, 0xee, 0x27, 0xcf, 0x55, 0xa1, 0x3b, 0x75, 0x45, 0x39, 0x90, 0x65, + 0x82, 0xec, 0x8b, 0x17, 0x4b, 0xd5, 0x8d, 0x5d, 0x1f, 0x3d, 0x76, 0x7c, + 0x61, 0x37, 0x21, 0xae, 0x05, 0x02, 0x03, 0x01, 0x00, 0x01, 0x02, 0x82, + 0x01, 0x00, 0x2d, 0x2f, 0xf5, 0x67, 0xb3, 0xfe, 0x74, 0xe0, 0x61, 0x91, + 0xb7, 0xfd, 0xed, 0x6d, 0xe1, 0x12, 0x29, 0x0c, 0x67, 0x06, 0x92, 0x43, + 0x0d, 0x59, 0x69, 0x18, 0x40, 0x47, 0xda, 0x23, 0x4c, 0x96, 0x93, 0xde, + 0xed, 0x16, 0x73, 0xed, 0x42, 0x95, 0x39, 0xc9, 0x69, 0xd3, 0x72, 0xc0, + 0x4d, 0x6b, 0x47, 0xe0, 0xf5, 0xb8, 0xce, 0xe0, 0x84, 0x3e, 0x5c, 0x22, + 0x83, 0x5d, 0xbd, 0x3b, 0x05, 0xa0, 0x99, 0x79, 0x84, 0xae, 0x60, 0x58, + 0xb1, 0x1b, 0xc4, 0x90, 0x7c, 0xbf, 0x67, 0xed, 0x84, 0xfa, 0x9a, 0xe2, + 0x52, 0xdf, 0xb0, 0xd0, 0xcd, 0x49, 0xe6, 0x18, 0xe3, 0x5d, 0xfd, 0xfe, + 0x59, 0xbc, 0xa3, 0xdd, 0xd6, 0x6c, 0x33, 0xce, 0xbb, 0xc7, 0x7a, 0xd4, + 0x41, 0xaa, 0x69, 0x5e, 0x13, 0xe3, 0x24, 0xb5, 0x18, 0xf0, 0x1c, 0x60, + 0xf5, 0xa8, 0x5c, 0x99, 0x4a, 0xd1, 0x79, 0xf2, 0xa6, 0xb5, 0xfb, 0xe9, + 0x34, 0x02, 0xb1, 0x17, 0x67, 0xbe, 0x01, 0xbf, 0x07, 0x34, 0x44, 0xd6, + 0xba, 0x1d, 0xd2, 0xbc, 0xa5, 0xbd, 0x07, 0x4d, 0x4a, 0x5f, 0xae, 0x35, + 0x31, 0xad, 0x13, 0x03, 0xd8, 0x4b, 0x30, 0xd8, 0x97, 0x31, 0x8c, 0xbb, + 0xba, 0x04, 0xe0, 0x3c, 0x2e, 0x66, 0xde, 0x6d, 0x91, 0xf8, 0x2f, 0x96, + 0xea, 0x1d, 0x4b, 0xb5, 0x4a, 0x5a, 0xae, 0x10, 0x2d, 0x59, 0x46, 0x57, + 0xf5, 0xc9, 0x78, 0x95, 0x53, 0x51, 0x2b, 0x29, 0x6d, 0xea, 0x29, 0xd8, + 0x02, 0x31, 0x96, 0x35, 0x7e, 0x3e, 0x3a, 0x6e, 0x95, 0x8f, 0x39, 0xe3, + 0xc2, 0x34, 0x40, 0x38, 0xea, 0x60, 0x4b, 0x31, 0xed, 0xc6, 0xf0, 0xf7, + 0xff, 0x6e, 0x71, 0x81, 0xa5, 0x7c, 0x92, 0x82, 0x6a, 0x26, 0x8f, 0x86, + 0x76, 0x8e, 0x96, 0xf8, 0x78, 0x56, 0x2f, 0xc7, 0x1d, 0x85, 0xd6, 0x9e, + 0x44, 0x86, 0x12, 0xf7, 0x04, 0x8f, 0x02, 0x81, 0x80, 0xcf, 0xd5, 0x02, + 0x83, 0xfe, 0xee, 0xb9, 0x7f, 0x6f, 0x08, 0xd7, 0x3c, 0xbc, 0x7b, 0x38, + 0x36, 0xf8, 0x2b, 0xbc, 0xd4, 0x99, 0x47, 0x9f, 0x5e, 0x6f, 0x76, 0xfd, + 0xfc, 0xb8, 0xb3, 0x8c, 0x4f, 0x71, 0xdc, 0x9e, 0x88, 0xbd, 0x6a, 0x6f, + 0x76, 0x37, 0x1a, 0xfd, 0x65, 0xd2, 0xaf, 0x18, 0x62, 0xb3, 0x2a, 0xfb, + 0x34, 0xa9, 0x5f, 0x71, 0xb8, 0xb1, 0x32, 0x04, 0x3f, 0xfe, 0xbe, 0x3a, + 0x95, 0x2b, 0xaf, 0x75, 0x92, 0x44, 0x81, 0x48, 0xc0, 0x3f, 0x9c, 0x69, + 0xb1, 0xd6, 0x8e, 0x4c, 0xe5, 0xcf, 0x32, 0xc8, 0x6b, 0xaf, 0x46, 0xfe, + 0xd3, 0x01, 0xca, 0x1a, 0xb4, 0x03, 0x06, 0x9b, 0x32, 0xf4, 0x56, 0xb9, + 0x1f, 0x71, 0x89, 0x8a, 0xb0, 0x81, 0xcd, 0x8c, 0x42, 0x52, 0xef, 0x52, + 0x71, 0x91, 0x5c, 0x97, 0x94, 0xb8, 0xf2, 0x95, 0x85, 0x1d, 0xa7, 0x51, + 0x0f, 0x99, 0xcb, 0x73, 0xeb, 0x02, 0x81, 0x80, 0xcc, 0x4e, 0x90, 0xd2, + 0xa1, 0xb3, 0xa0, 0x65, 0xd3, 0xb2, 0xd1, 0xf5, 0xa8, 0xfc, 0xe3, 0x1b, + 0x54, 0x44, 0x75, 0x66, 0x4e, 0xab, 0x56, 0x1d, 0x29, 0x71, 0xb9, 0x9f, + 0xb7, 0xbe, 0xf8, 0x44, 0xe8, 0xec, 0x1f, 0x36, 0x0b, 0x8c, 0x2a, 0xc8, + 0x35, 0x96, 0x92, 0x97, 0x1e, 0xa6, 0xa3, 0x8f, 0x72, 0x3f, 0xcc, 0x21, + 0x1f, 0x5d, 0xbc, 0xb1, 0x77, 0xa0, 0xfd, 0xac, 0x51, 0x64, 0xa1, 0xd4, + 0xff, 0x7f, 0xbb, 0x4e, 0x82, 0x99, 0x86, 0x35, 0x3c, 0xb9, 0x83, 0x65, + 0x9a, 0x14, 0x8c, 0xdd, 0x42, 0x0c, 0x7d, 0x31, 0xba, 0x38, 0x22, 0xea, + 0x90, 0xa3, 0x2b, 0xe4, 0x6c, 0x03, 0x0e, 0x8c, 0x17, 0xe1, 0xfa, 0x0a, + 0xd3, 0x78, 0x59, 0xe0, 0x6b, 0x0a, 0xa6, 0xfa, 0x3b, 0x21, 0x6d, 0x9c, + 0xbe, 0x6c, 0x0e, 0x22, 0x33, 0x97, 0x69, 0xc0, 0xa6, 0x15, 0x91, 0x3e, + 0x5d, 0xa7, 0x19, 0xcf, 0x02, 0x81, 0x80, 0x1c, 0x2d, 0x1f, 0xc3, 0x2f, + 0x6b, 0xc4, 0x00, 0x4f, 0xd8, 0x5d, 0xfd, 0xe0, 0xfb, 0xbf, 0x9a, 0x4c, + 0x38, 0xf9, 0xc7, 0xc4, 0xe4, 0x1d, 0xea, 0x1a, 0xa8, 0x82, 0x34, 0xa2, + 0x01, 0xcd, 0x92, 0xf3, 0xb7, 0xda, 0x52, 0x65, 0x83, 0xa9, 0x8a, 0xd8, + 0x5b, 0xb3, 0x60, 0xfb, 0x98, 0x3b, 0x71, 0x1e, 0x23, 0x44, 0x9d, 0x56, + 0x1d, 0x17, 0x78, 0xd7, 0xa5, 0x15, 0x48, 0x6b, 0xcb, 0xf4, 0x7b, 0x46, + 0xc9, 0xe9, 0xe1, 0xa3, 0xa1, 0xf7, 0x70, 0x00, 0xef, 0xbe, 0xb0, 0x9a, + 0x8a, 0xfe, 0x47, 0xe5, 0xb8, 0x57, 0xcd, 0xa9, 0x9c, 0xb1, 0x6d, 0x7f, + 0xff, 0x9b, 0x71, 0x2e, 0x3b, 0xd6, 0x0c, 0xa9, 0x6d, 0x9c, 0x79, 0x73, + 0xd6, 0x16, 0xd4, 0x69, 0x34, 0xa9, 0xc0, 0x50, 0x28, 0x1c, 0x00, 0x43, + 0x99, 0xce, 0xff, 0x1d, 0xb7, 0xdd, 0xa7, 0x87, 0x66, 0xa8, 0xa9, 0xb9, + 0xcb, 0x08, 0x73, 0x02, 0x81, 0x80, 0xcb, 0x3b, 0x3c, 0x04, 0xca, 0xa5, + 0x8c, 0x60, 0xbe, 0x7d, 0x9b, 0x2d, 0xeb, 0xb3, 0xe3, 0x96, 0x43, 0xf4, + 0xf5, 0x73, 0x97, 0xbe, 0x08, 0x23, 0x6a, 0x1e, 0x9e, 0xaf, 0xaa, 0x70, + 0x65, 0x36, 0xe7, 0x1c, 0x3a, 0xcf, 0xe0, 0x1c, 0xc6, 0x51, 0xf2, 0x3c, + 0x9e, 0x05, 0x85, 0x8f, 0xee, 0x13, 0xbb, 0x6a, 0x8a, 0xfc, 0x47, 0xdf, + 0x4e, 0xdc, 0x9a, 0x4b, 0xa3, 0x0b, 0xce, 0xcb, 0x73, 0xd0, 0x15, 0x78, + 0x52, 0x32, 0x7e, 0xe7, 0x89, 0x01, 0x5c, 0x2e, 0x8d, 0xee, 0x7b, 0x9f, + 0x05, 0xa0, 0xf3, 0x1a, 0xc9, 0x4e, 0xb6, 0x17, 0x31, 0x64, 0x74, 0x0c, + 0x5c, 0x95, 0x14, 0x7c, 0xd5, 0xf3, 0xb5, 0xae, 0x2c, 0xb4, 0xa8, 0x37, + 0x87, 0xf0, 0x1d, 0x8a, 0xb3, 0x1f, 0x27, 0xc2, 0xd0, 0xee, 0xa2, 0xdd, + 0x8a, 0x11, 0xab, 0x90, 0x6a, 0xba, 0x20, 0x7c, 0x43, 0xc6, 0xee, 0x12, + 0x53, 0x31, 0x02, 0x81, 0x80, 0x12, 0xf6, 0xb2, 0xcf, 0x13, 0x74, 0xa7, + 0x36, 0xfa, 0xd0, 0x56, 0x16, 0x05, 0x0f, 0x96, 0xab, 0x4b, 0x61, 0xd1, + 0x17, 0x7c, 0x7f, 0x9d, 0x52, 0x5a, 0x29, 0xf3, 0xd1, 0x80, 0xe7, 0x76, + 0x67, 0xe9, 0x9d, 0x99, 0xab, 0xf0, 0x52, 0x5d, 0x07, 0x58, 0x66, 0x0f, + 0x37, 0x52, 0x65, 0x5b, 0x0f, 0x25, 0xb8, 0xdf, 0x84, 0x31, 0xd9, 0xa8, + 0xff, 0x77, 0xc1, 0x6c, 0x12, 0xa0, 0xa5, 0x12, 0x2a, 0x9f, 0x0b, 0xf7, + 0xcf, 0xd5, 0xa2, 0x66, 0xa3, 0x5c, 0x15, 0x9f, 0x99, 0x12, 0x08, 0xb9, + 0x03, 0x16, 0xff, 0x44, 0x4f, 0x3e, 0x0b, 0x6b, 0xd0, 0xe9, 0x3b, 0x8a, + 0x7a, 0x24, 0x48, 0xe9, 0x57, 0xe3, 0xdd, 0xa6, 0xcf, 0xcf, 0x22, 0x66, + 0xb1, 0x06, 0x01, 0x3a, 0xc4, 0x68, 0x08, 0xd3, 0xb3, 0x88, 0x7b, 0x3b, + 0x00, 0x34, 0x4b, 0xaa, 0xc9, 0x53, 0x0b, 0x4c, 0xe7, 0x08, 0xfc, 0x32, + 0xb6}; +const uint8_t kTestVector10Spki[] = { + 0x30, 0x82, 0x01, 0x21, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, + 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0e, 0x00, + 0x30, 0x82, 0x01, 0x09, 0x02, 0x82, 0x01, 0x00, 0xa5, 0xdd, 0x86, 0x7a, + 0xc4, 0xcb, 0x02, 0xf9, 0x0b, 0x94, 0x57, 0xd4, 0x8c, 0x14, 0xa7, 0x70, + 0xef, 0x99, 0x1c, 0x56, 0xc3, 0x9c, 0x0e, 0xc6, 0x5f, 0xd1, 0x1a, 0xfa, + 0x89, 0x37, 0xce, 0xa5, 0x7b, 0x9b, 0xe7, 0xac, 0x73, 0xb4, 0x5c, 0x00, + 0x17, 0x61, 0x5b, 0x82, 0xd6, 0x22, 0xe3, 0x18, 0x75, 0x3b, 0x60, 0x27, + 0xc0, 0xfd, 0x15, 0x7b, 0xe1, 0x2f, 0x80, 0x90, 0xfe, 0xe2, 0xa7, 0xad, + 0xcd, 0x0e, 0xef, 0x75, 0x9f, 0x88, 0xba, 0x49, 0x97, 0xc7, 0xa4, 0x2d, + 0x58, 0xc9, 0xaa, 0x12, 0xcb, 0x99, 0xae, 0x00, 0x1f, 0xe5, 0x21, 0xc1, + 0x3b, 0xb5, 0x43, 0x14, 0x45, 0xa8, 0xd5, 0xae, 0x4f, 0x5e, 0x4c, 0x7e, + 0x94, 0x8a, 0xc2, 0x27, 0xd3, 0x60, 0x40, 0x71, 0xf2, 0x0e, 0x57, 0x7e, + 0x90, 0x5f, 0xbe, 0xb1, 0x5d, 0xfa, 0xf0, 0x6d, 0x1d, 0xe5, 0xae, 0x62, + 0x53, 0xd6, 0x3a, 0x6a, 0x21, 0x20, 0xb3, 0x1a, 0x5d, 0xa5, 0xda, 0xbc, + 0x95, 0x50, 0x60, 0x0e, 0x20, 0xf2, 0x7d, 0x37, 0x39, 0xe2, 0x62, 0x79, + 0x25, 0xfe, 0xa3, 0xcc, 0x50, 0x9f, 0x21, 0xdf, 0xf0, 0x4e, 0x6e, 0xea, + 0x45, 0x49, 0xc5, 0x40, 0xd6, 0x80, 0x9f, 0xf9, 0x30, 0x7e, 0xed, 0xe9, + 0x1f, 0xff, 0x58, 0x73, 0x3d, 0x83, 0x85, 0xa2, 0x37, 0xd6, 0xd3, 0x70, + 0x5a, 0x33, 0xe3, 0x91, 0x90, 0x09, 0x92, 0x07, 0x0d, 0xf7, 0xad, 0xf1, + 0x35, 0x7c, 0xf7, 0xe3, 0x70, 0x0c, 0xe3, 0x66, 0x7d, 0xe8, 0x3f, 0x17, + 0xb8, 0xdf, 0x17, 0x78, 0xdb, 0x38, 0x1d, 0xce, 0x09, 0xcb, 0x4a, 0xd0, + 0x58, 0xa5, 0x11, 0x00, 0x1a, 0x73, 0x81, 0x98, 0xee, 0x27, 0xcf, 0x55, + 0xa1, 0x3b, 0x75, 0x45, 0x39, 0x90, 0x65, 0x82, 0xec, 0x8b, 0x17, 0x4b, + 0xd5, 0x8d, 0x5d, 0x1f, 0x3d, 0x76, 0x7c, 0x61, 0x37, 0x21, 0xae, 0x05, + 0x02, 0x03, 0x01, 0x00, 0x01}; +// RSA-PSS test vectors, pss-vect.txt, Example 10.1 +const uint8_t kTestVector10Data[] = { + 0x88, 0x31, 0x77, 0xe5, 0x12, 0x6b, 0x9b, 0xe2, 0xd9, 0xa9, + 0x68, 0x03, 0x27, 0xd5, 0x37, 0x0c, 0x6f, 0x26, 0x86, 0x1f, + 0x58, 0x20, 0xc4, 0x3d, 0xa6, 0x7a, 0x3a, 0xd6, 0x09}; +const uint8_t kTestVector10Sig[] = { + 0x82, 0xc2, 0xb1, 0x60, 0x09, 0x3b, 0x8a, 0xa3, 0xc0, 0xf7, 0x52, 0x2b, + 0x19, 0xf8, 0x73, 0x54, 0x06, 0x6c, 0x77, 0x84, 0x7a, 0xbf, 0x2a, 0x9f, + 0xce, 0x54, 0x2d, 0x0e, 0x84, 0xe9, 0x20, 0xc5, 0xaf, 0xb4, 0x9f, 0xfd, + 0xfd, 0xac, 0xe1, 0x65, 0x60, 0xee, 0x94, 0xa1, 0x36, 0x96, 0x01, 0x14, + 0x8e, 0xba, 0xd7, 0xa0, 0xe1, 0x51, 0xcf, 0x16, 0x33, 0x17, 0x91, 0xa5, + 0x72, 0x7d, 0x05, 0xf2, 0x1e, 0x74, 0xe7, 0xeb, 0x81, 0x14, 0x40, 0x20, + 0x69, 0x35, 0xd7, 0x44, 0x76, 0x5a, 0x15, 0xe7, 0x9f, 0x01, 0x5c, 0xb6, + 0x6c, 0x53, 0x2c, 0x87, 0xa6, 0xa0, 0x59, 0x61, 0xc8, 0xbf, 0xad, 0x74, + 0x1a, 0x9a, 0x66, 0x57, 0x02, 0x28, 0x94, 0x39, 0x3e, 0x72, 0x23, 0x73, + 0x97, 0x96, 0xc0, 0x2a, 0x77, 0x45, 0x5d, 0x0f, 0x55, 0x5b, 0x0e, 0xc0, + 0x1d, 0xdf, 0x25, 0x9b, 0x62, 0x07, 0xfd, 0x0f, 0xd5, 0x76, 0x14, 0xce, + 0xf1, 0xa5, 0x57, 0x3b, 0xaa, 0xff, 0x4e, 0xc0, 0x00, 0x69, 0x95, 0x16, + 0x59, 0xb8, 0x5f, 0x24, 0x30, 0x0a, 0x25, 0x16, 0x0c, 0xa8, 0x52, 0x2d, + 0xc6, 0xe6, 0x72, 0x7e, 0x57, 0xd0, 0x19, 0xd7, 0xe6, 0x36, 0x29, 0xb8, + 0xfe, 0x5e, 0x89, 0xe2, 0x5c, 0xc1, 0x5b, 0xeb, 0x3a, 0x64, 0x75, 0x77, + 0x55, 0x92, 0x99, 0x28, 0x0b, 0x9b, 0x28, 0xf7, 0x9b, 0x04, 0x09, 0x00, + 0x0b, 0xe2, 0x5b, 0xbd, 0x96, 0x40, 0x8b, 0xa3, 0xb4, 0x3c, 0xc4, 0x86, + 0x18, 0x4d, 0xd1, 0xc8, 0xe6, 0x25, 0x53, 0xfa, 0x1a, 0xf4, 0x04, 0x0f, + 0x60, 0x66, 0x3d, 0xe7, 0xf5, 0xe4, 0x9c, 0x04, 0x38, 0x8e, 0x25, 0x7f, + 0x1c, 0xe8, 0x9c, 0x95, 0xda, 0xb4, 0x8a, 0x31, 0x5d, 0x9b, 0x66, 0xb1, + 0xb7, 0x62, 0x82, 0x33, 0x87, 0x6f, 0xf2, 0x38, 0x52, 0x30, 0xd0, 0x70, + 0xd0, 0x7e, 0x16, 0x66}; + +} // namespace nss_test diff --git a/security/nss/gtests/pk11_gtest/pk11_seed_cbc_unittest.cc b/security/nss/gtests/pk11_gtest/pk11_seed_cbc_unittest.cc new file mode 100644 index 0000000000..7f389fef17 --- /dev/null +++ b/security/nss/gtests/pk11_gtest/pk11_seed_cbc_unittest.cc @@ -0,0 +1,82 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include <memory> +#include "nss.h" +#include "pk11pub.h" +#include "secerr.h" + +#include "nss_scoped_ptrs.h" +#include "gtest/gtest.h" +#include "util.h" + +namespace nss_test { +class Pkcs11SeedTest : public ::testing::Test { + protected: + void EncryptDecryptSeed(SECStatus expected, unsigned int input_size, + unsigned int output_size, + CK_MECHANISM_TYPE mech = CKM_SEED_CBC) { + // Generate a random key. + ScopedPK11SlotInfo slot(PK11_GetInternalSlot()); + ScopedPK11SymKey sym_key( + PK11_KeyGen(slot.get(), mech, nullptr, 16, nullptr)); + EXPECT_TRUE(!!sym_key); + + std::vector<uint8_t> plaintext(input_size, 0xFF); + std::vector<uint8_t> init_vector(16); + std::vector<uint8_t> ciphertext(output_size, 0); + SECItem iv_param = {siBuffer, init_vector.data(), + (unsigned int)init_vector.size()}; + std::vector<uint8_t> decrypted(output_size, 0); + + // Try to encrypt, decrypt if positive test. + unsigned int output_len = 0; + EXPECT_EQ(expected, + PK11_Encrypt(sym_key.get(), mech, &iv_param, ciphertext.data(), + &output_len, output_size, plaintext.data(), + plaintext.size())); + + if (expected == SECSuccess) { + EXPECT_EQ(expected, + PK11_Decrypt(sym_key.get(), mech, &iv_param, decrypted.data(), + &output_len, output_size, ciphertext.data(), + output_len)); + decrypted.resize(output_len); + EXPECT_EQ(plaintext, decrypted); + } + } +}; + +#ifndef NSS_DISABLE_DEPRECATED_SEED +// The intention here is to test the arguments of these functions +// The resulted content is already tested in EncryptDeriveTests. +// SEED_CBC needs an IV of 16 bytes. +// The input data size must be multiple of 16. +// If not, some padding should be added. +// The output size must be at least the size of input data. +TEST_F(Pkcs11SeedTest, CBC_ValidArgs) { + EncryptDecryptSeed(SECSuccess, 16, 16); + // No problem if maxLen is bigger than input data. + EncryptDecryptSeed(SECSuccess, 16, 32); +} + +TEST_F(Pkcs11SeedTest, CBC_InvalidArgs) { + // maxLen lower than input data. + EncryptDecryptSeed(SECFailure, 16, 10); + // input data not multiple of SEED_BLOCK_SIZE (16) + EncryptDecryptSeed(SECFailure, 17, 32); +} + +TEST_F(Pkcs11SeedTest, ECB_Singleblock) { + EncryptDecryptSeed(SECSuccess, 16, 16, CKM_SEED_ECB); +} + +TEST_F(Pkcs11SeedTest, ECB_Multiblock) { + EncryptDecryptSeed(SECSuccess, 64, 64, CKM_SEED_ECB); +} +#endif + +} // namespace nss_test diff --git a/security/nss/gtests/pk11_gtest/pk11_signature_test.h b/security/nss/gtests/pk11_gtest/pk11_signature_test.h new file mode 100644 index 0000000000..cd46f17d74 --- /dev/null +++ b/security/nss/gtests/pk11_gtest/pk11_signature_test.h @@ -0,0 +1,139 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include <memory> +#include "nss.h" +#include "pk11pub.h" +#include "sechash.h" + +#include "cpputil.h" +#include "nss_scoped_ptrs.h" +#include "databuffer.h" + +#include "gtest/gtest.h" + +namespace nss_test { + +// For test vectors. +struct Pkcs11SignatureTestParams { + const DataBuffer pkcs8_; + const DataBuffer spki_; + const DataBuffer data_; + const DataBuffer signature_; +}; + +class Pk11SignatureTest : public ::testing::Test { + protected: + Pk11SignatureTest(CK_MECHANISM_TYPE mech, SECOidTag hash_oid) + : mechanism_(mech), hash_oid_(hash_oid) {} + + virtual const SECItem* parameters() const { return nullptr; } + CK_MECHANISM_TYPE mechanism() const { return mechanism_; } + + ScopedSECKEYPrivateKey ImportPrivateKey(const DataBuffer& pkcs8) { + ScopedPK11SlotInfo slot(PK11_GetInternalSlot()); + if (!slot) { + ADD_FAILURE() << "No slot"; + return nullptr; + } + + SECItem pkcs8Item = {siBuffer, toUcharPtr(pkcs8.data()), + static_cast<unsigned int>(pkcs8.len())}; + + SECKEYPrivateKey* key = nullptr; + SECStatus rv = PK11_ImportDERPrivateKeyInfoAndReturnKey( + slot.get(), &pkcs8Item, nullptr, nullptr, false, false, KU_ALL, &key, + nullptr); + + if (rv != SECSuccess) { + return nullptr; + } + + return ScopedSECKEYPrivateKey(key); + } + + ScopedSECKEYPublicKey ImportPublicKey(const DataBuffer& spki) { + SECItem spkiItem = {siBuffer, toUcharPtr(spki.data()), + static_cast<unsigned int>(spki.len())}; + + ScopedCERTSubjectPublicKeyInfo certSpki( + SECKEY_DecodeDERSubjectPublicKeyInfo(&spkiItem)); + if (!certSpki) { + return nullptr; + } + + return ScopedSECKEYPublicKey(SECKEY_ExtractPublicKey(certSpki.get())); + } + + bool ComputeHash(const DataBuffer& data, DataBuffer* hash) { + hash->Allocate(static_cast<size_t>(HASH_ResultLenByOidTag(hash_oid_))); + SECStatus rv = + PK11_HashBuf(hash_oid_, hash->data(), data.data(), data.len()); + return rv == SECSuccess; + } + + bool SignHashedData(ScopedSECKEYPrivateKey& privKey, const DataBuffer& hash, + DataBuffer* sig) { + SECItem hashItem = {siBuffer, toUcharPtr(hash.data()), + static_cast<unsigned int>(hash.len())}; + int sigLen = PK11_SignatureLen(privKey.get()); + EXPECT_LT(0, sigLen); + sig->Allocate(static_cast<size_t>(sigLen)); + SECItem sigItem = {siBuffer, toUcharPtr(sig->data()), + static_cast<unsigned int>(sig->len())}; + SECStatus rv = PK11_SignWithMechanism(privKey.get(), mechanism_, + parameters(), &sigItem, &hashItem); + return rv == SECSuccess; + } + + bool ImportPrivateKeyAndSignHashedData(const DataBuffer& pkcs8, + const DataBuffer& data, + DataBuffer* sig) { + ScopedSECKEYPrivateKey privKey(ImportPrivateKey(pkcs8)); + if (!privKey) { + return false; + } + + DataBuffer hash; + if (!ComputeHash(data, &hash)) { + ADD_FAILURE() << "Failed to compute hash"; + return false; + } + return SignHashedData(privKey, hash, sig); + } + + void Verify(const Pkcs11SignatureTestParams& params, const DataBuffer& sig) { + ScopedSECKEYPublicKey pubKey(ImportPublicKey(params.spki_)); + ASSERT_TRUE(pubKey); + + DataBuffer hash; + ASSERT_TRUE(ComputeHash(params.data_, &hash)); + + // Verify. + SECItem hashItem = {siBuffer, toUcharPtr(hash.data()), + static_cast<unsigned int>(hash.len())}; + SECItem sigItem = {siBuffer, toUcharPtr(sig.data()), + static_cast<unsigned int>(sig.len())}; + SECStatus rv = PK11_VerifyWithMechanism( + pubKey.get(), mechanism_, parameters(), &sigItem, &hashItem, nullptr); + EXPECT_EQ(rv, SECSuccess); + } + + void Verify(const Pkcs11SignatureTestParams& params) { + Verify(params, params.signature_); + } + + void SignAndVerify(const Pkcs11SignatureTestParams& params) { + DataBuffer sig; + ASSERT_TRUE( + ImportPrivateKeyAndSignHashedData(params.pkcs8_, params.data_, &sig)); + Verify(params, sig); + } + + private: + CK_MECHANISM_TYPE mechanism_; + SECOidTag hash_oid_; +}; + +} // namespace nss_test |