summaryrefslogtreecommitdiffstats
path: root/security/nss/gtests/pk11_gtest
diff options
context:
space:
mode:
Diffstat (limited to 'security/nss/gtests/pk11_gtest')
-rw-r--r--security/nss/gtests/pk11_gtest/Makefile43
-rw-r--r--security/nss/gtests/pk11_gtest/manifest.mn57
-rw-r--r--security/nss/gtests/pk11_gtest/pk11_aes_cmac_unittest.cc130
-rw-r--r--security/nss/gtests/pk11_gtest/pk11_aes_gcm_unittest.cc428
-rw-r--r--security/nss/gtests/pk11_gtest/pk11_aeskeywrap_unittest.cc122
-rw-r--r--security/nss/gtests/pk11_gtest/pk11_aeskeywrapkwp_unittest.cc123
-rw-r--r--security/nss/gtests/pk11_gtest/pk11_aeskeywrappad_unittest.cc423
-rw-r--r--security/nss/gtests/pk11_gtest/pk11_cbc_unittest.cc608
-rw-r--r--security/nss/gtests/pk11_gtest/pk11_chacha20poly1305_unittest.cc491
-rw-r--r--security/nss/gtests/pk11_gtest/pk11_cipherop_unittest.cc129
-rw-r--r--security/nss/gtests/pk11_gtest/pk11_curve25519_unittest.cc126
-rw-r--r--security/nss/gtests/pk11_gtest/pk11_der_private_key_import_unittest.cc162
-rw-r--r--security/nss/gtests/pk11_gtest/pk11_des_unittest.cc65
-rw-r--r--security/nss/gtests/pk11_gtest/pk11_dsa_unittest.cc79
-rw-r--r--security/nss/gtests/pk11_gtest/pk11_ecdh_unittest.cc86
-rw-r--r--security/nss/gtests/pk11_gtest/pk11_ecdsa_unittest.cc223
-rw-r--r--security/nss/gtests/pk11_gtest/pk11_ecdsa_vectors.h283
-rw-r--r--security/nss/gtests/pk11_gtest/pk11_encrypt_derive_unittest.cc225
-rw-r--r--security/nss/gtests/pk11_gtest/pk11_export_unittest.cc66
-rw-r--r--security/nss/gtests/pk11_gtest/pk11_find_certs_unittest.cc626
-rw-r--r--security/nss/gtests/pk11_gtest/pk11_gtest.gyp87
-rw-r--r--security/nss/gtests/pk11_gtest/pk11_hkdf_unittest.cc199
-rw-r--r--security/nss/gtests/pk11_gtest/pk11_hmac_unittest.cc74
-rw-r--r--security/nss/gtests/pk11_gtest/pk11_hpke_unittest.cc547
-rw-r--r--security/nss/gtests/pk11_gtest/pk11_ike_unittest.cc197
-rw-r--r--security/nss/gtests/pk11_gtest/pk11_import_unittest.cc281
-rw-r--r--security/nss/gtests/pk11_gtest/pk11_kbkdf.cc136
-rw-r--r--security/nss/gtests/pk11_gtest/pk11_key_unittest.cc80
-rw-r--r--security/nss/gtests/pk11_gtest/pk11_keygen.cc143
-rw-r--r--security/nss/gtests/pk11_gtest/pk11_keygen.h34
-rw-r--r--security/nss/gtests/pk11_gtest/pk11_module_unittest.cc84
-rw-r--r--security/nss/gtests/pk11_gtest/pk11_pbkdf2_unittest.cc184
-rw-r--r--security/nss/gtests/pk11_gtest/pk11_prf_unittest.cc227
-rw-r--r--security/nss/gtests/pk11_gtest/pk11_prng_unittest.cc121
-rw-r--r--security/nss/gtests/pk11_gtest/pk11_rsaencrypt_unittest.cc130
-rw-r--r--security/nss/gtests/pk11_gtest/pk11_rsaoaep_unittest.cc203
-rw-r--r--security/nss/gtests/pk11_gtest/pk11_rsapkcs1_unittest.cc251
-rw-r--r--security/nss/gtests/pk11_gtest/pk11_rsapss_unittest.cc259
-rw-r--r--security/nss/gtests/pk11_gtest/pk11_rsapss_vectors.h1083
-rw-r--r--security/nss/gtests/pk11_gtest/pk11_seed_cbc_unittest.cc82
-rw-r--r--security/nss/gtests/pk11_gtest/pk11_signature_test.h139
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, &params, 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, &params, 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, &params, 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, &params, 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, &params, 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, &params, 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, &params, 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, &param, 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, &param, 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, &param, 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, &param, 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, &param, encrypted, &encrypted_len,
+ sizeof(encrypted), kInput, input_len);
+ EXPECT_EQ(SECFailure, rv);
+
+ param.len++;
+ rv = PK11_Encrypt(key.get(), CKM_AES_CBC, &param, 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, &param, encrypted, &encrypted_len,
+ sizeof(encrypted), kInput, input_len);
+ EXPECT_EQ(SECFailure, rv);
+
+ param.len++;
+ rv = PK11_Encrypt(key.get(), CKM_AES_CTS, &param, 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, &params, 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, &params, 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, &params, 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, &params, 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, &params, 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, &params, 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, &params, 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, &params, 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, &params, 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*>(&param),
+ sizeof(CK_AES_CTR_PARAMS)};
+
+ key = PK11_ImportSymKey(slot, cipher, PK11_OriginUnwrap, CKA_ENCRYPT,
+ &keyItem, NULL);
+ ctx = PK11_CreateContextBySymKey(cipher, CKA_ENCRYPT, key, &paramItem);
+ 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, &params, 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 &param;
+ }
+
+ 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 &param;
+ }
+
+ 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, &params,
+ 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, &params_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, &params_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, &paramsItem,
+ 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 &params_; }
+
+ 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 &params_; }
+
+ 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, &params_, 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, &params_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, &param,
+ 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, &param, 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, &params,
+ &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 &params_; }
+
+ 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(), &params, &sig, &data);
+ EXPECT_EQ(rv, SECSuccess);
+
+ // Verify.
+ rv = PK11_VerifyWithMechanism(pub_key.get(), mechanism(), &params, &sig,
+ &data, nullptr);
+ EXPECT_EQ(rv, SECSuccess);
+
+ // Verification with modified data must fail.
+ data.data[0] ^= 0xff;
+ rv = PK11_VerifyWithMechanism(pub_key.get(), mechanism(), &params, &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(), &params, &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