Skip to content

Commit

Permalink
Bug 1702663 Need to support RSA PSS with Hashing PKCS #11 Mechanisms.
Browse files Browse the repository at this point in the history
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
  • Loading branch information
rjrelyea committed Apr 1, 2021
1 parent 7496e5f commit 5023aee
Show file tree
Hide file tree
Showing 15 changed files with 590 additions and 285 deletions.
15 changes: 15 additions & 0 deletions 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


1 change: 1 addition & 0 deletions gtests/pk11_gtest/manifest.mn
Expand Up @@ -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)

Expand Down
94 changes: 48 additions & 46 deletions gtests/pk11_gtest/pk11_dsa_unittest.cc
Expand Up @@ -6,72 +6,74 @@

#include <memory>
#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"

#include "testvectors/dsa-vectors.h"

namespace nss_test {

class Pkcs11DsaTest : public ::testing::TestWithParam<DsaTestVector> {
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<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;
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<unsigned int>(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<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);
};
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<DsaTestVector> {
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));
Expand Down
31 changes: 27 additions & 4 deletions gtests/pk11_gtest/pk11_ecdsa_unittest.cc
Expand Up @@ -8,6 +8,7 @@
#include "sechash.h"
#include "cryptohi.h"

#include "cpputil.h"
#include "gtest/gtest.h"
#include "nss_scoped_ptrs.h"

Expand All @@ -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 {
Expand Down Expand Up @@ -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
Expand All @@ -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
Expand All @@ -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
Expand Down
1 change: 1 addition & 0 deletions gtests/pk11_gtest/pk11_gtest.gyp
Expand Up @@ -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': [
Expand Down
49 changes: 46 additions & 3 deletions gtests/pk11_gtest/pk11_rsapkcs1_unittest.cc
Expand Up @@ -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"
Expand All @@ -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<RsaSignatureTestVector> {
: public Pkcs11RsaBaseTest,
public ::testing::WithParamInterface<RsaSignatureTestVector> {
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<unsigned int>(vec.public_key.size())};

Expand Down Expand Up @@ -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,
Expand Down

0 comments on commit 5023aee

Please sign in to comment.