From 7f3606a84f6c62b002246ee73121279e59f83437 Mon Sep 17 00:00:00 2001 From: Hans Petter Jansson Date: Thu, 28 May 2020 22:44:22 +0200 Subject: [PATCH] CKM_(EC)DSA_SHAxxx mechs: Add some missing pieces. This includes pairwise consistency checks and entry points for power-on self tests. --- cmd/lib/pk11table.c | 8 ++ lib/pk11wrap/pk11mech.c | 8 ++ lib/softoken/pkcs11c.c | 213 +++++++++++++++++++++++++++------------- lib/softoken/softoken.h | 10 ++ 4 files changed, 169 insertions(+), 70 deletions(-) Index: nss/cmd/lib/pk11table.c =================================================================== --- nss.orig/cmd/lib/pk11table.c +++ nss/cmd/lib/pk11table.c @@ -274,6 +274,10 @@ const Constant _consts[] = { mkEntry(CKM_DSA_KEY_PAIR_GEN, Mechanism), mkEntry(CKM_DSA, Mechanism), mkEntry(CKM_DSA_SHA1, Mechanism), + mkEntry(CKM_DSA_SHA224, Mechanism), + mkEntry(CKM_DSA_SHA256, Mechanism), + mkEntry(CKM_DSA_SHA384, Mechanism), + mkEntry(CKM_DSA_SHA512, Mechanism), mkEntry(CKM_DH_PKCS_KEY_PAIR_GEN, Mechanism), mkEntry(CKM_DH_PKCS_DERIVE, Mechanism), mkEntry(CKM_X9_42_DH_DERIVE, Mechanism), @@ -439,6 +443,10 @@ const Constant _consts[] = { mkEntry(CKM_EC_KEY_PAIR_GEN, Mechanism), mkEntry(CKM_ECDSA, Mechanism), mkEntry(CKM_ECDSA_SHA1, Mechanism), + mkEntry(CKM_ECDSA_SHA224, Mechanism), + mkEntry(CKM_ECDSA_SHA256, Mechanism), + mkEntry(CKM_ECDSA_SHA384, Mechanism), + mkEntry(CKM_ECDSA_SHA512, Mechanism), mkEntry(CKM_ECDH1_DERIVE, Mechanism), mkEntry(CKM_ECDH1_COFACTOR_DERIVE, Mechanism), mkEntry(CKM_EC_EDWARDS_KEY_PAIR_GEN, Mechanism), Index: nss/lib/pk11wrap/pk11mech.c =================================================================== --- nss.orig/lib/pk11wrap/pk11mech.c +++ nss/lib/pk11wrap/pk11mech.c @@ -377,6 +377,10 @@ PK11_GetKeyType(CK_MECHANISM_TYPE type, return CKK_RSA; case CKM_DSA: case CKM_DSA_SHA1: + case CKM_DSA_SHA224: + case CKM_DSA_SHA256: + case CKM_DSA_SHA384: + case CKM_DSA_SHA512: case CKM_DSA_KEY_PAIR_GEN: return CKK_DSA; case CKM_DH_PKCS_DERIVE: @@ -387,6 +391,10 @@ PK11_GetKeyType(CK_MECHANISM_TYPE type, return CKK_KEA; case CKM_ECDSA: case CKM_ECDSA_SHA1: + case CKM_ECDSA_SHA224: + case CKM_ECDSA_SHA256: + case CKM_ECDSA_SHA384: + case CKM_ECDSA_SHA512: case CKM_EC_KEY_PAIR_GEN: /* aka CKM_ECDSA_KEY_PAIR_GEN */ case CKM_ECDH1_DERIVE: return CKK_EC; /* CKK_ECDSA is deprecated */ Index: nss/lib/softoken/pkcs11c.c =================================================================== --- nss.orig/lib/softoken/pkcs11c.c +++ nss/lib/softoken/pkcs11c.c @@ -2677,7 +2677,7 @@ nsc_DSA_Verify_Stub(void *ctx, void *sig static SECStatus nsc_DSA_Sign_Stub(void *ctx, void *sigBuf, unsigned int *sigLen, unsigned int maxSigLen, - void *dataBuf, unsigned int dataLen) + const void *dataBuf, unsigned int dataLen) { NSSLOWKEYPrivateKey *key = (NSSLOWKEYPrivateKey *)ctx; SECItem signature = { siBuffer, (unsigned char *)sigBuf, maxSigLen }; @@ -2690,6 +2690,22 @@ nsc_DSA_Sign_Stub(void *ctx, void *sigBu return rv; } +SECStatus +DSA_HashSign(SECOidTag hashOid, NSSLOWKEYPrivateKey *key, + unsigned char *sig, unsigned int *sigLen, unsigned int maxLen, + const unsigned char *hash, unsigned int hashLen) +{ + SECStatus rv; + + rv = nsc_DSA_Sign_Stub(key, sig, sigLen, maxLen, hash, hashLen); + + if (rv != SECSuccess && PORT_GetError() == SEC_ERROR_LIBRARY_FAILURE) { + sftk_fatalError = PR_TRUE; + } + + return rv; +} + static SECStatus nsc_ECDSAVerifyStub(void *ctx, void *sigBuf, unsigned int sigLen, void *dataBuf, unsigned int dataLen) @@ -2703,7 +2719,7 @@ nsc_ECDSAVerifyStub(void *ctx, void *sig static SECStatus nsc_ECDSASignStub(void *ctx, void *sigBuf, unsigned int *sigLen, unsigned int maxSigLen, - void *dataBuf, unsigned int dataLen) + const void *dataBuf, unsigned int dataLen) { NSSLOWKEYPrivateKey *key = (NSSLOWKEYPrivateKey *)ctx; SECItem signature = { siBuffer, (unsigned char *)sigBuf, maxSigLen }; @@ -2744,6 +2760,22 @@ nsc_EDDSASignStub(void *ctx, void *sigBu return rv; } +SECStatus +ECDSA_HashSign(SECOidTag hashOid, NSSLOWKEYPrivateKey *key, + unsigned char *sig, unsigned int *sigLen, unsigned int maxLen, + const unsigned char *hash, unsigned int hashLen) +{ + SECStatus rv; + + rv = nsc_ECDSASignStub(key, sig, sigLen, maxLen, hash, hashLen); + + if (rv != SECSuccess && PORT_GetError() == SEC_ERROR_LIBRARY_FAILURE) { + sftk_fatalError = PR_TRUE; + } + + return rv; +} + /* NSC_SignInit setups up the signing operations. There are three basic * types of signing: * (1) the tradition single part, where "Raw RSA" or "Raw DSA" is applied @@ -3647,6 +3679,22 @@ NSC_VerifyInit(CK_SESSION_HANDLE hSessio info->hashOid = SEC_OID_##mmm; \ goto finish_rsa; +#define INIT_DSA_VFY_MECH(mmm) \ + case CKM_DSA_##mmm: \ + context->multi = PR_TRUE; \ + crv = sftk_doSub##mmm(context); \ + if (crv != CKR_OK) \ + break; \ + goto finish_dsa; + +#define INIT_ECDSA_VFY_MECH(mmm) \ + case CKM_ECDSA_##mmm: \ + context->multi = PR_TRUE; \ + crv = sftk_doSub##mmm(context); \ + if (crv != CKR_OK) \ + break; \ + goto finish_ecdsa; + switch (pMechanism->mechanism) { INIT_RSA_VFY_MECH(MD5) INIT_RSA_VFY_MECH(MD2) @@ -4904,6 +4952,73 @@ loser: #define PAIRWISE_DIGEST_LENGTH SHA224_LENGTH /* 224-bits */ #define PAIRWISE_MESSAGE_LENGTH 20 /* 160-bits */ +static CK_RV +pairwise_signverify_mech (CK_SESSION_HANDLE hSession, + SFTKObject *publicKey, SFTKObject *privateKey, + CK_MECHANISM mech, + CK_ULONG signature_length, + CK_ULONG pairwise_digest_length) +{ + /* Variables used for Signature/Verification functions. */ + /* Must be at least 256 bits for DSA2 digest */ + unsigned char *known_digest = (unsigned char *)"Mozilla Rules the World through NSS!"; + unsigned char *signature; + CK_RV crv; + + /* Allocate space for signature data. */ + signature = (unsigned char *)PORT_ZAlloc(signature_length); + if (signature == NULL) { + return CKR_HOST_MEMORY; + } + + /* Sign the known hash using the private key. */ + crv = NSC_SignInit(hSession, &mech, privateKey->handle); + if (crv != CKR_OK) { + PORT_Free(signature); + return crv; + } + + crv = NSC_Sign(hSession, + known_digest, + pairwise_digest_length, + signature, + &signature_length); + if (crv != CKR_OK) { + PORT_Free(signature); + return crv; + } + + /* detect trivial signing transforms */ + if ((signature_length >= pairwise_digest_length) && + (PORT_Memcmp(known_digest, signature + (signature_length - pairwise_digest_length), pairwise_digest_length) == 0)) { + PORT_Free(signature); + return CKR_DEVICE_ERROR; + } + + /* Verify the known hash using the public key. */ + crv = NSC_VerifyInit(hSession, &mech, publicKey->handle); + if (crv != CKR_OK) { + PORT_Free(signature); + return crv; + } + + crv = NSC_Verify(hSession, + known_digest, + pairwise_digest_length, + signature, + signature_length); + + /* Free signature data. */ + PORT_Free(signature); + + if ((crv == CKR_SIGNATURE_LEN_RANGE) || + (crv == CKR_SIGNATURE_INVALID)) { + return CKR_GENERAL_ERROR; + } + + return crv; +} + /* * FIPS 140-2 pairwise consistency check utilized to validate key pair. * @@ -4957,8 +5072,6 @@ sftk_PairwiseConsistencyCheck(CK_SESSION /* Variables used for Signature/Verification functions. */ /* Must be at least 256 bits for DSA2 digest */ - unsigned char *known_digest = (unsigned char *)"Mozilla Rules the World through NSS!"; - unsigned char *signature; CK_ULONG signature_length; if (keyType == CKK_RSA) { @@ -5112,80 +5225,36 @@ sftk_PairwiseConsistencyCheck(CK_SESSION } } +#define SIGNVERIFY_CHECK_MECH(vfymech) \ + mech.mechanism = vfymech; \ + crv = pairwise_signverify_mech (hSession, publicKey, privateKey, \ + mech, signature_length, pairwise_digest_length); \ + if (crv != CKR_OK) \ + return crv; + if (canSignVerify) { - /* Determine length of signature. */ switch (keyType) { case CKK_RSA: signature_length = modulusLen; - mech.mechanism = CKM_RSA_PKCS; + SIGNVERIFY_CHECK_MECH(CKM_SHA224_RSA_PKCS) break; case CKK_DSA: signature_length = DSA_MAX_SIGNATURE_LEN; pairwise_digest_length = subPrimeLen; - mech.mechanism = CKM_DSA; + SIGNVERIFY_CHECK_MECH(CKM_DSA_SHA224) break; case CKK_EC: signature_length = MAX_ECKEY_LEN * 2; - mech.mechanism = CKM_ECDSA; + SIGNVERIFY_CHECK_MECH(CKM_ECDSA_SHA224) break; case CKK_EC_EDWARDS: signature_length = ED25519_SIGN_LEN; - mech.mechanism = CKM_EDDSA; + SIGNVERIFY_CHECK_MECH(CKM_EDDSA) break; default: return CKR_DEVICE_ERROR; } - /* Allocate space for signature data. */ - signature = (unsigned char *)PORT_ZAlloc(signature_length); - if (signature == NULL) { - return CKR_HOST_MEMORY; - } - - /* Sign the known hash using the private key. */ - crv = NSC_SignInit(hSession, &mech, privateKey->handle); - if (crv != CKR_OK) { - PORT_Free(signature); - return crv; - } - - crv = NSC_Sign(hSession, - known_digest, - pairwise_digest_length, - signature, - &signature_length); - if (crv != CKR_OK) { - PORT_Free(signature); - return crv; - } - - /* detect trivial signing transforms */ - if ((signature_length >= pairwise_digest_length) && - (PORT_Memcmp(known_digest, signature + (signature_length - pairwise_digest_length), pairwise_digest_length) == 0)) { - PORT_Free(signature); - return CKR_DEVICE_ERROR; - } - - /* Verify the known hash using the public key. */ - crv = NSC_VerifyInit(hSession, &mech, publicKey->handle); - if (crv != CKR_OK) { - PORT_Free(signature); - return crv; - } - - crv = NSC_Verify(hSession, - known_digest, - pairwise_digest_length, - signature, - signature_length); - - /* Free signature data. */ - PORT_Free(signature); - - if ((crv == CKR_SIGNATURE_LEN_RANGE) || - (crv == CKR_SIGNATURE_INVALID)) { - return CKR_GENERAL_ERROR; - } if (crv != CKR_OK) { return crv; } Index: nss/lib/softoken/softoken.h =================================================================== --- nss.orig/lib/softoken/softoken.h +++ nss/lib/softoken/softoken.h @@ -35,6 +35,16 @@ RSA_HashCheckSign(SECOidTag hashOid, NSS const unsigned char *sig, unsigned int sigLen, const unsigned char *hash, unsigned int hashLen); +extern SECStatus +DSA_HashSign(SECOidTag hashOid, NSSLOWKEYPrivateKey *key, + unsigned char *sig, unsigned int *sigLen, unsigned int maxLen, + const unsigned char *hash, unsigned int hashLen); + +extern SECStatus +ECDSA_HashSign(SECOidTag hashOid, NSSLOWKEYPrivateKey *key, + unsigned char *sig, unsigned int *sigLen, unsigned int maxLen, + const unsigned char *hash, unsigned int hashLen); + /* ** Prepare a buffer for padded CBC encryption, growing to the appropriate ** boundary, filling with the appropriate padding.