summaryrefslogtreecommitdiffstats
path: root/security/nss/gtests/pk11_gtest
diff options
context:
space:
mode:
authorMoonchild <moonchild@palemoon.org>2020-12-23 19:02:52 +0000
committerMoonchild <moonchild@palemoon.org>2020-12-23 19:02:52 +0000
commit029bcfe189eae5eebbaf58ccff4e1200dd78b228 (patch)
tree1c226a334ea1a88e2d1c6f949c9320eb0c3bff59 /security/nss/gtests/pk11_gtest
parent149d2ffa779826cb48a381099858e76e4624d471 (diff)
downloadUXP-029bcfe189eae5eebbaf58ccff4e1200dd78b228.tar
UXP-029bcfe189eae5eebbaf58ccff4e1200dd78b228.tar.gz
UXP-029bcfe189eae5eebbaf58ccff4e1200dd78b228.tar.lz
UXP-029bcfe189eae5eebbaf58ccff4e1200dd78b228.tar.xz
UXP-029bcfe189eae5eebbaf58ccff4e1200dd78b228.zip
Issue #1693 - Update NSS to 3.59.1.1
This updates to MoonchildProductions/NSS@bd49b2b88 in the repo created for our consumption of the library.
Diffstat (limited to 'security/nss/gtests/pk11_gtest')
-rw-r--r--security/nss/gtests/pk11_gtest/manifest.mn9
-rw-r--r--security/nss/gtests/pk11_gtest/pk11_aes_cmac_unittest.cc44
-rw-r--r--security/nss/gtests/pk11_gtest/pk11_aes_gcm_unittest.cc286
-rw-r--r--security/nss/gtests/pk11_gtest/pk11_aeskeywrap_unittest.cc1
-rw-r--r--security/nss/gtests/pk11_gtest/pk11_aeskeywrapkwp_unittest.cc123
-rw-r--r--security/nss/gtests/pk11_gtest/pk11_aeskeywrappad_unittest.cc1
-rw-r--r--security/nss/gtests/pk11_gtest/pk11_cbc_unittest.cc71
-rw-r--r--security/nss/gtests/pk11_gtest/pk11_chacha20poly1305_unittest.cc220
-rw-r--r--security/nss/gtests/pk11_gtest/pk11_cipherop_unittest.cc49
-rw-r--r--security/nss/gtests/pk11_gtest/pk11_curve25519_unittest.cc4
-rw-r--r--security/nss/gtests/pk11_gtest/pk11_der_private_key_import_unittest.cc1
-rw-r--r--security/nss/gtests/pk11_gtest/pk11_des_unittest.cc1
-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.cc48
-rw-r--r--security/nss/gtests/pk11_gtest/pk11_encrypt_derive_unittest.cc19
-rw-r--r--security/nss/gtests/pk11_gtest/pk11_export_unittest.cc1
-rw-r--r--security/nss/gtests/pk11_gtest/pk11_find_certs_unittest.cc244
-rw-r--r--security/nss/gtests/pk11_gtest/pk11_gtest.gyp9
-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_import_unittest.cc1
-rw-r--r--security/nss/gtests/pk11_gtest/pk11_kbkdf.cc136
-rw-r--r--security/nss/gtests/pk11_gtest/pk11_module_unittest.cc1
-rw-r--r--security/nss/gtests/pk11_gtest/pk11_pbkdf2_unittest.cc49
-rw-r--r--security/nss/gtests/pk11_gtest/pk11_prf_unittest.cc1
-rw-r--r--security/nss/gtests/pk11_gtest/pk11_prng_unittest.cc1
-rw-r--r--security/nss/gtests/pk11_gtest/pk11_rsaencrypt_unittest.cc127
-rw-r--r--security/nss/gtests/pk11_gtest/pk11_rsaoaep_unittest.cc186
-rw-r--r--security/nss/gtests/pk11_gtest/pk11_rsapkcs1_unittest.cc279
-rw-r--r--security/nss/gtests/pk11_gtest/pk11_rsapss_unittest.cc144
-rw-r--r--security/nss/gtests/pk11_gtest/pk11_seed_cbc_unittest.cc70
33 files changed, 2856 insertions, 255 deletions
diff --git a/security/nss/gtests/pk11_gtest/manifest.mn b/security/nss/gtests/pk11_gtest/manifest.mn
index 1c0ae6921..f560d9eb1 100644
--- a/security/nss/gtests/pk11_gtest/manifest.mn
+++ b/security/nss/gtests/pk11_gtest/manifest.mn
@@ -9,23 +9,32 @@ 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_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 \
diff --git a/security/nss/gtests/pk11_gtest/pk11_aes_cmac_unittest.cc b/security/nss/gtests/pk11_gtest/pk11_aes_cmac_unittest.cc
index 962423406..45e4cac1a 100644
--- a/security/nss/gtests/pk11_gtest/pk11_aes_cmac_unittest.cc
+++ b/security/nss/gtests/pk11_gtest/pk11_aes_cmac_unittest.cc
@@ -1,4 +1,5 @@
/* -*- 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/. */
@@ -13,11 +14,12 @@
#include "gtest/gtest.h"
#include "nss_scoped_ptrs.h"
+#include "testvectors/cmac-vectors.h"
#include "util.h"
namespace nss_test {
-class Pkcs11AesCmacTest : public ::testing::Test {
+class Pkcs11AesCmacTest : public ::testing::TestWithParam<AesCmacTestVector> {
protected:
ScopedPK11SymKey ImportKey(CK_MECHANISM_TYPE mech, SECItem *key_item) {
ScopedPK11SlotInfo slot(PK11_GetInternalSlot());
@@ -53,8 +55,46 @@ class Pkcs11AesCmacTest : public ::testing::Test {
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_CASE_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
@@ -87,4 +127,4 @@ TEST_F(Pkcs11AesCmacTest, InvalidKeySize) {
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
index f5025fa14..5396bf6e9 100644
--- a/security/nss/gtests/pk11_gtest/pk11_aes_gcm_unittest.cc
+++ b/security/nss/gtests/pk11_gtest/pk11_aes_gcm_unittest.cc
@@ -1,4 +1,5 @@
/* -*- 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/. */
@@ -6,6 +7,7 @@
#include <memory>
#include "nss.h"
#include "pk11pub.h"
+#include "pk11priv.h"
#include "secerr.h"
#include "sechash.h"
@@ -17,26 +19,24 @@
namespace nss_test {
-class Pkcs11AesGcmTest : public ::testing::TestWithParam<gcm_kat_value> {
+class Pkcs11AesGcmTest : public ::testing::TestWithParam<AesGcmKatValue> {
protected:
- void RunTest(const gcm_kat_value val) {
- std::vector<uint8_t> key = hex_string_to_bytes(val.key);
- std::vector<uint8_t> iv = hex_string_to_bytes(val.iv);
- std::vector<uint8_t> plaintext = hex_string_to_bytes(val.plaintext);
- std::vector<uint8_t> aad = hex_string_to_bytes(val.additional_data);
- std::vector<uint8_t> result = hex_string_to_bytes(val.result);
- bool invalid_ct = val.invalid_ct;
- bool invalid_iv = val.invalid_iv;
- std::stringstream s;
- s << "Test #" << val.test_id << " failed.";
- std::string msg = s.str();
+ 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_GCM_PARAMS gcm_params;
+ CK_NSS_GCM_PARAMS gcm_params;
gcm_params.pIv = iv.data();
gcm_params.ulIvLen = iv.size();
gcm_params.pAAD = aad.data();
@@ -125,7 +125,7 @@ class Pkcs11AesGcmTest : public ::testing::TestWithParam<gcm_kat_value> {
std::vector<uint8_t> aad(0);
// Prepare AEAD params.
- CK_GCM_PARAMS gcm_params;
+ CK_NSS_GCM_PARAMS gcm_params;
gcm_params.pIv = iv.data();
gcm_params.ulIvLen = iv.size();
gcm_params.pAAD = aad.data();
@@ -141,6 +141,211 @@ class Pkcs11AesGcmTest : public ::testing::TestWithParam<gcm_kat_value> {
&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;
};
@@ -167,4 +372,57 @@ TEST_F(Pkcs11AesGcmTest, TwelveByteZeroIV) {
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
index c2c60f4a9..0aa711dc8 100644
--- a/security/nss/gtests/pk11_gtest/pk11_aeskeywrap_unittest.cc
+++ b/security/nss/gtests/pk11_gtest/pk11_aeskeywrap_unittest.cc
@@ -1,4 +1,5 @@
/* -*- 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/. */
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 000000000..42cd0b36a
--- /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_CASE_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
index 75078fb77..0f79abed5 100644
--- a/security/nss/gtests/pk11_gtest/pk11_aeskeywrappad_unittest.cc
+++ b/security/nss/gtests/pk11_gtest/pk11_aeskeywrappad_unittest.cc
@@ -1,4 +1,5 @@
/* -*- 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/. */
diff --git a/security/nss/gtests/pk11_gtest/pk11_cbc_unittest.cc b/security/nss/gtests/pk11_gtest/pk11_cbc_unittest.cc
index 1e4aa2faf..7f950422f 100644
--- a/security/nss/gtests/pk11_gtest/pk11_cbc_unittest.cc
+++ b/security/nss/gtests/pk11_gtest/pk11_cbc_unittest.cc
@@ -1,4 +1,5 @@
/* -*- 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/. */
@@ -8,8 +9,10 @@
#include "pk11pub.h"
#include "secerr.h"
-#include "nss_scoped_ptrs.h"
#include "gtest/gtest.h"
+#include "nss_scoped_ptrs.h"
+#include "testvectors/cbc-vectors.h"
+#include "util.h"
namespace nss_test {
@@ -253,8 +256,8 @@ TEST_F(Pkcs11CbcPadTest, FailEncryptShortParam) {
unsigned int encrypted_len = 0;
size_t input_len = AES_BLOCK_SIZE;
- // CK_GCM_PARAMS is the largest param struct used across AES modes
- uint8_t param_buf[sizeof(CK_GCM_PARAMS)];
+ // 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};
@@ -278,18 +281,18 @@ TEST_F(Pkcs11CbcPadTest, FailEncryptShortParam) {
sizeof(encrypted), kInput, input_len);
EXPECT_EQ(SECSuccess, rv);
- // GCM should have a CK_GCM_PARAMS
- param.len = sizeof(CK_GCM_PARAMS) - 1;
+ // 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_GCM_PARAMS*>(param.data)->pIv = param_buf;
- reinterpret_cast<CK_GCM_PARAMS*>(param.data)->ulIvLen = 12;
- reinterpret_cast<CK_GCM_PARAMS*>(param.data)->pAAD = nullptr;
- reinterpret_cast<CK_GCM_PARAMS*>(param.data)->ulAADLen = 0;
- reinterpret_cast<CK_GCM_PARAMS*>(param.data)->ulTagBits = 128;
+ 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);
@@ -554,4 +557,52 @@ INSTANTIATE_TEST_CASE_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_CASE_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
index 00d5e5244..3ea17678d 100644
--- a/security/nss/gtests/pk11_gtest/pk11_chacha20poly1305_unittest.cc
+++ b/security/nss/gtests/pk11_gtest/pk11_chacha20poly1305_unittest.cc
@@ -1,4 +1,5 @@
/* -*- 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/. */
@@ -6,6 +7,7 @@
#include <memory>
#include "nss.h"
#include "pk11pub.h"
+#include "pk11priv.h"
#include "sechash.h"
#include "secerr.h"
@@ -25,7 +27,7 @@ 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 ::testing::TestWithParam<ChaChaTestVector> {
public:
void EncryptDecrypt(const ScopedPK11SymKey& key, const bool invalid_iv,
const bool invalid_tag, const uint8_t* data,
@@ -43,7 +45,7 @@ class Pkcs11ChaCha20Poly1305Test
SECItem params = {siBuffer, reinterpret_cast<unsigned char*>(&aead_params),
sizeof(aead_params)};
- // Encrypt with bad parameters.
+ // 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;
@@ -52,9 +54,16 @@ class Pkcs11ChaCha20Poly1305Test
&encrypted_len, encrypted.size(), data, data_len);
EXPECT_EQ(SECFailure, rv);
EXPECT_EQ(0U, encrypted_len);
- aead_params.ulTagLen = 16;
+
+ // 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);
@@ -73,6 +82,7 @@ class Pkcs11ChaCha20Poly1305Test
// 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);
}
@@ -166,10 +176,10 @@ class Pkcs11ChaCha20Poly1305Test
}
}
- void EncryptDecrypt(const chaChaTestVector testvector) {
+ void EncryptDecrypt(const ChaChaTestVector testvector) {
ScopedPK11SlotInfo slot(PK11_GetInternalSlot());
- SECItem keyItem = {siBuffer, toUcharPtr(testvector.Key.data()),
- static_cast<unsigned int>(testvector.Key.size())};
+ 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,
@@ -177,11 +187,173 @@ class Pkcs11ChaCha20Poly1305Test
EXPECT_TRUE(!!key);
// Check.
- EncryptDecrypt(key, testvector.invalidIV, testvector.invalidTag,
- testvector.Data.data(), testvector.Data.size(),
- testvector.AAD.data(), testvector.AAD.size(),
- testvector.IV.data(), testvector.IV.size(),
- testvector.CT.data(), testvector.CT.size());
+ 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:
@@ -260,13 +432,16 @@ TEST_F(Pkcs11ChaCha20Poly1305Test, GenerateXor) {
ScopedPK11SymKey key(PK11_KeyGen(slot.get(), kMech, nullptr, 32, nullptr));
EXPECT_TRUE(!!key);
- SECItem ctrNonceItem = {siBuffer, toUcharPtr(kCtrNonce),
- static_cast<unsigned int>(sizeof(kCtrNonce))};
+ 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.
- SECStatus rv =
- PK11_Encrypt(key.get(), kMechXor, &ctrNonceItem, encrypted,
- &encrypted_len, sizeof(encrypted), kData, sizeof(kData));
+ 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));
}
@@ -300,4 +475,17 @@ INSTANTIATE_TEST_CASE_P(NSSTestVector, Pkcs11ChaCha20Poly1305Test,
INSTANTIATE_TEST_CASE_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
index 38982fd88..700750cc9 100644
--- a/security/nss/gtests/pk11_gtest/pk11_cipherop_unittest.cc
+++ b/security/nss/gtests/pk11_gtest/pk11_cipherop_unittest.cc
@@ -77,4 +77,53 @@ TEST(Pkcs11CipherOp, SingleCtxMultipleUnalignedCipherOps) {
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
index 647e3a706..b26e5d41e 100644
--- a/security/nss/gtests/pk11_gtest/pk11_curve25519_unittest.cc
+++ b/security/nss/gtests/pk11_gtest/pk11_curve25519_unittest.cc
@@ -15,7 +15,7 @@
namespace nss_test {
class Pkcs11Curve25519Test
- : public ::testing::TestWithParam<curve25519_testvector> {
+ : 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,
@@ -107,7 +107,7 @@ class Pkcs11Curve25519Test
}
};
- void Derive(const curve25519_testvector testvector) {
+ 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(),
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
index 0c524233d..449e7728b 100644
--- 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
@@ -1,4 +1,5 @@
/* -*- 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/. */
diff --git a/security/nss/gtests/pk11_gtest/pk11_des_unittest.cc b/security/nss/gtests/pk11_gtest/pk11_des_unittest.cc
index afb560ce1..30f1afb8d 100644
--- a/security/nss/gtests/pk11_gtest/pk11_des_unittest.cc
+++ b/security/nss/gtests/pk11_gtest/pk11_des_unittest.cc
@@ -1,4 +1,5 @@
/* -*- 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/. */
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 000000000..9d6c8c856
--- /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_CASE_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 000000000..959295c14
--- /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_CASE_P(WycheproofP256EcdhTest, Pkcs11EcdhTest,
+ ::testing::ValuesIn(kP256EcdhWycheproofVectors));
+INSTANTIATE_TEST_CASE_P(WycheproofP384EcdhTest, Pkcs11EcdhTest,
+ ::testing::ValuesIn(kP384EcdhWycheproofVectors));
+INSTANTIATE_TEST_CASE_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
index 1816e3c9c..83ac47306 100644
--- a/security/nss/gtests/pk11_gtest/pk11_ecdsa_unittest.cc
+++ b/security/nss/gtests/pk11_gtest/pk11_ecdsa_unittest.cc
@@ -6,12 +6,16 @@
#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 {
@@ -172,4 +176,48 @@ TEST_F(Pkcs11EcdsaSha256Test, ImportSpkiPointNotOnCurve) {
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_CASE_P(WycheproofP256SignatureSha256Test,
+ Pkcs11EcdsaWycheproofTest,
+ ::testing::ValuesIn(kP256EcdsaSha256Vectors));
+
+INSTANTIATE_TEST_CASE_P(WycheproofP384SignatureSha384Test,
+ Pkcs11EcdsaWycheproofTest,
+ ::testing::ValuesIn(kP384EcdsaSha384Vectors));
+
+INSTANTIATE_TEST_CASE_P(WycheproofP521SignatureSha512Test,
+ Pkcs11EcdsaWycheproofTest,
+ ::testing::ValuesIn(kP521EcdsaSha512Vectors));
+
} // 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
index f4accac02..139346559 100644
--- a/security/nss/gtests/pk11_gtest/pk11_encrypt_derive_unittest.cc
+++ b/security/nss/gtests/pk11_gtest/pk11_encrypt_derive_unittest.cc
@@ -72,10 +72,12 @@ class EncryptDeriveTest
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;
@@ -93,7 +95,9 @@ class EncryptDeriveTest
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);
@@ -110,7 +114,9 @@ class EncryptDeriveTest
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());
@@ -132,14 +138,18 @@ class EncryptDeriveTest
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;
@@ -186,8 +196,13 @@ class EncryptDeriveTest
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, CKM_SEED_ECB, CKM_SEED_CBC};
+ 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_CASE_P(EncryptDeriveTests, EncryptDeriveTest,
::testing::ValuesIn(kEncryptDeriveMechanisms));
diff --git a/security/nss/gtests/pk11_gtest/pk11_export_unittest.cc b/security/nss/gtests/pk11_gtest/pk11_export_unittest.cc
index caf1e6265..bfd65b952 100644
--- a/security/nss/gtests/pk11_gtest/pk11_export_unittest.cc
+++ b/security/nss/gtests/pk11_gtest/pk11_export_unittest.cc
@@ -1,4 +1,5 @@
/* -*- 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/. */
diff --git a/security/nss/gtests/pk11_gtest/pk11_find_certs_unittest.cc b/security/nss/gtests/pk11_gtest/pk11_find_certs_unittest.cc
index cfe87020b..9f6baf178 100644
--- a/security/nss/gtests/pk11_gtest/pk11_find_certs_unittest.cc
+++ b/security/nss/gtests/pk11_gtest/pk11_find_certs_unittest.cc
@@ -1,4 +1,5 @@
/* -*- 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/. */
@@ -141,11 +142,11 @@ class PK11FindCertsTestBase : public ::testing::Test {
mod_spec.append(test_name);
mod_spec.append("'");
m_slot = SECMOD_OpenUserDB(mod_spec.c_str());
- ASSERT_NE(m_slot, nullptr);
+ ASSERT_NE(nullptr, m_slot);
}
virtual void TearDown() {
- ASSERT_EQ(SECMOD_CloseUserDB(m_slot), SECSuccess);
+ 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()));
@@ -158,6 +159,41 @@ class PK11FindCertsTestBase : public ::testing::Test {
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) {
@@ -167,8 +203,8 @@ TEST_F(PK11FindRawCertsBySubjectTest, TestNoCertsImportedNoCertsFound) {
CERTCertificateList* certificates = nullptr;
SECStatus rv =
PK11_FindRawCertsWithSubject(m_slot, &subject_item, &certificates);
- EXPECT_EQ(rv, SECSuccess);
- EXPECT_EQ(certificates, nullptr);
+ EXPECT_EQ(SECSuccess, rv);
+ EXPECT_EQ(nullptr, certificates);
}
// If we have one certificate but it has an unrelated subject DN, we shouldn't
@@ -178,9 +214,9 @@ TEST_F(PK11FindRawCertsBySubjectTest, TestOneCertImportedNoCertsFound) {
SECItem cert_item = {siBuffer,
const_cast<unsigned char*>(kUnrelatedTestCertDER.data()),
(unsigned int)kUnrelatedTestCertDER.size()};
- ASSERT_EQ(PK11_ImportDERCert(m_slot, &cert_item, CK_INVALID_HANDLE,
- cert_nickname, false),
- SECSuccess);
+ 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()),
@@ -188,8 +224,8 @@ TEST_F(PK11FindRawCertsBySubjectTest, TestOneCertImportedNoCertsFound) {
CERTCertificateList* certificates = nullptr;
SECStatus rv =
PK11_FindRawCertsWithSubject(m_slot, &subject_item, &certificates);
- EXPECT_EQ(rv, SECSuccess);
- EXPECT_EQ(certificates, nullptr);
+ EXPECT_EQ(SECSuccess, rv);
+ EXPECT_EQ(nullptr, certificates);
}
TEST_F(PK11FindRawCertsBySubjectTest, TestMultipleMatchingCertsFound) {
@@ -197,23 +233,23 @@ TEST_F(PK11FindRawCertsBySubjectTest, TestMultipleMatchingCertsFound) {
SECItem cert1_item = {siBuffer,
const_cast<unsigned char*>(kTestCert1DER.data()),
(unsigned int)kTestCert1DER.size()};
- ASSERT_EQ(PK11_ImportDERCert(m_slot, &cert1_item, CK_INVALID_HANDLE,
- cert1_nickname, false),
- SECSuccess);
+ 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(PK11_ImportDERCert(m_slot, &cert2_item, CK_INVALID_HANDLE,
- cert2_nickname, false),
- SECSuccess);
+ 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(PK11_ImportDERCert(m_slot, &unrelated_cert_item, CK_INVALID_HANDLE,
- unrelated_cert_nickname, false),
- SECSuccess);
+ ASSERT_EQ(SECSuccess,
+ PK11_ImportDERCert(m_slot, &unrelated_cert_item, CK_INVALID_HANDLE,
+ unrelated_cert_nickname, false));
CERTCertificateList* certificates = nullptr;
SECItem subject_item = {
@@ -221,10 +257,10 @@ TEST_F(PK11FindRawCertsBySubjectTest, TestMultipleMatchingCertsFound) {
(unsigned int)kTestCertSubjectDER.size()};
SECStatus rv =
PK11_FindRawCertsWithSubject(m_slot, &subject_item, &certificates);
- EXPECT_EQ(rv, SECSuccess);
- ASSERT_NE(certificates, nullptr);
+ EXPECT_EQ(SECSuccess, rv);
+ ASSERT_NE(nullptr, certificates);
ScopedCERTCertificateList scoped_certificates(certificates);
- ASSERT_EQ(scoped_certificates->len, 2);
+ ASSERT_EQ(2, scoped_certificates->len);
std::vector<uint8_t> found_cert1(
scoped_certificates->certs[0].data,
@@ -244,9 +280,9 @@ TEST_F(PK11FindRawCertsBySubjectTest, TestNoCertsOnInternalSlots) {
SECItem cert1_item = {siBuffer,
const_cast<unsigned char*>(kTestCert1DER.data()),
(unsigned int)kTestCert1DER.size()};
- ASSERT_EQ(PK11_ImportDERCert(m_slot, &cert1_item, CK_INVALID_HANDLE,
- cert1_nickname, false),
- SECSuccess);
+ 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()),
@@ -255,15 +291,15 @@ TEST_F(PK11FindRawCertsBySubjectTest, TestNoCertsOnInternalSlots) {
ScopedPK11SlotInfo internal_key_slot(PK11_GetInternalKeySlot());
SECStatus rv = PK11_FindRawCertsWithSubject(
internal_key_slot.get(), &subject_item, &internal_key_slot_certificates);
- EXPECT_EQ(rv, SECSuccess);
- EXPECT_EQ(internal_key_slot_certificates, nullptr);
+ 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(rv, SECSuccess);
- EXPECT_EQ(internal_slot_certificates, nullptr);
+ EXPECT_EQ(SECSuccess, rv);
+ EXPECT_EQ(nullptr, internal_slot_certificates);
}
// issuer:test cert
@@ -304,10 +340,9 @@ TEST_F(PK11FindRawCertsBySubjectTest, TestFindEmptySubject) {
SECItem empty_subject_cert_item = {
siBuffer, const_cast<unsigned char*>(kEmptySubjectCertDER.data()),
(unsigned int)kEmptySubjectCertDER.size()};
- ASSERT_EQ(
- PK11_ImportDERCert(m_slot, &empty_subject_cert_item, CK_INVALID_HANDLE,
- empty_subject_cert_nickname, false),
- SECSuccess);
+ 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()),
@@ -315,15 +350,15 @@ TEST_F(PK11FindRawCertsBySubjectTest, TestFindEmptySubject) {
CERTCertificateList* certificates = nullptr;
SECStatus rv =
PK11_FindRawCertsWithSubject(m_slot, &subject_item, &certificates);
- EXPECT_EQ(rv, SECSuccess);
- ASSERT_NE(certificates, nullptr);
+ EXPECT_EQ(SECSuccess, rv);
+ ASSERT_NE(nullptr, certificates);
ScopedCERTCertificateList scoped_certificates(certificates);
- ASSERT_EQ(scoped_certificates->len, 1);
+ 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(found_cert, kEmptySubjectCertDER);
+ EXPECT_EQ(kEmptySubjectCertDER, found_cert);
}
// Searching for a zero-length subject doesn't make sense (the minimum subject
@@ -334,16 +369,16 @@ TEST_F(PK11FindRawCertsBySubjectTest, TestSearchForNullSubject) {
SECItem cert1_item = {siBuffer,
const_cast<unsigned char*>(kTestCert1DER.data()),
(unsigned int)kTestCert1DER.size()};
- ASSERT_EQ(PK11_ImportDERCert(m_slot, &cert1_item, CK_INVALID_HANDLE,
- cert1_nickname, false),
- SECSuccess);
+ 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(rv, SECSuccess);
- EXPECT_EQ(certificates, nullptr);
+ EXPECT_EQ(SECSuccess, rv);
+ EXPECT_EQ(nullptr, certificates);
}
class PK11GetCertsMatchingPrivateKeyTest : public PK11FindCertsTestBase {};
@@ -407,11 +442,10 @@ TEST_F(PK11GetCertsMatchingPrivateKeyTest, TestNoCertsAtAll) {
(unsigned int)kTestPrivateKeyInfoDER.size(),
};
SECKEYPrivateKey* priv_key = nullptr;
- ASSERT_EQ(PK11_ImportDERPrivateKeyInfoAndReturnKey(
- m_slot, &private_key_info, nullptr, nullptr, false, false,
- KU_ALL, &priv_key, nullptr),
- SECSuccess);
- ASSERT_NE(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()));
@@ -425,20 +459,19 @@ TEST_F(PK11GetCertsMatchingPrivateKeyTest, TestNoCertsForKey) {
(unsigned int)kTestPrivateKeyInfoDER.size(),
};
SECKEYPrivateKey* priv_key = nullptr;
- ASSERT_EQ(PK11_ImportDERPrivateKeyInfoAndReturnKey(
- m_slot, &private_key_info, nullptr, nullptr, false, false,
- KU_ALL, &priv_key, nullptr),
- SECSuccess);
- ASSERT_NE(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(PK11_ImportDERCert(m_slot, &cert_item, CK_INVALID_HANDLE,
- cert_nickname, false),
- SECSuccess);
+ ASSERT_EQ(SECSuccess,
+ PK11_ImportDERCert(m_slot, &cert_item, CK_INVALID_HANDLE,
+ cert_nickname, false));
ScopedCERTCertList certs(
PK11_GetCertsMatchingPrivateKey(scoped_priv_key.get()));
@@ -448,8 +481,8 @@ TEST_F(PK11GetCertsMatchingPrivateKeyTest, TestNoCertsForKey) {
void CheckCertListForSubjects(
ScopedCERTCertList& list,
const std::vector<const char*>& expected_subjects) {
- ASSERT_NE(list.get(), nullptr);
- ASSERT_NE(expected_subjects.size(), 0ul);
+ 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;
@@ -462,7 +495,7 @@ void CheckCertListForSubjects(
}
}
ASSERT_TRUE(found);
- ASSERT_EQ(list_length, expected_subjects.size());
+ ASSERT_EQ(expected_subjects.size(), list_length);
}
}
@@ -473,28 +506,27 @@ TEST_F(PK11GetCertsMatchingPrivateKeyTest, TestOneCertForKey) {
(unsigned int)kTestPrivateKeyInfoDER.size(),
};
SECKEYPrivateKey* priv_key = nullptr;
- ASSERT_EQ(PK11_ImportDERPrivateKeyInfoAndReturnKey(
- m_slot, &private_key_info, nullptr, nullptr, false, false,
- KU_ALL, &priv_key, nullptr),
- SECSuccess);
- ASSERT_NE(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(PK11_ImportDERCert(m_slot, &cert1_item, CK_INVALID_HANDLE,
- cert1_nickname, false),
- SECSuccess);
+ 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(PK11_ImportDERCert(m_slot, &cert_item, CK_INVALID_HANDLE,
- cert_nickname, false),
- SECSuccess);
+ ASSERT_EQ(SECSuccess,
+ PK11_ImportDERCert(m_slot, &cert_item, CK_INVALID_HANDLE,
+ cert_nickname, false));
ScopedCERTCertList certs(
PK11_GetCertsMatchingPrivateKey(scoped_priv_key.get()));
@@ -508,39 +540,87 @@ TEST_F(PK11GetCertsMatchingPrivateKeyTest, TestTwoCertsForKey) {
(unsigned int)kTestPrivateKeyInfoDER.size(),
};
SECKEYPrivateKey* priv_key = nullptr;
- ASSERT_EQ(PK11_ImportDERPrivateKeyInfoAndReturnKey(
- m_slot, &private_key_info, nullptr, nullptr, false, false,
- KU_ALL, &priv_key, nullptr),
- SECSuccess);
- ASSERT_NE(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(PK11_ImportDERCert(m_slot, &cert1_item, CK_INVALID_HANDLE,
- cert1_nickname, false),
- SECSuccess);
+ 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(PK11_ImportDERCert(m_slot, &cert2_item, CK_INVALID_HANDLE,
- cert2_nickname, false),
- SECSuccess);
+ 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(PK11_ImportDERCert(m_slot, &cert_item, CK_INVALID_HANDLE,
- cert_nickname, false),
- SECSuccess);
+ 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
index b521687fb..1982fb484 100644
--- a/security/nss/gtests/pk11_gtest/pk11_gtest.gyp
+++ b/security/nss/gtests/pk11_gtest/pk11_gtest.gyp
@@ -14,6 +14,7 @@
'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',
@@ -21,16 +22,24 @@
'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_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',
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 000000000..c3fff235b
--- /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_CASE_P(
+ HkdfSha1, Pkcs11HkdfTest,
+ ::testing::Combine(::testing::ValuesIn(kHkdfSha1WycheproofVectors),
+ ::testing::ValuesIn(kHkdfTestTypesAll),
+ ::testing::Values(CKM_SHA_1)));
+
+INSTANTIATE_TEST_CASE_P(
+ HkdfSha256, Pkcs11HkdfTest,
+ ::testing::Combine(::testing::ValuesIn(kHkdfSha256WycheproofVectors),
+ ::testing::ValuesIn(kHkdfTestTypesAll),
+ ::testing::Values(CKM_SHA256)));
+
+INSTANTIATE_TEST_CASE_P(
+ HkdfSha384, Pkcs11HkdfTest,
+ ::testing::Combine(::testing::ValuesIn(kHkdfSha384WycheproofVectors),
+ ::testing::ValuesIn(kHkdfTestTypesAll),
+ ::testing::Values(CKM_SHA384)));
+
+INSTANTIATE_TEST_CASE_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 000000000..00891d51c
--- /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_CASE_P(
+ HmacSha256, Pkcs11HmacTest,
+ ::testing::Combine(::testing::ValuesIn(kHmacSha256WycheproofVectors),
+ ::testing::Values(CKM_SHA256_HMAC)));
+INSTANTIATE_TEST_CASE_P(
+ HmacSha384, Pkcs11HmacTest,
+ ::testing::Combine(::testing::ValuesIn(kHmacSha384WycheproofVectors),
+ ::testing::Values(CKM_SHA384_HMAC)));
+INSTANTIATE_TEST_CASE_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 000000000..1858e7f10
--- /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_CASE_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_import_unittest.cc b/security/nss/gtests/pk11_gtest/pk11_import_unittest.cc
index 3ca184b5f..19ecb94a2 100644
--- a/security/nss/gtests/pk11_gtest/pk11_import_unittest.cc
+++ b/security/nss/gtests/pk11_gtest/pk11_import_unittest.cc
@@ -1,4 +1,5 @@
/* -*- 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/. */
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 000000000..d8a0a0f58
--- /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_module_unittest.cc b/security/nss/gtests/pk11_gtest/pk11_module_unittest.cc
index ec4667df8..9627c823e 100644
--- a/security/nss/gtests/pk11_gtest/pk11_module_unittest.cc
+++ b/security/nss/gtests/pk11_gtest/pk11_module_unittest.cc
@@ -1,4 +1,5 @@
/* -*- 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/. */
diff --git a/security/nss/gtests/pk11_gtest/pk11_pbkdf2_unittest.cc b/security/nss/gtests/pk11_gtest/pk11_pbkdf2_unittest.cc
index a2118ef93..503654061 100644
--- a/security/nss/gtests/pk11_gtest/pk11_pbkdf2_unittest.cc
+++ b/security/nss/gtests/pk11_gtest/pk11_pbkdf2_unittest.cc
@@ -1,4 +1,5 @@
/* -*- 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/. */
@@ -50,6 +51,7 @@ class Pkcs11Pbkdf2Test : public ::testing::Test {
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;
@@ -59,6 +61,10 @@ class Pkcs11Pbkdf2Test : public ::testing::Test {
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.
@@ -70,6 +76,12 @@ class Pkcs11Pbkdf2Test : public ::testing::Test {
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:
@@ -98,13 +110,8 @@ class Pkcs11Pbkdf2Test : public ::testing::Test {
return !memcmp(&derived[0], key_data->data, key_data->len);
}
- 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())};
-
+ 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,
@@ -118,6 +125,34 @@ class Pkcs11Pbkdf2Test : public ::testing::Test {
// 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>
diff --git a/security/nss/gtests/pk11_gtest/pk11_prf_unittest.cc b/security/nss/gtests/pk11_gtest/pk11_prf_unittest.cc
index e79dac5e4..3580b10a2 100644
--- a/security/nss/gtests/pk11_gtest/pk11_prf_unittest.cc
+++ b/security/nss/gtests/pk11_gtest/pk11_prf_unittest.cc
@@ -1,4 +1,5 @@
/* -*- 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/. */
diff --git a/security/nss/gtests/pk11_gtest/pk11_prng_unittest.cc b/security/nss/gtests/pk11_gtest/pk11_prng_unittest.cc
index 52fd91de0..ef05fe51c 100644
--- a/security/nss/gtests/pk11_gtest/pk11_prng_unittest.cc
+++ b/security/nss/gtests/pk11_gtest/pk11_prng_unittest.cc
@@ -1,4 +1,5 @@
/* -*- 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/. */
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 000000000..6c5635f6c
--- /dev/null
+++ b/security/nss/gtests/pk11_gtest/pk11_rsaencrypt_unittest.cc
@@ -0,0 +1,127 @@
+/* -*- 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_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());
+
+ // RSA_DecryptBlock returns SECFailure with an empty message.
+ if (vec.valid && vec.msg.size()) {
+ EXPECT_EQ(SECSuccess, rv);
+ decrypted.resize(decrypted_len);
+ EXPECT_EQ(vec.msg, decrypted);
+ } else {
+ EXPECT_EQ(SECFailure, rv);
+ }
+ };
+};
+
+TEST_P(RsaDecryptWycheproofTest, Pkcs1Decrypt) { TestDecrypt(GetParam()); }
+
+INSTANTIATE_TEST_CASE_P(WycheproofRsa2048DecryptTest, RsaDecryptWycheproofTest,
+ ::testing::ValuesIn(kRsa2048DecryptWycheproofVectors));
+
+INSTANTIATE_TEST_CASE_P(WycheproofRsa3072DecryptTest, RsaDecryptWycheproofTest,
+ ::testing::ValuesIn(kRsa3072DecryptWycheproofVectors));
+
+INSTANTIATE_TEST_CASE_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 000000000..d14eb9c64
--- /dev/null
+++ b/security/nss/gtests/pk11_gtest/pk11_rsaoaep_unittest.cc
@@ -0,0 +1,186 @@
+/* -*- 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_CASE_P(WycheproofRsa2048Sha1OaepTest, RsaOaepWycheproofTest,
+ ::testing::ValuesIn(kRsaOaep2048Sha1WycheproofVectors));
+
+INSTANTIATE_TEST_CASE_P(
+ WycheproofOaep2048Sha256Sha1Test, RsaOaepWycheproofTest,
+ ::testing::ValuesIn(kRsaOaep2048Sha256Mgf1Sha1WycheproofVectors));
+
+INSTANTIATE_TEST_CASE_P(
+ WycheproofOaep2048Sha256Sha256Test, RsaOaepWycheproofTest,
+ ::testing::ValuesIn(kRsaOaep2048Sha256Mgf1Sha256WycheproofVectors));
+
+INSTANTIATE_TEST_CASE_P(
+ WycheproofOaep2048Sha384Sha1Test, RsaOaepWycheproofTest,
+ ::testing::ValuesIn(kRsaOaep2048Sha384Mgf1Sha1WycheproofVectors));
+
+INSTANTIATE_TEST_CASE_P(
+ WycheproofOaep2048Sha384Sha384Test, RsaOaepWycheproofTest,
+ ::testing::ValuesIn(kRsaOaep2048Sha384Mgf1Sha384WycheproofVectors));
+
+INSTANTIATE_TEST_CASE_P(
+ WycheproofOaep2048Sha512Sha1Test, RsaOaepWycheproofTest,
+ ::testing::ValuesIn(kRsaOaep2048Sha512Mgf1Sha1WycheproofVectors));
+
+INSTANTIATE_TEST_CASE_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;
+
+ // This fails because this method is broken and assumes CKM_RSA_PKCS and
+ // doesn't understand OAEP.
+ p_unwrapped_tmp = PK11_PubUnwrapSymKey(priv.get(), wrapped.get(), CKM_AES_CBC,
+ CKA_DECRYPT, 16);
+ ASSERT_EQ(p_unwrapped_tmp, nullptr);
+
+ 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);
+
+ // Extract key's value in order to validate decryption worked.
+ rv = PK11_ExtractKeyValue(to_wrap.get());
+ ASSERT_EQ(rv, SECSuccess);
+
+ rv = PK11_ExtractKeyValue(unwrapped.get());
+ ASSERT_EQ(rv, SECSuccess);
+
+ // References owned by PKCS#11 layer; no need to scope and free.
+ SECItem* expectedItem = PK11_GetKeyData(to_wrap.get());
+ 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
index 8a9eb56f4..941de9797 100644
--- a/security/nss/gtests/pk11_gtest/pk11_rsapkcs1_unittest.cc
+++ b/security/nss/gtests/pk11_gtest/pk11_rsapkcs1_unittest.cc
@@ -1,101 +1,206 @@
/* -*- 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 "gtest/gtest.h"
-#include "nss_scoped_ptrs.h"
-#include "cpputil.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 {
-// Test that the RSASSA-PKCS1-v1_5 implementation enforces the missing NULL
-// parameter.
-TEST(RsaPkcs1Test, RequireNullParameter) {
- // kSpki is an RSA public key in an X.509 SubjectPublicKeyInfo.
- const uint8_t kSpki[] = {
- 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,
- };
- // kHash is the SHA-256 hash of {1,2,3,4}.
- const uint8_t kHash[] = {
- 0x9f, 0x64, 0xa7, 0x47, 0xe1, 0xb9, 0x7f, 0x13, 0x1f, 0xab, 0xb6,
- 0xb4, 0x47, 0x29, 0x6c, 0x9b, 0x6f, 0x02, 0x01, 0xe7, 0x9f, 0xb3,
- 0xc5, 0x35, 0x6e, 0x6c, 0x77, 0xe8, 0x9b, 0x6a, 0x80, 0x6a,
- };
- // kSignature is the signature of kHash with RSASSA-PKCS1-v1_5.
- const uint8_t kSignature[] = {
- 0xa5, 0xf0, 0x8a, 0x47, 0x5d, 0x3c, 0xb3, 0xcc, 0xa9, 0x79, 0xaf, 0x4d,
- 0x8c, 0xae, 0x4c, 0x14, 0xef, 0xc2, 0x0b, 0x34, 0x36, 0xde, 0xf4, 0x3e,
- 0x3d, 0xbb, 0x4a, 0x60, 0x5c, 0xc8, 0x91, 0x28, 0xda, 0xfb, 0x7e, 0x04,
- 0x96, 0x7e, 0x63, 0x13, 0x90, 0xce, 0xb9, 0xb4, 0x62, 0x7a, 0xfd, 0x09,
- 0x3d, 0xc7, 0x67, 0x78, 0x54, 0x04, 0xeb, 0x52, 0x62, 0x6e, 0x24, 0x67,
- 0xb4, 0x40, 0xfc, 0x57, 0x62, 0xc6, 0xf1, 0x67, 0xc1, 0x97, 0x8f, 0x6a,
- 0xa8, 0xae, 0x44, 0x46, 0x5e, 0xab, 0x67, 0x17, 0x53, 0x19, 0x3a, 0xda,
- 0x5a, 0xc8, 0x16, 0x3e, 0x86, 0xd5, 0xc5, 0x71, 0x2f, 0xfc, 0x23, 0x48,
- 0xd9, 0x0b, 0x13, 0xdd, 0x7b, 0x5a, 0x25, 0x79, 0xef, 0xa5, 0x7b, 0x04,
- 0xed, 0x44, 0xf6, 0x18, 0x55, 0xe4, 0x0a, 0xe9, 0x57, 0x79, 0x5d, 0xd7,
- 0x55, 0xa7, 0xab, 0x45, 0x02, 0x97, 0x60, 0x42,
- };
- // kSignature is an invalid signature of kHash with RSASSA-PKCS1-v1_5 with the
- // NULL parameter omitted.
- const uint8_t kSignatureInvalid[] = {
- 0x71, 0x6c, 0x24, 0x4e, 0xc9, 0x9b, 0x19, 0xc7, 0x49, 0x29, 0xb8, 0xd4,
- 0xfb, 0x26, 0x23, 0xc0, 0x96, 0x18, 0xcd, 0x1e, 0x60, 0xe8, 0x88, 0x94,
- 0x8c, 0x59, 0xfb, 0x58, 0x5c, 0x61, 0x58, 0x7a, 0xae, 0xcc, 0xeb, 0xee,
- 0x1e, 0x85, 0x7d, 0x83, 0xa9, 0xdc, 0x6f, 0x4c, 0x34, 0x5c, 0xcb, 0xd9,
- 0xde, 0x58, 0x76, 0xdf, 0x1f, 0x5e, 0xd4, 0x57, 0x5b, 0xeb, 0xaf, 0x4f,
- 0x7a, 0xa7, 0x6b, 0x21, 0xf1, 0x0a, 0x96, 0x78, 0xc7, 0xa8, 0x02, 0x7a,
- 0xc2, 0x06, 0xd3, 0x18, 0x79, 0x72, 0x6b, 0xfe, 0x2d, 0xec, 0xd8, 0x8e,
- 0x98, 0x86, 0x89, 0xf4, 0x67, 0x14, 0x2b, 0xac, 0x6d, 0xd7, 0x04, 0xd8,
- 0xab, 0x05, 0xe6, 0x51, 0xf6, 0xee, 0x58, 0x63, 0xef, 0x6a, 0x3e, 0x89,
- 0x99, 0x2a, 0x1c, 0x10, 0xc2, 0xd0, 0x41, 0x9e, 0x1e, 0x9a, 0x9a, 0x57,
- 0x32, 0x0f, 0x49, 0xb4, 0x57, 0x37, 0xa4, 0x26,
+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 spkiItem = {siBuffer, toUcharPtr(kSpki), sizeof(kSpki)};
- ScopedCERTSubjectPublicKeyInfo certSpki(
- SECKEY_DecodeDERSubjectPublicKeyInfo(&spkiItem));
- ASSERT_TRUE(certSpki);
- ScopedSECKEYPublicKey pubKey(SECKEY_ExtractPublicKey(certSpki.get()));
- ASSERT_TRUE(pubKey);
+ 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 sigItem = {siBuffer, toUcharPtr(kSignature), sizeof(kSignature)};
- SECStatus rv = VFY_VerifyDigestDirect(&hash, pubKey.get(), &sigItem,
+ 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.
- sigItem = {siBuffer, toUcharPtr(kSignatureInvalid),
- sizeof(kSignatureInvalid)};
- rv = VFY_VerifyDigestDirect(&hash, pubKey.get(), &sigItem,
+ 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
@@ -105,4 +210,42 @@ TEST(RsaPkcs1Test, RequireNullParameter) {
#endif
}
+TEST_P(Pkcs11RsaPkcs1WycheproofTest, Verify) { Derive(GetParam()); }
+
+INSTANTIATE_TEST_CASE_P(
+ Wycheproof2048RsaSignatureSha224Test, Pkcs11RsaPkcs1WycheproofTest,
+ ::testing::ValuesIn(kRsaSignature2048Sha224WycheproofVectors));
+
+INSTANTIATE_TEST_CASE_P(
+ Wycheproof2048RsaSignatureSha256Test, Pkcs11RsaPkcs1WycheproofTest,
+ ::testing::ValuesIn(kRsaSignature2048Sha256WycheproofVectors));
+
+INSTANTIATE_TEST_CASE_P(
+ Wycheproof2048RsaSignatureSha512Test, Pkcs11RsaPkcs1WycheproofTest,
+ ::testing::ValuesIn(kRsaSignature2048Sha512WycheproofVectors));
+
+INSTANTIATE_TEST_CASE_P(
+ Wycheproof3072RsaSignatureSha256Test, Pkcs11RsaPkcs1WycheproofTest,
+ ::testing::ValuesIn(kRsaSignature3072Sha256WycheproofVectors));
+
+INSTANTIATE_TEST_CASE_P(
+ Wycheproof3072RsaSignatureSha384Test, Pkcs11RsaPkcs1WycheproofTest,
+ ::testing::ValuesIn(kRsaSignature3072Sha384WycheproofVectors));
+
+INSTANTIATE_TEST_CASE_P(
+ Wycheproof3072RsaSignatureSha512Test, Pkcs11RsaPkcs1WycheproofTest,
+ ::testing::ValuesIn(kRsaSignature3072Sha512WycheproofVectors));
+
+INSTANTIATE_TEST_CASE_P(
+ Wycheproof4096RsaSignatureSha384Test, Pkcs11RsaPkcs1WycheproofTest,
+ ::testing::ValuesIn(kRsaSignature4096Sha384WycheproofVectors));
+
+INSTANTIATE_TEST_CASE_P(
+ Wycheproof4096RsaSignatureSha512Test, Pkcs11RsaPkcs1WycheproofTest,
+ ::testing::ValuesIn(kRsaSignature4096Sha512WycheproofVectors));
+
+INSTANTIATE_TEST_CASE_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
index 1ce642937..48a7cc268 100644
--- a/security/nss/gtests/pk11_gtest/pk11_rsapss_unittest.cc
+++ b/security/nss/gtests/pk11_gtest/pk11_rsapss_unittest.cc
@@ -1,4 +1,5 @@
/* -*- 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/. */
@@ -8,49 +9,117 @@
#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) {
- rsaPssParams_.hashAlg = CKM_SHA_1;
- rsaPssParams_.mgf = CKG_MGF1_SHA1;
- rsaPssParams_.sLen = HASH_ResultLenByOidTag(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*>(&rsaPssParams_);
- params_.len = sizeof(rsaPssParams_);
+ 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 rsaPssParams_;
+ 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 hashMech = CKM_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* pubKeyRaw = nullptr;
+ SECKEYPublicKey* pub_keyRaw = nullptr;
ScopedSECKEYPrivateKey privKey(
PK11_GenerateKeyPair(slot.get(), CKM_RSA_PKCS_KEY_PAIR_GEN, &rsaGenParams,
- &pubKeyRaw, false, false, nullptr));
- ASSERT_TRUE(!!privKey && pubKeyRaw);
- ScopedSECKEYPublicKey pubKey(pubKeyRaw);
+ &pub_keyRaw, false, false, nullptr));
+ ASSERT_TRUE(!!privKey && pub_keyRaw);
+ ScopedSECKEYPublicKey pub_key(pub_keyRaw);
// Generate random data to sign.
uint8_t dataBuf[50];
@@ -65,30 +134,30 @@ TEST_F(Pkcs11RsaPssTest, GenerateAndSignAndVerify) {
static_cast<unsigned int>(sigBuf.size())};
// Set up PSS parameters.
- CK_RSA_PKCS_PSS_PARAMS rsaPssParams = {hashMech, mgf, hLen};
- SECItem params = {siBuffer, reinterpret_cast<unsigned char*>(&rsaPssParams),
- sizeof(rsaPssParams)};
+ 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(pubKey.get(), mechanism(), &params, &sig, &data,
- nullptr);
+ 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(pubKey.get(), mechanism(), &params, &sig, &data,
- nullptr);
+ 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(pubKey.get(), mechanism(), &params, &sig, &data,
- nullptr);
+ rv = PK11_VerifyWithMechanism(pub_key.get(), mechanism(), &params, &sig,
+ &data, nullptr);
EXPECT_EQ(rv, SECFailure);
}
@@ -99,12 +168,12 @@ TEST_F(Pkcs11RsaPssTest, NoLeakWithInvalidExponent) {
// Generate RSA key pair.
ScopedPK11SlotInfo slot(PK11_GetInternalSlot());
- SECKEYPublicKey* pubKey = nullptr;
+ SECKEYPublicKey* pub_key = nullptr;
SECKEYPrivateKey* privKey =
PK11_GenerateKeyPair(slot.get(), CKM_RSA_PKCS_KEY_PAIR_GEN, &rsaGenParams,
- &pubKey, false, false, nullptr);
+ &pub_key, false, false, nullptr);
EXPECT_FALSE(privKey);
- EXPECT_FALSE(pubKey);
+ EXPECT_FALSE(pub_key);
}
class Pkcs11RsaPssVectorTest
: public Pkcs11RsaPssTest,
@@ -158,4 +227,33 @@ static const Pkcs11SignatureTestParams kRsaPssVectors[] = {
INSTANTIATE_TEST_CASE_P(RsaPssSignVerify, Pkcs11RsaPssVectorTest,
::testing::ValuesIn(kRsaPssVectors));
+TEST_P(Pkcs11RsaPssTestWycheproof, Verify) { TestPss(GetParam()); }
+
+INSTANTIATE_TEST_CASE_P(
+ Wycheproof2048RsaPssSha120Test, Pkcs11RsaPssTestWycheproof,
+ ::testing::ValuesIn(kRsaPss2048Sha120WycheproofVectors));
+
+INSTANTIATE_TEST_CASE_P(
+ Wycheproof2048RsaPssSha25632Test, Pkcs11RsaPssTestWycheproof,
+ ::testing::ValuesIn(kRsaPss2048Sha25632WycheproofVectors));
+
+INSTANTIATE_TEST_CASE_P(
+ Wycheproof2048RsaPssSha2560Test, Pkcs11RsaPssTestWycheproof,
+ ::testing::ValuesIn(kRsaPss2048Sha2560WycheproofVectors));
+
+INSTANTIATE_TEST_CASE_P(
+ Wycheproof3072RsaPssSha25632Test, Pkcs11RsaPssTestWycheproof,
+ ::testing::ValuesIn(kRsaPss3072Sha25632WycheproofVectors));
+
+INSTANTIATE_TEST_CASE_P(
+ Wycheproof4096RsaPssSha25632Test, Pkcs11RsaPssTestWycheproof,
+ ::testing::ValuesIn(kRsaPss4096Sha25632WycheproofVectors));
+
+INSTANTIATE_TEST_CASE_P(
+ Wycheproof4096RsaPssSha51232Test, Pkcs11RsaPssTestWycheproof,
+ ::testing::ValuesIn(kRsaPss4096Sha51232WycheproofVectors));
+
+INSTANTIATE_TEST_CASE_P(WycheproofRsaPssMiscTest, Pkcs11RsaPssTestWycheproof,
+ ::testing::ValuesIn(kRsaPssMiscWycheproofVectors));
+
} // 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
index 40efe266e..7f389fef1 100644
--- a/security/nss/gtests/pk11_gtest/pk11_seed_cbc_unittest.cc
+++ b/security/nss/gtests/pk11_gtest/pk11_seed_cbc_unittest.cc
@@ -1,4 +1,5 @@
/* -*- 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/. */
@@ -13,58 +14,69 @@
#include "util.h"
namespace nss_test {
-class Pkcs11SeedCbcTest : public ::testing::Test {
+class Pkcs11SeedTest : public ::testing::Test {
protected:
- enum class Action { Encrypt, Decrypt };
-
- SECStatus EncryptDecryptSeed(Action action, unsigned int input_size,
- unsigned int output_size) {
+ 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(), kMech, nullptr, 16, nullptr));
+ PK11_KeyGen(slot.get(), mech, nullptr, 16, nullptr));
EXPECT_TRUE(!!sym_key);
- std::vector<uint8_t> data(input_size);
+ std::vector<uint8_t> plaintext(input_size, 0xFF);
std::vector<uint8_t> init_vector(16);
- std::vector<uint8_t> output(output_size);
- SECItem params = {siBuffer, init_vector.data(),
- (unsigned int)init_vector.size()};
+ 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.
+ // Try to encrypt, decrypt if positive test.
unsigned int output_len = 0;
- if (action == Action::Encrypt) {
- return PK11_Encrypt(sym_key.get(), kMech, &params, output.data(),
- &output_len, output_size, data.data(), data.size());
- } else {
- return PK11_Decrypt(sym_key.get(), kMech, &params, output.data(),
- &output_len, output_size, data.data(), data.size());
+ 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);
}
}
- const CK_MECHANISM_TYPE kMech = CKM_SEED_CBC;
};
+#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(Pkcs11SeedCbcTest, SeedCBC_ValidArgs) {
- EXPECT_EQ(SECSuccess, EncryptDecryptSeed(Action::Encrypt, 16, 16));
- EXPECT_EQ(SECSuccess, EncryptDecryptSeed(Action::Decrypt, 16, 16));
+TEST_F(Pkcs11SeedTest, CBC_ValidArgs) {
+ EncryptDecryptSeed(SECSuccess, 16, 16);
// No problem if maxLen is bigger than input data.
- EXPECT_EQ(SECSuccess, EncryptDecryptSeed(Action::Encrypt, 16, 32));
- EXPECT_EQ(SECSuccess, EncryptDecryptSeed(Action::Decrypt, 16, 32));
+ EncryptDecryptSeed(SECSuccess, 16, 32);
}
-TEST_F(Pkcs11SeedCbcTest, SeedCBC_InvalidArgs) {
+TEST_F(Pkcs11SeedTest, CBC_InvalidArgs) {
// maxLen lower than input data.
- EXPECT_EQ(SECFailure, EncryptDecryptSeed(Action::Encrypt, 16, 10));
- EXPECT_EQ(SECFailure, EncryptDecryptSeed(Action::Decrypt, 16, 10));
+ EncryptDecryptSeed(SECFailure, 16, 10);
// input data not multiple of SEED_BLOCK_SIZE (16)
- EXPECT_EQ(SECFailure, EncryptDecryptSeed(Action::Encrypt, 17, 32));
- EXPECT_EQ(SECFailure, EncryptDecryptSeed(Action::Decrypt, 17, 32));
+ 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 \ No newline at end of file
+} // namespace nss_test