From 5023aeed7fa9712595c1413631e70e564d28eff6 Mon Sep 17 00:00:00 2001 From: Robert Relyea Date: Thu, 1 Apr 2021 15:13:20 -0700 Subject: [PATCH] Bug 1702663 Need to support RSA PSS with Hashing PKCS #11 Mechanisms. FIPS requires that we supply a hash and sign interface for our supported signing algorithms to be validated. We already have those interfaces in softoken for RSA PKCS1, DSA, and ECDSA. However, we don't test those interfaces, now do we supply a way for an application to access those interfaces (usually applications use the VFY_ and SGN_ interfaces which handles the hashing an verify/sign operations). We also have a generic pk11_signature_tests class in pk11_gtest, but only ecdsa and some rsa pss tests uses it. This patch rectifies all of these deficiencies: lib/softokn 1) Hash and sign/verify mechanisms have been added to softoken to support PSS hash and sign. 2) The rsa, dsa, and ecdsa hash and sign algorithms were also cleaned up by creating a fake CKM_SHA1 which matches CKM_SHA_1 so that we can fully use the same macros for all the hash types. 1&2 was sufficient to provide the goals of this task, however we wanted to be able to add tests for this functionality.. lib/pk11wrap 3) Two new functions were added: PK11_CreateContextByPubKey and PK11_CreateContextByPrivKey. These allow you to create multipart contexts with Public and Private keys. This is a requirement to support hash and sign, as they are multi-part operations (rather then just signing a hash, which is a single part operation). With these functions, you can now use the PK11_DigestOp and PK11_DigestFinal to complete a signature or verify optiation. gtests/pk11_gtest 4) Add hash and sign/hash and verify support to the generic pk11_signature_tests.h. 5) pk11_dsa_unittest.cc, pk11_rsa_unittest.cc, and the remainder of pk11_rsapss_unittest.cc (Wycheproof tests) were moved to use the pk11_signature_tests common implementation rather then their own. 6) pk11_ecdsa_unittest.cc was updated to support the hash&sign/verify combo mechanism. 7) With multiple functions using pk11_signature_tests.h, The large functions are moved to pk11_signature_tests.cpp. 8) The test vectors themselves were not changes, now just test against the traditional hash first then verify interfaces and the hash and verify interfaces. Differential Revision: https://phabricator.services.mozilla.com/D110641 --HG-- extra : rebase_source : d2ec6b9589562cedd4aca45b79a649162eadc5ec --- .../abi-check/expected-report-libnss3.so.txt | 15 ++ gtests/pk11_gtest/manifest.mn | 1 + gtests/pk11_gtest/pk11_dsa_unittest.cc | 94 ++++----- gtests/pk11_gtest/pk11_ecdsa_unittest.cc | 31 ++- gtests/pk11_gtest/pk11_gtest.gyp | 1 + gtests/pk11_gtest/pk11_rsapkcs1_unittest.cc | 49 ++++- gtests/pk11_gtest/pk11_rsapss_unittest.cc | 118 +++++------- gtests/pk11_gtest/pk11_signature_test.cc | 181 ++++++++++++++++++ gtests/pk11_gtest/pk11_signature_test.h | 106 +++------- lib/nss/nss.def | 9 +- lib/pk11wrap/pk11cxt.c | 116 +++++++++-- lib/pk11wrap/pk11pub.h | 14 +- lib/pk11wrap/secmodti.h | 3 +- lib/softoken/pkcs11.c | 5 + lib/softoken/pkcs11c.c | 132 +++++++------ 15 files changed, 590 insertions(+), 285 deletions(-) create mode 100644 gtests/pk11_gtest/pk11_signature_test.cc diff --git a/automation/abi-check/expected-report-libnss3.so.txt b/automation/abi-check/expected-report-libnss3.so.txt index e69de29bb2..f4cb8919da 100644 --- a/automation/abi-check/expected-report-libnss3.so.txt +++ b/automation/abi-check/expected-report-libnss3.so.txt @@ -0,0 +1,15 @@ + +2 Added functions: + + 'function PK11Context* PK11_CreateContextByPrivKey(CK_MECHANISM_TYPE, CK_ATTRIBUTE_TYPE, SECKEYPrivateKey*, const SECItem*)' {PK11_CreateContextByPrivKey@@NSS_3.64} + 'function PK11Context* PK11_CreateContextByPubKey(CK_MECHANISM_TYPE, CK_ATTRIBUTE_TYPE, SECKEYPublicKey*, const SECItem*, void*)' {PK11_CreateContextByPubKey@@NSS_3.64} + +1 function with some indirect sub-type change: + + [C]'function PK11Context* PK11_CreateContextBySymKey(CK_MECHANISM_TYPE, CK_ATTRIBUTE_TYPE, PK11SymKey*, SECItem*)' at pk11cxt.c:479:1 has some indirect sub-type changes: + parameter 4 of type 'SECItem*' changed: + in pointed to type 'typedef SECItem': + entity changed from 'typedef SECItem' to 'const SECItem' + type size hasn't changed + + diff --git a/gtests/pk11_gtest/manifest.mn b/gtests/pk11_gtest/manifest.mn index 80530675b3..a1a1af346e 100644 --- a/gtests/pk11_gtest/manifest.mn +++ b/gtests/pk11_gtest/manifest.mn @@ -38,6 +38,7 @@ CPPSRCS = \ pk11_rsaoaep_unittest.cc \ pk11_rsapkcs1_unittest.cc \ pk11_rsapss_unittest.cc \ + pk11_signature_test.cc \ pk11_seed_cbc_unittest.cc \ $(NULL) diff --git a/gtests/pk11_gtest/pk11_dsa_unittest.cc b/gtests/pk11_gtest/pk11_dsa_unittest.cc index 0c776c9f1d..634d496bf0 100644 --- a/gtests/pk11_gtest/pk11_dsa_unittest.cc +++ b/gtests/pk11_gtest/pk11_dsa_unittest.cc @@ -6,12 +6,14 @@ #include #include "nss.h" +#include "prerror.h" #include "pk11pub.h" #include "sechash.h" #include "cryptohi.h" #include "cpputil.h" #include "databuffer.h" +#include "pk11_signature_test.h" #include "gtest/gtest.h" #include "nss_scoped_ptrs.h" @@ -19,59 +21,59 @@ #include "testvectors/dsa-vectors.h" namespace nss_test { - -class Pkcs11DsaTest : public ::testing::TestWithParam { +CK_MECHANISM_TYPE +DsaHashToComboMech(SECOidTag hash) { + switch (hash) { + case SEC_OID_SHA1: + return CKM_DSA_SHA1; + case SEC_OID_SHA224: + return CKM_DSA_SHA224; + case SEC_OID_SHA256: + return CKM_DSA_SHA256; + case SEC_OID_SHA384: + return CKM_DSA_SHA384; + case SEC_OID_SHA512: + return CKM_DSA_SHA512; + default: + break; + } + return CKM_INVALID_MECHANISM; +} + +class Pkcs11DsaTestBase : public Pk11SignatureTest { 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(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(sig_len)}; - ScopedSECItem decoded_sig_item( - DSAU_DecodeDerSigToLen(&sig_item, SECKEY_SignatureLen(pub_key.get()))); - if (!decoded_sig_item) { - ASSERT_FALSE(expect_success) << msg; + Pkcs11DsaTestBase(SECOidTag hashOid) + : Pk11SignatureTest(CKM_DSA, hashOid, DsaHashToComboMech(hashOid)) {} + + void Verify(const DsaTestVector vec) { + /* DSA vectors encode the signature in DER, we need to unwrap it before + * we can send the raw signatures to PKCS #11. */ + DataBuffer pubKeyBuffer(vec.public_key.data(), vec.public_key.size()); + ScopedSECKEYPublicKey nssPubKey(ImportPublicKey(pubKeyBuffer)); + SECItem sigItem = {siBuffer, toUcharPtr(vec.sig.data()), + static_cast(vec.sig.size())}; + ScopedSECItem decodedSigItem( + DSAU_DecodeDerSigToLen(&sigItem, SECKEY_SignatureLen(nssPubKey.get()))); + if (!decodedSigItem) { + ASSERT_FALSE(vec.valid) << "Failed to decode DSA signature Error: " + << PORT_ErrorToString(PORT_GetError()) << "\n"; return; } - DataBuffer hash; - hash.Allocate(static_cast(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(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); - }; + Pkcs11SignatureTestParams params = { + DataBuffer(), pubKeyBuffer, DataBuffer(vec.msg.data(), vec.msg.size()), + DataBuffer(decodedSigItem.get()->data, decodedSigItem.get()->len)}; + Pk11SignatureTest::Verify(params, (bool)vec.valid); + } +}; - 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); - }; +class Pkcs11DsaTest : public Pkcs11DsaTestBase, + public ::testing::WithParamInterface { + public: + Pkcs11DsaTest() : Pkcs11DsaTestBase(GetParam().hash_oid) {} }; -TEST_P(Pkcs11DsaTest, WycheproofVectors) { Derive(GetParam()); } +TEST_P(Pkcs11DsaTest, WycheproofVectors) { Verify(GetParam()); } INSTANTIATE_TEST_SUITE_P(DsaTest, Pkcs11DsaTest, ::testing::ValuesIn(kDsaWycheproofVectors)); diff --git a/gtests/pk11_gtest/pk11_ecdsa_unittest.cc b/gtests/pk11_gtest/pk11_ecdsa_unittest.cc index c127004c8f..9f4bf6a2b5 100644 --- a/gtests/pk11_gtest/pk11_ecdsa_unittest.cc +++ b/gtests/pk11_gtest/pk11_ecdsa_unittest.cc @@ -8,6 +8,7 @@ #include "sechash.h" #include "cryptohi.h" +#include "cpputil.h" #include "gtest/gtest.h" #include "nss_scoped_ptrs.h" @@ -19,10 +20,29 @@ namespace nss_test { +CK_MECHANISM_TYPE +EcHashToComboMech(SECOidTag hash) { + switch (hash) { + case SEC_OID_SHA1: + return CKM_ECDSA_SHA1; + case SEC_OID_SHA224: + return CKM_ECDSA_SHA224; + case SEC_OID_SHA256: + return CKM_ECDSA_SHA256; + case SEC_OID_SHA384: + return CKM_ECDSA_SHA384; + case SEC_OID_SHA512: + return CKM_ECDSA_SHA512; + default: + break; + } + return CKM_INVALID_MECHANISM; +} + class Pkcs11EcdsaTestBase : public Pk11SignatureTest { protected: Pkcs11EcdsaTestBase(SECOidTag hash_oid) - : Pk11SignatureTest(CKM_ECDSA, hash_oid) {} + : Pk11SignatureTest(CKM_ECDSA, hash_oid, EcHashToComboMech(hash_oid)) {} }; struct Pkcs11EcdsaTestParams { @@ -88,7 +108,8 @@ TEST_F(Pkcs11EcdsaSha256Test, ImportOnlyAlgorithmParams) { sizeof(kP256Pkcs8OnlyAlgorithmParams)); DataBuffer data(kP256Data, sizeof(kP256Data)); DataBuffer sig; - EXPECT_TRUE(ImportPrivateKeyAndSignHashedData(k, data, &sig)); + DataBuffer sig2; + EXPECT_TRUE(ImportPrivateKeyAndSignHashedData(k, data, &sig, &sig2)); }; // Importing a private key in PKCS#8 format must succeed when the outer AlgID @@ -99,7 +120,8 @@ TEST_F(Pkcs11EcdsaSha256Test, ImportMatchingCurveOIDAndAlgorithmParams) { sizeof(kP256Pkcs8MatchingCurveOIDAndAlgorithmParams)); DataBuffer data(kP256Data, sizeof(kP256Data)); DataBuffer sig; - EXPECT_TRUE(ImportPrivateKeyAndSignHashedData(k, data, &sig)); + DataBuffer sig2; + EXPECT_TRUE(ImportPrivateKeyAndSignHashedData(k, data, &sig, &sig2)); }; // Importing a private key in PKCS#8 format must succeed when the outer AlgID @@ -110,7 +132,8 @@ TEST_F(Pkcs11EcdsaSha256Test, ImportDissimilarCurveOIDAndAlgorithmParams) { sizeof(kP256Pkcs8DissimilarCurveOIDAndAlgorithmParams)); DataBuffer data(kP256Data, sizeof(kP256Data)); DataBuffer sig; - EXPECT_TRUE(ImportPrivateKeyAndSignHashedData(k, data, &sig)); + DataBuffer sig2; + EXPECT_TRUE(ImportPrivateKeyAndSignHashedData(k, data, &sig, &sig2)); }; // Importing a private key in PKCS#8 format must fail when the outer ASN.1 diff --git a/gtests/pk11_gtest/pk11_gtest.gyp b/gtests/pk11_gtest/pk11_gtest.gyp index 4171ea3828..44778f51b4 100644 --- a/gtests/pk11_gtest/pk11_gtest.gyp +++ b/gtests/pk11_gtest/pk11_gtest.gyp @@ -44,6 +44,7 @@ 'pk11_rsapkcs1_unittest.cc', 'pk11_rsapss_unittest.cc', 'pk11_seed_cbc_unittest.cc', + 'pk11_signature_test.cc', '<(DEPTH)/gtests/common/gtests.cc' ], 'dependencies': [ diff --git a/gtests/pk11_gtest/pk11_rsapkcs1_unittest.cc b/gtests/pk11_gtest/pk11_rsapkcs1_unittest.cc index db31f0dacb..7ae7189823 100644 --- a/gtests/pk11_gtest/pk11_rsapkcs1_unittest.cc +++ b/gtests/pk11_gtest/pk11_rsapkcs1_unittest.cc @@ -15,6 +15,7 @@ #include "pk11pub.h" #include "secerr.h" #include "sechash.h" +#include "pk11_signature_test.h" #include "testvectors/rsa_signature_2048_sha224-vectors.h" #include "testvectors/rsa_signature_2048_sha256-vectors.h" @@ -28,10 +29,46 @@ namespace nss_test { +CK_MECHANISM_TYPE RsaHashToComboMech(SECOidTag hash) { + switch (hash) { + case SEC_OID_SHA1: + return CKM_SHA1_RSA_PKCS; + case SEC_OID_SHA224: + return CKM_SHA224_RSA_PKCS; + case SEC_OID_SHA256: + return CKM_SHA256_RSA_PKCS; + case SEC_OID_SHA384: + return CKM_SHA384_RSA_PKCS; + case SEC_OID_SHA512: + return CKM_SHA512_RSA_PKCS; + default: + break; + } + return CKM_INVALID_MECHANISM; +} + +class Pkcs11RsaBaseTest : public Pk11SignatureTest { + protected: + Pkcs11RsaBaseTest(SECOidTag hashOid) + : Pk11SignatureTest(CKM_RSA_PKCS, hashOid, RsaHashToComboMech(hashOid)) {} + + void Verify(const RsaSignatureTestVector vec) { + Pkcs11SignatureTestParams params = { + DataBuffer(), DataBuffer(vec.public_key.data(), vec.public_key.size()), + DataBuffer(vec.msg.data(), vec.msg.size()), + DataBuffer(vec.sig.data(), vec.sig.size())}; + Pk11SignatureTest::Verify(params, (bool)vec.valid); + } +}; + class Pkcs11RsaPkcs1WycheproofTest - : public ::testing::TestWithParam { + : public Pkcs11RsaBaseTest, + public ::testing::WithParamInterface { + public: + Pkcs11RsaPkcs1WycheproofTest() : Pkcs11RsaBaseTest(GetParam().hash_oid) {} + protected: - void Derive(const RsaSignatureTestVector vec) { + void Verify1(const RsaSignatureTestVector vec) { SECItem spki_item = {siBuffer, toUcharPtr(vec.public_key.data()), static_cast(vec.public_key.size())}; @@ -210,7 +247,13 @@ TEST(RsaPkcs1Test, RequireNullParameter) { #endif } -TEST_P(Pkcs11RsaPkcs1WycheproofTest, Verify) { Derive(GetParam()); } +TEST_P(Pkcs11RsaPkcs1WycheproofTest, Verify) { + /* Using VFY_ interface */ + Verify1(GetParam()); + /* Using PKCS #11 interface */ + setSkipRaw(true); + Verify(GetParam()); +} INSTANTIATE_TEST_SUITE_P( Wycheproof2048RsaSignatureSha224Test, Pkcs11RsaPkcs1WycheproofTest, diff --git a/gtests/pk11_gtest/pk11_rsapss_unittest.cc b/gtests/pk11_gtest/pk11_rsapss_unittest.cc index 06c3ae32a6..e8428f794f 100644 --- a/gtests/pk11_gtest/pk11_rsapss_unittest.cc +++ b/gtests/pk11_gtest/pk11_rsapss_unittest.cc @@ -9,7 +9,6 @@ #include "pk11pub.h" #include "sechash.h" -#include "cpputil.h" #include "databuffer.h" #include "gtest/gtest.h" @@ -28,83 +27,68 @@ namespace nss_test { -class Pkcs11RsaPssTestWycheproof - : public ::testing::TestWithParam { - protected: - void TestPss(const RsaPssTestVector& vec) { - SECItem spki_item = {siBuffer, toUcharPtr(vec.public_key.data()), - static_cast(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(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(hash.len())}; - SECItem sig_item = {siBuffer, toUcharPtr(vec.sig.data()), - static_cast(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(&pss_params), - sizeof(pss_params)}; - - rv = PK11_VerifyWithMechanism(pub_key.get(), CKM_RSA_PKCS_PSS, ¶ms, - &sig_item, &hash_item, nullptr); - EXPECT_EQ(vec.valid ? SECSuccess : SECFailure, rv); - }; -}; +CK_MECHANISM_TYPE RsaPssMapCombo(SECOidTag hashOid) { + switch (hashOid) { + case SEC_OID_SHA1: + return CKM_SHA1_RSA_PKCS_PSS; + case SEC_OID_SHA224: + return CKM_SHA224_RSA_PKCS_PSS; + case SEC_OID_SHA256: + return CKM_SHA256_RSA_PKCS_PSS; + case SEC_OID_SHA384: + return CKM_SHA384_RSA_PKCS_PSS; + case SEC_OID_SHA512: + return CKM_SHA512_RSA_PKCS_PSS; + default: + break; + } + return CKM_INVALID_MECHANISM; +} -class Pkcs11RsaPssTest : public Pk11SignatureTest { - public: - Pkcs11RsaPssTest() : Pk11SignatureTest(CKM_RSA_PKCS_PSS, SEC_OID_SHA1) { - pss_params_.hashAlg = CKM_SHA_1; - pss_params_.mgf = CKG_MGF1_SHA1; - pss_params_.sLen = HASH_ResultLenByOidTag(SEC_OID_SHA1); +class Pkcs11RsaPssTestBase : public Pk11SignatureTest { + protected: + Pkcs11RsaPssTestBase(SECOidTag hashOid, CK_RSA_PKCS_MGF_TYPE mgf, int sLen) + : Pk11SignatureTest(CKM_RSA_PKCS_PSS, hashOid, RsaPssMapCombo(hashOid)) { + pss_params_.hashAlg = PK11_AlgtagToMechanism(hashOid); + pss_params_.mgf = mgf; + pss_params_.sLen = sLen; params_.type = siBuffer; params_.data = reinterpret_cast(&pss_params_); params_.len = sizeof(pss_params_); } - protected: const SECItem* parameters() const { return ¶ms_; } + void Verify(const RsaPssTestVector& vec) { + Pkcs11SignatureTestParams params = { + DataBuffer(), DataBuffer(vec.public_key.data(), vec.public_key.size()), + DataBuffer(vec.msg.data(), vec.msg.size()), + DataBuffer(vec.sig.data(), vec.sig.size())}; + + Pk11SignatureTest::Verify(params, vec.valid); + } + private: CK_RSA_PKCS_PSS_PARAMS pss_params_; SECItem params_; }; +class Pkcs11RsaPssTest : public Pkcs11RsaPssTestBase { + public: + Pkcs11RsaPssTest() + : Pkcs11RsaPssTestBase(SEC_OID_SHA1, CKG_MGF1_SHA1, SHA1_LENGTH) {} +}; + +class Pkcs11RsaPssTestWycheproof + : public Pkcs11RsaPssTestBase, + public ::testing::WithParamInterface { + public: + Pkcs11RsaPssTestWycheproof() + : Pkcs11RsaPssTestBase(GetParam().hash_oid, GetParam().mgf_hash, + GetParam().sLen) {} +}; + TEST_F(Pkcs11RsaPssTest, GenerateAndSignAndVerify) { // Sign data with a 1024-bit RSA key, using PSS/SHA-256. SECOidTag hashOid = SEC_OID_SHA256; @@ -179,7 +163,9 @@ class Pkcs11RsaPssVectorTest : public Pkcs11RsaPssTest, public ::testing::WithParamInterface {}; -TEST_P(Pkcs11RsaPssVectorTest, Verify) { Verify(GetParam()); } +TEST_P(Pkcs11RsaPssVectorTest, Verify) { + Pk11SignatureTest::Verify(GetParam()); +} TEST_P(Pkcs11RsaPssVectorTest, SignAndVerify) { SignAndVerify(GetParam()); } @@ -227,7 +213,7 @@ static const Pkcs11SignatureTestParams kRsaPssVectors[] = { INSTANTIATE_TEST_SUITE_P(RsaPssSignVerify, Pkcs11RsaPssVectorTest, ::testing::ValuesIn(kRsaPssVectors)); -TEST_P(Pkcs11RsaPssTestWycheproof, Verify) { TestPss(GetParam()); } +TEST_P(Pkcs11RsaPssTestWycheproof, Verify) { Verify(GetParam()); } INSTANTIATE_TEST_SUITE_P( Wycheproof2048RsaPssSha120Test, Pkcs11RsaPssTestWycheproof, diff --git a/gtests/pk11_gtest/pk11_signature_test.cc b/gtests/pk11_gtest/pk11_signature_test.cc new file mode 100644 index 0000000000..7ef51812c9 --- /dev/null +++ b/gtests/pk11_gtest/pk11_signature_test.cc @@ -0,0 +1,181 @@ +/* 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 +#include "nss.h" +#include "pk11pub.h" +#include "sechash.h" +#include "prerror.h" + +#include "cpputil.h" +#include "nss_scoped_ptrs.h" +#include "databuffer.h" + +#include "gtest/gtest.h" +#include "pk11_signature_test.h" + +namespace nss_test { + +ScopedSECKEYPrivateKey Pk11SignatureTest::ImportPrivateKey( + const DataBuffer& pkcs8) { + ScopedPK11SlotInfo slot(PK11_GetInternalSlot()); + if (!slot) { + ADD_FAILURE() << "No slot"; + return nullptr; + } + + SECItem pkcs8Item = {siBuffer, toUcharPtr(pkcs8.data()), + static_cast(pkcs8.len())}; + + SECKEYPrivateKey* key = nullptr; + SECStatus rv = PK11_ImportDERPrivateKeyInfoAndReturnKey( + slot.get(), &pkcs8Item, nullptr, nullptr, false, false, KU_ALL, &key, + nullptr); + + if (rv != SECSuccess) { + return nullptr; + } + + return ScopedSECKEYPrivateKey(key); +} + +ScopedSECKEYPublicKey Pk11SignatureTest::ImportPublicKey( + const DataBuffer& spki) { + SECItem spkiItem = {siBuffer, toUcharPtr(spki.data()), + static_cast(spki.len())}; + + ScopedCERTSubjectPublicKeyInfo certSpki( + SECKEY_DecodeDERSubjectPublicKeyInfo(&spkiItem)); + if (!certSpki) { + return nullptr; + } + + return ScopedSECKEYPublicKey(SECKEY_ExtractPublicKey(certSpki.get())); +} + +bool Pk11SignatureTest::SignHashedData(ScopedSECKEYPrivateKey& privKey, + const DataBuffer& hash, + DataBuffer* sig) { + SECItem hashItem = {siBuffer, toUcharPtr(hash.data()), + static_cast(hash.len())}; + unsigned int sigLen = PK11_SignatureLen(privKey.get()); + EXPECT_LT(0, (int)sigLen); + sig->Allocate(static_cast(sigLen)); + SECItem sigItem = {siBuffer, toUcharPtr(sig->data()), + static_cast(sig->len())}; + SECStatus rv = PK11_SignWithMechanism(privKey.get(), mechanism_, parameters(), + &sigItem, &hashItem); + EXPECT_EQ(sigLen, sigItem.len); + return rv == SECSuccess; +} + +bool Pk11SignatureTest::SignData(ScopedSECKEYPrivateKey& privKey, + const DataBuffer& data, DataBuffer* sig) { + unsigned int sigLen = PK11_SignatureLen(privKey.get()); + bool result = true; + EXPECT_LT(0, (int)sigLen); + sig->Allocate(static_cast(sigLen)); + + // test the hash and verify interface */ + PK11Context* context = PK11_CreateContextByPrivKey( + combo_, CKA_SIGN, privKey.get(), parameters()); + if (context == NULL) { + ADD_FAILURE() << "Failed to sign data: couldn't create context" + << "\n" + << "mech=0x" << std::hex << combo_ << "\n" + << "Error: " << PORT_ErrorToString(PORT_GetError()); + return false; + } + SECStatus rv = PK11_DigestOp(context, data.data(), data.len()); + if (rv != SECSuccess) { + ADD_FAILURE() << "Failed to sign data: Update failed\n" + << "Error: " << PORT_ErrorToString(PORT_GetError()); + PK11_DestroyContext(context, PR_TRUE); + return false; + } + unsigned int len = sigLen; + rv = PK11_DigestFinal(context, sig->data(), &len, sigLen); + if (rv != SECSuccess) { + ADD_FAILURE() << "Failed to sign data: final failed\n" + << "Error: " << PORT_ErrorToString(PORT_GetError()); + result = false; + } + if (len != sigLen) { + ADD_FAILURE() << "sign data: unexpected len " << len << "expected" + << sigLen; + result = false; + } + PK11_DestroyContext(context, PR_TRUE); + return result; +} + +bool Pk11SignatureTest::ImportPrivateKeyAndSignHashedData( + const DataBuffer& pkcs8, const DataBuffer& data, DataBuffer* sig, + DataBuffer* sig2) { + ScopedSECKEYPrivateKey privKey(ImportPrivateKey(pkcs8)); + if (!privKey) { + return false; + } + + DataBuffer hash; + if (!ComputeHash(data, &hash)) { + ADD_FAILURE() << "Failed to compute hash"; + return false; + } + if (!SignHashedData(privKey, hash, sig)) { + ADD_FAILURE() << "Failed to sign hashed data"; + return false; + } + if (!SignData(privKey, data, sig2)) { + /* failure was already added by SignData, with an error message */ + return false; + } + return true; +} + +void Pk11SignatureTest::Verify(const Pkcs11SignatureTestParams& params, + const DataBuffer& sig, bool valid) { + ScopedSECKEYPublicKey pubKey(ImportPublicKey(params.spki_)); + ASSERT_TRUE(pubKey); + + SECStatus rv; + DataBuffer hash; + + SECItem sigItem = {siBuffer, toUcharPtr(sig.data()), + static_cast(sig.len())}; + + /* RSA single shot requires encoding the hash before calling + * VerifyWithMechanism. We already check that mechanism + * with the VFY_ interface, so just do the combined hash/Verify + * in that case */ + if (!skip_raw_) { + ASSERT_TRUE(ComputeHash(params.data_, &hash)); + + // Verify. + SECItem hashItem = {siBuffer, toUcharPtr(hash.data()), + static_cast(hash.len())}; + rv = PK11_VerifyWithMechanism(pubKey.get(), mechanism_, parameters(), + &sigItem, &hashItem, nullptr); + EXPECT_EQ(rv, valid ? SECSuccess : SECFailure); + } + + // test the hash and verify interface */ + PK11Context* context = PK11_CreateContextByPubKey( + combo_, CKA_VERIFY, pubKey.get(), parameters(), NULL); + /* we assert here because we'll crash if we try to continue + * without a context. */ + ASSERT_NE((void*)context, (void*)NULL) + << "CreateContext failed Error:" << PORT_ErrorToString(PORT_GetError()) + << "\n"; + rv = PK11_DigestOp(context, params.data_.data(), params.data_.len()); + /* expect success unconditionally here */ + EXPECT_EQ(rv, SECSuccess); + unsigned int len; + rv = PK11_DigestFinal(context, sigItem.data, &len, sigItem.len); + EXPECT_EQ(rv, valid ? SECSuccess : SECFailure) + << "verify failed Error:" << PORT_ErrorToString(PORT_GetError()) << "\n"; + PK11_DestroyContext(context, PR_TRUE); +} + +} // namespace nss_test diff --git a/gtests/pk11_gtest/pk11_signature_test.h b/gtests/pk11_gtest/pk11_signature_test.h index cd46f17d74..82ef038963 100644 --- a/gtests/pk11_gtest/pk11_signature_test.h +++ b/gtests/pk11_gtest/pk11_signature_test.h @@ -7,7 +7,6 @@ #include "pk11pub.h" #include "sechash.h" -#include "cpputil.h" #include "nss_scoped_ptrs.h" #include "databuffer.h" @@ -25,46 +24,18 @@ struct Pkcs11SignatureTestParams { class Pk11SignatureTest : public ::testing::Test { protected: - Pk11SignatureTest(CK_MECHANISM_TYPE mech, SECOidTag hash_oid) - : mechanism_(mech), hash_oid_(hash_oid) {} + Pk11SignatureTest(CK_MECHANISM_TYPE mech, SECOidTag hash_oid, + CK_MECHANISM_TYPE combo) + : mechanism_(mech), hash_oid_(hash_oid), combo_(combo) { + skip_raw_ = false; + } virtual const SECItem* parameters() const { return nullptr; } CK_MECHANISM_TYPE mechanism() const { return mechanism_; } + void setSkipRaw(bool skip_raw) { skip_raw_ = true; } - ScopedSECKEYPrivateKey ImportPrivateKey(const DataBuffer& pkcs8) { - ScopedPK11SlotInfo slot(PK11_GetInternalSlot()); - if (!slot) { - ADD_FAILURE() << "No slot"; - return nullptr; - } - - SECItem pkcs8Item = {siBuffer, toUcharPtr(pkcs8.data()), - static_cast(pkcs8.len())}; - - SECKEYPrivateKey* key = nullptr; - SECStatus rv = PK11_ImportDERPrivateKeyInfoAndReturnKey( - slot.get(), &pkcs8Item, nullptr, nullptr, false, false, KU_ALL, &key, - nullptr); - - if (rv != SECSuccess) { - return nullptr; - } - - return ScopedSECKEYPrivateKey(key); - } - - ScopedSECKEYPublicKey ImportPublicKey(const DataBuffer& spki) { - SECItem spkiItem = {siBuffer, toUcharPtr(spki.data()), - static_cast(spki.len())}; - - ScopedCERTSubjectPublicKeyInfo certSpki( - SECKEY_DecodeDERSubjectPublicKeyInfo(&spkiItem)); - if (!certSpki) { - return nullptr; - } - - return ScopedSECKEYPublicKey(SECKEY_ExtractPublicKey(certSpki.get())); - } + ScopedSECKEYPrivateKey ImportPrivateKey(const DataBuffer& pkcs8); + ScopedSECKEYPublicKey ImportPublicKey(const DataBuffer& spki); bool ComputeHash(const DataBuffer& data, DataBuffer* hash) { hash->Allocate(static_cast(HASH_ResultLenByOidTag(hash_oid_))); @@ -74,66 +45,37 @@ class Pk11SignatureTest : public ::testing::Test { } bool SignHashedData(ScopedSECKEYPrivateKey& privKey, const DataBuffer& hash, - DataBuffer* sig) { - SECItem hashItem = {siBuffer, toUcharPtr(hash.data()), - static_cast(hash.len())}; - int sigLen = PK11_SignatureLen(privKey.get()); - EXPECT_LT(0, sigLen); - sig->Allocate(static_cast(sigLen)); - SECItem sigItem = {siBuffer, toUcharPtr(sig->data()), - static_cast(sig->len())}; - SECStatus rv = PK11_SignWithMechanism(privKey.get(), mechanism_, - parameters(), &sigItem, &hashItem); - return rv == SECSuccess; - } - + DataBuffer* sig); + bool SignData(ScopedSECKEYPrivateKey& privKey, const DataBuffer& data, + DataBuffer* sig); bool ImportPrivateKeyAndSignHashedData(const DataBuffer& pkcs8, const DataBuffer& data, - DataBuffer* sig) { - ScopedSECKEYPrivateKey privKey(ImportPrivateKey(pkcs8)); - if (!privKey) { - return false; - } - - DataBuffer hash; - if (!ComputeHash(data, &hash)) { - ADD_FAILURE() << "Failed to compute hash"; - return false; - } - return SignHashedData(privKey, hash, sig); - } - - void Verify(const Pkcs11SignatureTestParams& params, const DataBuffer& sig) { - ScopedSECKEYPublicKey pubKey(ImportPublicKey(params.spki_)); - ASSERT_TRUE(pubKey); - - DataBuffer hash; - ASSERT_TRUE(ComputeHash(params.data_, &hash)); + DataBuffer* sig, DataBuffer* sig2); + void Verify(const Pkcs11SignatureTestParams& params, const DataBuffer& sig, + bool valid); - // Verify. - SECItem hashItem = {siBuffer, toUcharPtr(hash.data()), - static_cast(hash.len())}; - SECItem sigItem = {siBuffer, toUcharPtr(sig.data()), - static_cast(sig.len())}; - SECStatus rv = PK11_VerifyWithMechanism( - pubKey.get(), mechanism_, parameters(), &sigItem, &hashItem, nullptr); - EXPECT_EQ(rv, SECSuccess); + void Verify(const Pkcs11SignatureTestParams& params, bool valid) { + Verify(params, params.signature_, valid); } void Verify(const Pkcs11SignatureTestParams& params) { - Verify(params, params.signature_); + Verify(params, params.signature_, true); } void SignAndVerify(const Pkcs11SignatureTestParams& params) { DataBuffer sig; - ASSERT_TRUE( - ImportPrivateKeyAndSignHashedData(params.pkcs8_, params.data_, &sig)); - Verify(params, sig); + DataBuffer sig2; + ASSERT_TRUE(ImportPrivateKeyAndSignHashedData(params.pkcs8_, params.data_, + &sig, &sig2)); + Verify(params, sig, true); + Verify(params, sig2, true); } private: CK_MECHANISM_TYPE mechanism_; SECOidTag hash_oid_; + CK_MECHANISM_TYPE combo_; + bool skip_raw_; }; } // namespace nss_test diff --git a/lib/nss/nss.def b/lib/nss/nss.def index db912e1ec9..91486ceff0 100644 --- a/lib/nss/nss.def +++ b/lib/nss/nss.def @@ -1219,4 +1219,11 @@ PK11_HPKE_ExportContext; PK11_HPKE_ImportContext; ;+ local: ;+ *; -;+}; \ No newline at end of file +;+}; +;+NSS_3.64 { # NSS 3.64 release +;+ global: +PK11_CreateContextByPubKey; +PK11_CreateContextByPrivKey; +;+ local: +;+ *; +;+}; diff --git a/lib/pk11wrap/pk11cxt.c b/lib/pk11wrap/pk11cxt.c index b1569ebf94..9deff08d5e 100644 --- a/lib/pk11wrap/pk11cxt.c +++ b/lib/pk11wrap/pk11cxt.c @@ -125,7 +125,7 @@ SECStatus pk11_restoreContext(PK11Context *context, void *space, unsigned long savedLength) { CK_RV crv; - CK_OBJECT_HANDLE objectID = (context->key) ? context->key->objectID : CK_INVALID_HANDLE; + CK_OBJECT_HANDLE objectID = context->objectID; PORT_Assert(space != NULL); if (space == NULL) { @@ -150,7 +150,7 @@ SECStatus pk11_Finalize(PK11Context *context); */ static CK_RV pk11_contextInitMessage(PK11Context *context, CK_MECHANISM_PTR mech, - PK11SymKey *key, CK_C_MessageEncryptInit initFunc, + CK_C_MessageEncryptInit initFunc, CK_FLAGS flags, CK_RV scrv) { PK11SlotInfo *slot = context->slot; @@ -197,7 +197,6 @@ static SECStatus pk11_context_init(PK11Context *context, CK_MECHANISM *mech_info) { CK_RV crv; - PK11SymKey *symKey = context->key; SECStatus rv = SECSuccess; context->simulate_message = PR_FALSE; @@ -212,7 +211,7 @@ pk11_context_init(PK11Context *context, CK_MECHANISM *mech_info) if (context->fortezzaHack) { CK_ULONG count = 0; /* generate the IV for fortezza */ - crv = PK11_GETTAB(context->slot)->C_EncryptInit(context->session, mech_info, symKey->objectID); + crv = PK11_GETTAB(context->slot)->C_EncryptInit(context->session, mech_info, context->objectID); if (crv != CKR_OK) { PK11_ExitContextMonitor(context); break; @@ -221,7 +220,7 @@ pk11_context_init(PK11Context *context, CK_MECHANISM *mech_info) ->C_EncryptFinal(context->session, NULL, &count); } - crv = PK11_GETTAB(context->slot)->C_DecryptInit(context->session, mech_info, symKey->objectID); + crv = PK11_GETTAB(context->slot)->C_DecryptInit(context->session, mech_info, context->objectID); PK11_ExitContextMonitor(context); break; case CKA_SIGN: @@ -230,8 +229,15 @@ pk11_context_init(PK11Context *context, CK_MECHANISM *mech_info) PK11_ExitContextMonitor(context); break; case CKA_VERIFY: + /* NOTE: we previously has this set to C_SignInit for Macing. + * It turns out now one could possibly use it that way, though, + * because PK11_HashOp() always called C_VerifyUpdate on CKA_VERIFY, + * which would have failed. So everyone just calls us with CKA_SIGN + * when Macing even when they are verifying, no need to 'do it + * for them'. It needs to be VerifyInit now so that we can do + * PKCS #11 hash/Verify combo operations. */ PK11_EnterContextMonitor(context); - crv = PK11_GETTAB(context->slot)->C_SignInit(context->session, mech_info, symKey->objectID); + crv = PK11_GETTAB(context->slot)->C_VerifyInit(context->session, mech_info, context->objectID); PK11_ExitContextMonitor(context); break; case CKA_DIGEST: @@ -241,22 +247,22 @@ pk11_context_init(PK11Context *context, CK_MECHANISM *mech_info) break; case CKA_NSS_MESSAGE | CKA_ENCRYPT: - crv = pk11_contextInitMessage(context, mech_info, symKey, + crv = pk11_contextInitMessage(context, mech_info, PK11_GETTAB(context->slot)->C_MessageEncryptInit, CKF_MESSAGE_ENCRYPT, CKR_OK); break; case CKA_NSS_MESSAGE | CKA_DECRYPT: - crv = pk11_contextInitMessage(context, mech_info, symKey, + crv = pk11_contextInitMessage(context, mech_info, PK11_GETTAB(context->slot)->C_MessageDecryptInit, CKF_MESSAGE_DECRYPT, CKR_OK); break; case CKA_NSS_MESSAGE | CKA_SIGN: - crv = pk11_contextInitMessage(context, mech_info, symKey, + crv = pk11_contextInitMessage(context, mech_info, PK11_GETTAB(context->slot)->C_MessageSignInit, CKF_MESSAGE_SIGN, CKR_FUNCTION_NOT_SUPPORTED); break; case CKA_NSS_MESSAGE | CKA_VERIFY: - crv = pk11_contextInitMessage(context, mech_info, symKey, + crv = pk11_contextInitMessage(context, mech_info, PK11_GETTAB(context->slot)->C_MessageVerifyInit, CKF_MESSAGE_VERIFY, CKR_FUNCTION_NOT_SUPPORTED); break; @@ -348,16 +354,17 @@ _PK11_ContextGetAEADSimulation(PK11Context *context) */ static PK11Context * pk11_CreateNewContextInSlot(CK_MECHANISM_TYPE type, - PK11SlotInfo *slot, CK_ATTRIBUTE_TYPE operation, PK11SymKey *symKey, - SECItem *param) + PK11SlotInfo *slot, CK_ATTRIBUTE_TYPE operation, + PK11SymKey *symKey, CK_OBJECT_HANDLE objectID, + const SECItem *param, void *pwArg) { CK_MECHANISM mech_info; PK11Context *context; SECStatus rv; PORT_Assert(slot != NULL); - if (!slot || (!symKey && ((operation != CKA_DIGEST) || - (type == CKM_SKIPJACK_CBC64)))) { + if (!slot || ((objectID == CK_INVALID_HANDLE) && ((operation != CKA_DIGEST) || + (type == CKM_SKIPJACK_CBC64)))) { PORT_SetError(SEC_ERROR_INVALID_ARGS); return NULL; } @@ -382,10 +389,16 @@ pk11_CreateNewContextInSlot(CK_MECHANISM_TYPE type, /* initialize the critical fields of the context */ context->operation = operation; + /* If we were given a symKey, keep our own reference to it so + * that the key doesn't disappear in the middle of the operation + * if the caller frees it. Public and Private keys are not reference + * counted, so the caller just has to keep his copies around until + * the operation completes */ context->key = symKey ? PK11_ReferenceSymKey(symKey) : NULL; + context->objectID = objectID; context->slot = PK11_ReferenceSlot(slot); context->session = pk11_GetNewSession(slot, &context->ownSession); - context->cx = symKey ? symKey->cx : NULL; + context->pwArg = pwArg; /* get our session */ context->savedData = NULL; @@ -474,11 +487,11 @@ PK11_CreateContextByRawKey(PK11SlotInfo *slot, CK_MECHANISM_TYPE type, /* * Create a context from a key. We really should make sure we aren't using - * the same key in multiple session! + * the same key in multiple sessions! */ PK11Context * PK11_CreateContextBySymKey(CK_MECHANISM_TYPE type, CK_ATTRIBUTE_TYPE operation, - PK11SymKey *symKey, SECItem *param) + PK11SymKey *symKey, const SECItem *param) { PK11SymKey *newKey; PK11Context *context; @@ -491,13 +504,72 @@ PK11_CreateContextBySymKey(CK_MECHANISM_TYPE type, CK_ATTRIBUTE_TYPE operation, symKey = newKey; } - /* Context Adopts the symKey.... */ + /* Context keeps its reference to the symKey, so it's safe to + * free our reference we we are through, even though we may have + * created the key using pk11_ForceSlot. */ context = pk11_CreateNewContextInSlot(type, symKey->slot, operation, symKey, - param); + symKey->objectID, param, symKey->cx); PK11_FreeSymKey(symKey); return context; } +/* To support multipart public key operations (like hash/verify operations), + * we need to create contexts with public keys. */ +PK11Context * +PK11_CreateContextByPubKey(CK_MECHANISM_TYPE type, CK_ATTRIBUTE_TYPE operation, + SECKEYPublicKey *pubKey, const SECItem *param, + void *pwArg) +{ + PK11SlotInfo *slot = pubKey->pkcs11Slot; + SECItem nullparam = { 0, 0, 0 }; + + /* if this slot doesn't support the mechanism, go to a slot that does */ + /* public keys have all their data in the public key data structure, + * so there's no need to export the old key, just import this one. The + * import manages consistancy of the public key data structure */ + if (slot == NULL || !PK11_DoesMechanism(slot, type)) { + CK_OBJECT_HANDLE objectID; + slot = PK11_GetBestSlot(type, NULL); + if (slot == NULL) { + return NULL; + } + objectID = PK11_ImportPublicKey(slot, pubKey, PR_FALSE); + PK11_FreeSlot(slot); + if (objectID == CK_INVALID_HANDLE) { + return NULL; + } + } + + /* unlike symkeys, we accept a NULL parameter. map a null parameter + * to the empty parameter. This matches the semantics of + * PK11_VerifyWithMechanism */ + return pk11_CreateNewContextInSlot(type, pubKey->pkcs11Slot, operation, + NULL, pubKey->pkcs11ID, + param ? param : &nullparam, pwArg); +} + +/* To support multipart private key operations (like hash/sign operations), + * we need to create contexts with private keys. */ +PK11Context * +PK11_CreateContextByPrivKey(CK_MECHANISM_TYPE type, CK_ATTRIBUTE_TYPE operation, + SECKEYPrivateKey *privKey, const SECItem *param) +{ + SECItem nullparam = { 0, 0, 0 }; + /* Private keys are generally not movable. If the token the + * private key lives on can't do the operation, generally we are + * stuck anyway. So no need to try to manipulate the key into + * another token */ + + /* if this slot doesn't support the mechanism, go to a slot that does */ + /* unlike symkeys, we accept a NULL parameter. map a null parameter + * to the empty parameter. This matches the semantics of + * PK11_SignWithMechanism */ + return pk11_CreateNewContextInSlot(type, privKey->pkcs11Slot, operation, + NULL, privKey->pkcs11ID, + param ? param : &nullparam, + privKey->wincx); +} + /* * Digest contexts don't need keys, but the do need to find a slot. * Macing should use PK11_CreateContextBySymKey. @@ -523,7 +595,8 @@ PK11_CreateDigestContext(SECOidTag hashAlg) param.len = 0; param.type = 0; - context = pk11_CreateNewContextInSlot(type, slot, CKA_DIGEST, NULL, ¶m); + context = pk11_CreateNewContextInSlot(type, slot, CKA_DIGEST, NULL, + CK_INVALID_HANDLE, ¶m, NULL); PK11_FreeSlot(slot); return context; } @@ -541,7 +614,8 @@ PK11_CloneContext(PK11Context *old) unsigned long len; newcx = pk11_CreateNewContextInSlot(old->type, old->slot, old->operation, - old->key, old->param); + old->key, old->objectID, old->param, + old->pwArg); if (newcx == NULL) return NULL; diff --git a/lib/pk11wrap/pk11pub.h b/lib/pk11wrap/pk11pub.h index 1a074219b0..559fc3c661 100644 --- a/lib/pk11wrap/pk11pub.h +++ b/lib/pk11wrap/pk11pub.h @@ -811,7 +811,17 @@ SECStatus PK11_VerifyWithMechanism(SECKEYPublicKey *key, **********************************************************************/ void PK11_DestroyContext(PK11Context *context, PRBool freeit); PK11Context *PK11_CreateContextBySymKey(CK_MECHANISM_TYPE type, - CK_ATTRIBUTE_TYPE operation, PK11SymKey *symKey, SECItem *param); + CK_ATTRIBUTE_TYPE operation, + PK11SymKey *symKey, + const SECItem *param); +PK11Context *PK11_CreateContextByPubKey(CK_MECHANISM_TYPE type, + CK_ATTRIBUTE_TYPE operation, + SECKEYPublicKey *pubKey, + const SECItem *param, void *pwArg); +PK11Context *PK11_CreateContextByPrivKey(CK_MECHANISM_TYPE type, + CK_ATTRIBUTE_TYPE operation, + SECKEYPrivateKey *privKey, + const SECItem *param); PK11Context *PK11_CreateDigestContext(SECOidTag hashAlg); PK11Context *PK11_CloneContext(PK11Context *old); SECStatus PK11_DigestBegin(PK11Context *cx); @@ -1007,7 +1017,7 @@ PRBool SECMOD_HasRootCerts(void); /********************************************************************** * Other Utilities **********************************************************************/ -/* +/* * Get the state of the system FIPS mode - * NSS uses this to force FIPS mode if the system bit is on. This returns * the system state independent of the database state and can be called diff --git a/lib/pk11wrap/secmodti.h b/lib/pk11wrap/secmodti.h index 52c839119c..04c63a8690 100644 --- a/lib/pk11wrap/secmodti.h +++ b/lib/pk11wrap/secmodti.h @@ -149,12 +149,13 @@ struct PK11ContextStr { * doing (CKA_ENCRYPT, CKA_SIGN, * CKA_HASH, etc.) */ PK11SymKey *key; /* symetric key for this context */ + CK_OBJECT_HANDLE objectID; /* object handle to key */ PK11SlotInfo *slot; /* slot this context is using */ CK_SESSION_HANDLE session; /* session this context is using */ PZLock *sessionLock; /* lock before accessing a PKCS #11 * session */ PRBool ownSession; /* do we own the session? */ - void *cx; /* window context for login */ + void *pwArg; /* applicaton specific passwd arg */ void *savedData; /* save data when we are * multiplexing on a single context */ unsigned long savedLength; /* length of the saved context */ diff --git a/lib/softoken/pkcs11.c b/lib/softoken/pkcs11.c index 216c5ac184..33dacc6daf 100644 --- a/lib/softoken/pkcs11.c +++ b/lib/softoken/pkcs11.c @@ -318,6 +318,11 @@ static const struct mechanismList mechanisms[] = { { CKM_SHA256_RSA_PKCS, { RSA_MIN_MODULUS_BITS, CK_MAX, CKF_SN_VR }, PR_TRUE }, { CKM_SHA384_RSA_PKCS, { RSA_MIN_MODULUS_BITS, CK_MAX, CKF_SN_VR }, PR_TRUE }, { CKM_SHA512_RSA_PKCS, { RSA_MIN_MODULUS_BITS, CK_MAX, CKF_SN_VR }, PR_TRUE }, + { CKM_SHA1_RSA_PKCS_PSS, { RSA_MIN_MODULUS_BITS, CK_MAX, CKF_SN_VR }, PR_TRUE }, + { CKM_SHA224_RSA_PKCS_PSS, { RSA_MIN_MODULUS_BITS, CK_MAX, CKF_SN_VR }, PR_TRUE }, + { CKM_SHA256_RSA_PKCS_PSS, { RSA_MIN_MODULUS_BITS, CK_MAX, CKF_SN_VR }, PR_TRUE }, + { CKM_SHA384_RSA_PKCS_PSS, { RSA_MIN_MODULUS_BITS, CK_MAX, CKF_SN_VR }, PR_TRUE }, + { CKM_SHA512_RSA_PKCS_PSS, { RSA_MIN_MODULUS_BITS, CK_MAX, CKF_SN_VR }, PR_TRUE }, /* ------------------------- DSA Operations --------------------------- */ { CKM_DSA_KEY_PAIR_GEN, { DSA_MIN_P_BITS, DSA_MAX_P_BITS, CKF_GENERATE_KEY_PAIR }, PR_TRUE }, { CKM_DSA, { DSA_MIN_P_BITS, DSA_MAX_P_BITS, CKF_SN_VR }, PR_TRUE }, diff --git a/lib/softoken/pkcs11c.c b/lib/softoken/pkcs11c.c index b54d28de9e..9709f43394 100644 --- a/lib/softoken/pkcs11c.c +++ b/lib/softoken/pkcs11c.c @@ -57,6 +57,12 @@ #include "pkcs11f.h" +/* create a definition of SHA1 that's consistent + * with the rest of the CKM_SHAxxx hashes*/ +#define CKM_SHA1 CKM_SHA_1 +#define CKM_SHA1_HMAC CKM_SHA_1_HMAC +#define CKM_SHA1_HMAC_GENERAL CKM_SHA_1_HMAC_GENERAL + typedef struct { PRUint8 client_version[2]; PRUint8 random[46]; @@ -1858,12 +1864,12 @@ NSC_DigestInit(CK_SESSION_HANDLE hSession, return crv; } -#define INIT_MECH(mech, mmm) \ - case mech: { \ +#define INIT_MECH(mmm) \ + case CKM_##mmm: { \ mmm##Context *mmm##_ctx = mmm##_NewContext(); \ context->cipherInfo = (void *)mmm##_ctx; \ context->cipherInfoLen = mmm##_FlattenSize(mmm##_ctx); \ - context->currentMech = mech; \ + context->currentMech = CKM_##mmm; \ context->hashUpdate = (SFTKHash)mmm##_Update; \ context->end = (SFTKEnd)mmm##_End; \ context->destroy = (SFTKDestroy)mmm##_DestroyContext; \ @@ -1876,13 +1882,13 @@ NSC_DigestInit(CK_SESSION_HANDLE hSession, } switch (pMechanism->mechanism) { - INIT_MECH(CKM_MD2, MD2) - INIT_MECH(CKM_MD5, MD5) - INIT_MECH(CKM_SHA_1, SHA1) - INIT_MECH(CKM_SHA224, SHA224) - INIT_MECH(CKM_SHA256, SHA256) - INIT_MECH(CKM_SHA384, SHA384) - INIT_MECH(CKM_SHA512, SHA512) + INIT_MECH(MD2) + INIT_MECH(MD5) + INIT_MECH(SHA1) + INIT_MECH(SHA224) + INIT_MECH(SHA256) + INIT_MECH(SHA384) + INIT_MECH(SHA512) default: crv = CKR_MECHANISM_INVALID; @@ -2775,7 +2781,29 @@ NSC_SignInit(CK_SESSION_HANDLE hSession, } context->maxLen = nsslowkey_PrivateModulusLen(privKey); break; + +#define INIT_RSA_PSS_SIG_MECH(mmm) \ + case CKM_##mmm##_RSA_PKCS_PSS: \ + context->multi = PR_TRUE; \ + crv = sftk_doSub##mmm(context); \ + if (crv != CKR_OK) \ + break; \ + if (pMechanism->ulParameterLen != sizeof(CK_RSA_PKCS_PSS_PARAMS)) { \ + crv = CKR_MECHANISM_PARAM_INVALID; \ + break; \ + } \ + if (((const CK_RSA_PKCS_PSS_PARAMS *)pMechanism->pParameter)->hashAlg != CKM_##mmm) { \ + crv = CKR_MECHANISM_PARAM_INVALID; \ + break; \ + } \ + goto finish_rsa_pss; + INIT_RSA_PSS_SIG_MECH(SHA1) + INIT_RSA_PSS_SIG_MECH(SHA224) + INIT_RSA_PSS_SIG_MECH(SHA256) + INIT_RSA_PSS_SIG_MECH(SHA384) + INIT_RSA_PSS_SIG_MECH(SHA512) case CKM_RSA_PKCS_PSS: + finish_rsa_pss: if (key_type != CKK_RSA) { crv = CKR_KEY_TYPE_INCONSISTENT; break; @@ -2803,18 +2831,18 @@ NSC_SignInit(CK_SESSION_HANDLE hSession, context->maxLen = nsslowkey_PrivateModulusLen(info->key); break; -#define INIT_DSA_SIGN_MECH(mmm) \ +#define INIT_DSA_SIG_MECH(mmm) \ case CKM_DSA_##mmm: \ context->multi = PR_TRUE; \ crv = sftk_doSub##mmm(context); \ if (crv != CKR_OK) \ break; \ goto finish_dsa; - INIT_DSA_SIGN_MECH(SHA1) - INIT_DSA_SIGN_MECH(SHA224) - INIT_DSA_SIGN_MECH(SHA256) - INIT_DSA_SIGN_MECH(SHA384) - INIT_DSA_SIGN_MECH(SHA512) + INIT_DSA_SIG_MECH(SHA1) + INIT_DSA_SIG_MECH(SHA224) + INIT_DSA_SIG_MECH(SHA256) + INIT_DSA_SIG_MECH(SHA384) + INIT_DSA_SIG_MECH(SHA512) case CKM_DSA: finish_dsa: if (key_type != CKK_DSA) { @@ -2832,18 +2860,18 @@ NSC_SignInit(CK_SESSION_HANDLE hSession, break; -#define INIT_ECDSA_SIGN_MECH(mmm) \ +#define INIT_ECDSA_SIG_MECH(mmm) \ case CKM_ECDSA_##mmm: \ context->multi = PR_TRUE; \ crv = sftk_doSub##mmm(context); \ if (crv != CKR_OK) \ break; \ goto finish_ecdsa; - INIT_ECDSA_SIGN_MECH(SHA1) - INIT_ECDSA_SIGN_MECH(SHA224) - INIT_ECDSA_SIGN_MECH(SHA256) - INIT_ECDSA_SIGN_MECH(SHA384) - INIT_ECDSA_SIGN_MECH(SHA512) + INIT_ECDSA_SIG_MECH(SHA1) + INIT_ECDSA_SIG_MECH(SHA224) + INIT_ECDSA_SIG_MECH(SHA256) + INIT_ECDSA_SIG_MECH(SHA384) + INIT_ECDSA_SIG_MECH(SHA512) case CKM_ECDSA: finish_ecdsa: if (key_type != CKK_EC) { @@ -2879,23 +2907,12 @@ NSC_SignInit(CK_SESSION_HANDLE hSession, INIT_HMAC_MECH(MD2) INIT_HMAC_MECH(MD5) + INIT_HMAC_MECH(SHA1) INIT_HMAC_MECH(SHA224) INIT_HMAC_MECH(SHA256) INIT_HMAC_MECH(SHA384) INIT_HMAC_MECH(SHA512) - case CKM_SHA_1_HMAC_GENERAL: - PORT_Assert(pMechanism->pParameter); - if (!pMechanism->pParameter || pMechanism->ulParameterLen != sizeof(CK_MAC_GENERAL_PARAMS)) { - crv = CKR_MECHANISM_PARAM_INVALID; - break; - } - crv = sftk_doMACInit(pMechanism->mechanism, context, key, - *(CK_ULONG *)pMechanism->pParameter); - break; - case CKM_SHA_1_HMAC: - crv = sftk_doMACInit(pMechanism->mechanism, context, key, SHA1_LENGTH); - break; case CKM_AES_CMAC_GENERAL: PORT_Assert(pMechanism->pParameter); if (!pMechanism->pParameter || pMechanism->ulParameterLen != sizeof(CK_MAC_GENERAL_PARAMS)) { @@ -3557,7 +3574,14 @@ NSC_VerifyInit(CK_SESSION_HANDLE hSession, context->destroy = sftk_Null; } break; + + INIT_RSA_PSS_SIG_MECH(SHA1) + INIT_RSA_PSS_SIG_MECH(SHA224) + INIT_RSA_PSS_SIG_MECH(SHA256) + INIT_RSA_PSS_SIG_MECH(SHA384) + INIT_RSA_PSS_SIG_MECH(SHA512) case CKM_RSA_PKCS_PSS: + finish_rsa_pss: if (key_type != CKK_RSA) { crv = CKR_KEY_TYPE_INCONSISTENT; break; @@ -3583,13 +3607,14 @@ NSC_VerifyInit(CK_SESSION_HANDLE hSession, context->destroy = (SFTKDestroy)sftk_Space; context->verify = (SFTKVerify)sftk_RSACheckSignPSS; break; - case CKM_DSA_SHA1: - context->multi = PR_TRUE; - crv = sftk_doSubSHA1(context); - if (crv != CKR_OK) - break; - /* fall through */ + + INIT_DSA_SIG_MECH(SHA1) + INIT_DSA_SIG_MECH(SHA224) + INIT_DSA_SIG_MECH(SHA256) + INIT_DSA_SIG_MECH(SHA384) + INIT_DSA_SIG_MECH(SHA512) case CKM_DSA: + finish_dsa: if (key_type != CKK_DSA) { crv = CKR_KEY_TYPE_INCONSISTENT; break; @@ -3602,13 +3627,14 @@ NSC_VerifyInit(CK_SESSION_HANDLE hSession, context->verify = (SFTKVerify)nsc_DSA_Verify_Stub; context->destroy = sftk_Null; break; - case CKM_ECDSA_SHA1: - context->multi = PR_TRUE; - crv = sftk_doSubSHA1(context); - if (crv != CKR_OK) - break; - /* fall through */ + + INIT_ECDSA_SIG_MECH(SHA1) + INIT_ECDSA_SIG_MECH(SHA224) + INIT_ECDSA_SIG_MECH(SHA256) + INIT_ECDSA_SIG_MECH(SHA384) + INIT_ECDSA_SIG_MECH(SHA512) case CKM_ECDSA: + finish_ecdsa: if (key_type != CKK_EC) { crv = CKR_KEY_TYPE_INCONSISTENT; break; @@ -3625,24 +3651,12 @@ NSC_VerifyInit(CK_SESSION_HANDLE hSession, INIT_HMAC_MECH(MD2) INIT_HMAC_MECH(MD5) + INIT_HMAC_MECH(SHA1) INIT_HMAC_MECH(SHA224) INIT_HMAC_MECH(SHA256) INIT_HMAC_MECH(SHA384) INIT_HMAC_MECH(SHA512) - case CKM_SHA_1_HMAC_GENERAL: - PORT_Assert(pMechanism->pParameter); - if (!pMechanism->pParameter) { - crv = CKR_MECHANISM_PARAM_INVALID; - break; - } - crv = sftk_doMACInit(pMechanism->mechanism, context, key, - *(CK_ULONG *)pMechanism->pParameter); - break; - case CKM_SHA_1_HMAC: - crv = sftk_doMACInit(pMechanism->mechanism, context, key, SHA1_LENGTH); - break; - case CKM_SSL3_MD5_MAC: PORT_Assert(pMechanism->pParameter); if (!pMechanism->pParameter) {