diff options
Diffstat (limited to 'security/nss/gtests/pk11_gtest/pk11_curve25519_unittest.cc')
-rw-r--r-- | security/nss/gtests/pk11_gtest/pk11_curve25519_unittest.cc | 126 |
1 files changed, 126 insertions, 0 deletions
diff --git a/security/nss/gtests/pk11_gtest/pk11_curve25519_unittest.cc b/security/nss/gtests/pk11_gtest/pk11_curve25519_unittest.cc new file mode 100644 index 0000000000..d3f3c37c43 --- /dev/null +++ b/security/nss/gtests/pk11_gtest/pk11_curve25519_unittest.cc @@ -0,0 +1,126 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include <memory> +#include "nss.h" +#include "pk11pub.h" +#include "prerror.h" +#include "cpputil.h" +#include "nss_scoped_ptrs.h" + +#include "testvectors/curve25519-vectors.h" +#include "gtest/gtest.h" + +namespace nss_test { + +class Pkcs11Curve25519Test + : public ::testing::TestWithParam<EcdhTestVectorStr> { + protected: + void Derive(const uint8_t* pkcs8, size_t pkcs8_len, const uint8_t* spki, + size_t spki_len, const uint8_t* secret, size_t secret_len, + bool expect_success) { + ScopedPK11SlotInfo slot(PK11_GetInternalKeySlot()); + ASSERT_TRUE(slot); + + SECItem pkcs8_item = {siBuffer, toUcharPtr(pkcs8), + static_cast<unsigned int>(pkcs8_len)}; + + SECKEYPrivateKey* key = nullptr; + SECStatus rv = PK11_ImportDERPrivateKeyInfoAndReturnKey( + slot.get(), &pkcs8_item, nullptr, nullptr, false, false, KU_ALL, &key, + nullptr); + EXPECT_EQ(SECSuccess, rv); + + ScopedSECKEYPrivateKey priv_key_sess(key); + ASSERT_TRUE(priv_key_sess); + + SECItem spki_item = {siBuffer, toUcharPtr(spki), + static_cast<unsigned int>(spki_len)}; + + ScopedCERTSubjectPublicKeyInfo cert_spki( + SECKEY_DecodeDERSubjectPublicKeyInfo(&spki_item)); + if (!expect_success && !cert_spki) { + return; + } + ASSERT_TRUE(cert_spki); + + ScopedSECKEYPublicKey pub_key_remote( + SECKEY_ExtractPublicKey(cert_spki.get())); + ASSERT_TRUE(pub_key_remote); + + // sym_key_sess = ECDH(session_import(private_test), public_test) + ScopedPK11SymKey sym_key_sess(PK11_PubDeriveWithKDF( + priv_key_sess.get(), pub_key_remote.get(), false, nullptr, nullptr, + CKM_ECDH1_DERIVE, CKM_SHA512_HMAC, CKA_DERIVE, 0, CKD_NULL, nullptr, + nullptr)); + ASSERT_EQ(expect_success, !!sym_key_sess); + + if (expect_success) { + rv = PK11_ExtractKeyValue(sym_key_sess.get()); + EXPECT_EQ(SECSuccess, rv); + + SECItem* key_data = PK11_GetKeyData(sym_key_sess.get()); + EXPECT_EQ(secret_len, key_data->len); + EXPECT_EQ(memcmp(key_data->data, secret, secret_len), 0); + + // Perform wrapped export on the imported private, import it as + // permanent, and verify we derive the same shared secret + static const uint8_t pw[] = "pw"; + SECItem pwItem = {siBuffer, toUcharPtr(pw), sizeof(pw)}; + ScopedSECKEYEncryptedPrivateKeyInfo epki(PK11_ExportEncryptedPrivKeyInfo( + slot.get(), SEC_OID_AES_256_CBC, &pwItem, priv_key_sess.get(), 1, + nullptr)); + ASSERT_NE(nullptr, epki) << "PK11_ExportEncryptedPrivKeyInfo failed: " + << PORT_ErrorToName(PORT_GetError()); + + ScopedSECKEYPublicKey pub_key_local( + SECKEY_ConvertToPublicKey(priv_key_sess.get())); + + SECKEYPrivateKey* priv_key_tok = nullptr; + rv = PK11_ImportEncryptedPrivateKeyInfoAndReturnKey( + slot.get(), epki.get(), &pwItem, nullptr, + &pub_key_local->u.ec.publicValue, PR_TRUE, PR_TRUE, ecKey, 0, + &priv_key_tok, nullptr); + ASSERT_EQ(SECSuccess, rv) << "PK11_ImportEncryptedPrivateKeyInfo failed " + << PORT_ErrorToName(PORT_GetError()); + ASSERT_TRUE(priv_key_tok); + + // sym_key_tok = ECDH(token_import(export(private_test)), + // public_test) + ScopedPK11SymKey sym_key_tok(PK11_PubDeriveWithKDF( + priv_key_tok, pub_key_remote.get(), false, nullptr, nullptr, + CKM_ECDH1_DERIVE, CKM_SHA512_HMAC, CKA_DERIVE, 0, CKD_NULL, nullptr, + nullptr)); + EXPECT_TRUE(sym_key_tok); + + if (sym_key_tok) { + rv = PK11_ExtractKeyValue(sym_key_tok.get()); + EXPECT_EQ(SECSuccess, rv); + + key_data = PK11_GetKeyData(sym_key_tok.get()); + EXPECT_EQ(secret_len, key_data->len); + EXPECT_EQ(memcmp(key_data->data, secret, secret_len), 0); + } + rv = PK11_DeleteTokenPrivateKey(priv_key_tok, true); + EXPECT_EQ(SECSuccess, rv); + } + }; + + void Derive(const EcdhTestVectorStr testvector) { + Derive(testvector.private_key.data(), testvector.private_key.size(), + testvector.public_key.data(), testvector.public_key.size(), + testvector.secret.data(), testvector.secret.size(), + testvector.valid); + }; +}; + +TEST_P(Pkcs11Curve25519Test, TestVectors) { Derive(GetParam()); } + +INSTANTIATE_TEST_SUITE_P(NSSTestVector, Pkcs11Curve25519Test, + ::testing::ValuesIn(kCurve25519Vectors)); + +INSTANTIATE_TEST_SUITE_P(WycheproofTestVector, Pkcs11Curve25519Test, + ::testing::ValuesIn(kCurve25519WycheproofVectors)); + +} // namespace nss_test |