diff options
author | Dana Keeler <dkeeler@mozilla.com> | 2022-03-09 02:25:51 +0000 |
---|---|---|
committer | Dana Keeler <dkeeler@mozilla.com> | 2022-03-09 02:25:51 +0000 |
commit | 7d2a566944c72a7347b569de6669c550fe846f6f (patch) | |
tree | 0f40418eeca48e4399043cb568d37686d6ebfc34 /lib | |
parent | a78986a387a20724dc0daafb93b734aeb7260247 (diff) | |
download | nss-hg-7d2a566944c72a7347b569de6669c550fe846f6f.tar.gz |
Bug 1755092 - rework signature verification in mozilla::pkix r=jschanck
The initial implementation of mozilla::pkix split signature verification into
two steps: digesting the data that had been signed and then verifying that
digest. This separation added complexity that was hidden by the VFY_* APIs.
However, those APIs are in need of improvements. This patch avoids the VFY_*
APIs as well as the additional complexity by removing the separate digest step
and using the PK11_Verify* APIs directly.
Differential Revision: https://phabricator.services.mozilla.com/D138605
Diffstat (limited to 'lib')
-rw-r--r-- | lib/mozpkix/include/pkix-test/pkixtestutil.h | 9 | ||||
-rw-r--r-- | lib/mozpkix/include/pkix/pkixder.h | 5 | ||||
-rw-r--r-- | lib/mozpkix/include/pkix/pkixnss.h | 12 | ||||
-rw-r--r-- | lib/mozpkix/include/pkix/pkixtypes.h | 24 | ||||
-rw-r--r-- | lib/mozpkix/include/pkix/pkixutil.h | 12 | ||||
-rw-r--r-- | lib/mozpkix/lib/pkixbuild.cpp | 24 | ||||
-rw-r--r-- | lib/mozpkix/lib/pkixc.cpp | 18 | ||||
-rw-r--r-- | lib/mozpkix/lib/pkixcheck.cpp | 5 | ||||
-rw-r--r-- | lib/mozpkix/lib/pkixder.cpp | 54 | ||||
-rw-r--r-- | lib/mozpkix/lib/pkixnss.cpp | 192 | ||||
-rw-r--r-- | lib/mozpkix/lib/pkixverify.cpp | 60 | ||||
-rw-r--r-- | lib/mozpkix/test-lib/pkixtestnss.cpp | 16 |
12 files changed, 263 insertions, 168 deletions
diff --git a/lib/mozpkix/include/pkix-test/pkixtestutil.h b/lib/mozpkix/include/pkix-test/pkixtestutil.h index 70c0fee94..44a60fea1 100644 --- a/lib/mozpkix/include/pkix-test/pkixtestutil.h +++ b/lib/mozpkix/include/pkix-test/pkixtestutil.h @@ -279,10 +279,11 @@ TestKeyPair* GenerateDSSKeyPair(); inline void DeleteTestKeyPair(TestKeyPair* keyPair) { delete keyPair; } typedef std::unique_ptr<TestKeyPair> ScopedTestKeyPair; -Result TestVerifyECDSASignedDigest(const SignedDigest& signedDigest, - Input subjectPublicKeyInfo); -Result TestVerifyRSAPKCS1SignedDigest(const SignedDigest& signedDigest, - Input subjectPublicKeyInfo); +Result TestVerifyECDSASignedData(Input data, DigestAlgorithm digestAlgorithm, + Input signature, Input subjectPublicKeyInfo); +Result TestVerifyRSAPKCS1SignedData(Input data, DigestAlgorithm digestAlgorithm, + Input signature, + Input subjectPublicKeyInfo); Result TestDigestBuf(Input item, DigestAlgorithm digestAlg, /*out*/ uint8_t* digestBuf, size_t digestBufLen); diff --git a/lib/mozpkix/include/pkix/pkixder.h b/lib/mozpkix/include/pkix/pkixder.h index 379106ef4..1b0d08e0d 100644 --- a/lib/mozpkix/include/pkix/pkixder.h +++ b/lib/mozpkix/include/pkix/pkixder.h @@ -488,7 +488,7 @@ inline Result OptionalExtensions(Reader& input, uint8_t tag, Result DigestAlgorithmIdentifier(Reader& input, /*out*/ DigestAlgorithm& algorithm); -enum class PublicKeyAlgorithm { RSA_PKCS1, ECDSA, Uninitialized }; +enum class PublicKeyAlgorithm { RSA_PKCS1, ECDSA }; Result SignatureAlgorithmIdentifierValue( Reader& input, @@ -524,6 +524,9 @@ struct SignedDataWithSignature final { // certs [0] EXPLICIT SEQUENCE OF Certificate OPTIONAL } Result SignedData(Reader& input, /*out*/ Reader& tbs, /*out*/ SignedDataWithSignature& signedDataWithSignature); + +// Parses an ECDSASigValue (RFC 5480) into its components r and s. +Result ECDSASigValue(Input ecdsaSignature, /*out*/ Input& r, /*out*/ Input& s); } } } // namespace mozilla::pkix::der diff --git a/lib/mozpkix/include/pkix/pkixnss.h b/lib/mozpkix/include/pkix/pkixnss.h index b181ca541..4c5f0a322 100644 --- a/lib/mozpkix/include/pkix/pkixnss.h +++ b/lib/mozpkix/include/pkix/pkixnss.h @@ -34,15 +34,15 @@ namespace pkix { // Verifies the PKCS#1.5 signature on the given data using the given RSA public // key. -Result VerifyRSAPKCS1SignedDigestNSS(const SignedDigest& sd, - Input subjectPublicKeyInfo, - void* pkcs11PinArg); +Result VerifyRSAPKCS1SignedDataNSS(Input data, DigestAlgorithm digestAlgorithm, + Input signature, Input subjectPublicKeyInfo, + void* pkcs11PinArg); // Verifies the ECDSA signature on the given data using the given ECC public // key. -Result VerifyECDSASignedDigestNSS(const SignedDigest& sd, - Input subjectPublicKeyInfo, - void* pkcs11PinArg); +Result VerifyECDSASignedDataNSS(Input data, DigestAlgorithm digestAlgorithm, + Input signature, Input subjectPublicKeyInfo, + void* pkcs11PinArg); // Computes the digest of the given data using the given digest algorithm. // diff --git a/lib/mozpkix/include/pkix/pkixtypes.h b/lib/mozpkix/include/pkix/pkixtypes.h index 6c391681f..18f52b472 100644 --- a/lib/mozpkix/include/pkix/pkixtypes.h +++ b/lib/mozpkix/include/pkix/pkixtypes.h @@ -52,14 +52,6 @@ enum class NamedCurve { secp256r1 = 3, }; -struct SignedDigest final { - Input digest; - DigestAlgorithm digestAlgorithm; - Input signature; - - void operator=(const SignedDigest&) = delete; -}; - enum class EndEntityOrCA { MustBeEndEntity = 0, MustBeCA = 1 }; enum class KeyUsage : uint8_t { @@ -305,10 +297,12 @@ class TrustDomain { // // CheckRSAPublicKeyModulusSizeInBits will be called before calling this // function, so it is not necessary to repeat those checks here. However, - // VerifyRSAPKCS1SignedDigest *is* responsible for doing the mathematical + // VerifyRSAPKCS1SignedData *is* responsible for doing the mathematical // verification of the public key validity as specified in NIST SP 800-56A. - virtual Result VerifyRSAPKCS1SignedDigest(const SignedDigest& signedDigest, - Input subjectPublicKeyInfo) = 0; + virtual Result VerifyRSAPKCS1SignedData(Input data, + DigestAlgorithm digestAlgorithm, + Input signature, + Input subjectPublicKeyInfo) = 0; // Check that the given named ECC curve is acceptable for ECDSA signatures. // @@ -323,10 +317,12 @@ class TrustDomain { // // CheckECDSACurveIsAcceptable will be called before calling this function, // so it is not necessary to repeat that check here. However, - // VerifyECDSASignedDigest *is* responsible for doing the mathematical + // VerifyECDSASignedData *is* responsible for doing the mathematical // verification of the public key validity as specified in NIST SP 800-56A. - virtual Result VerifyECDSASignedDigest(const SignedDigest& signedDigest, - Input subjectPublicKeyInfo) = 0; + virtual Result VerifyECDSASignedData(Input data, + DigestAlgorithm digestAlgorithm, + Input signature, + Input subjectPublicKeyInfo) = 0; // Check that the validity duration is acceptable. // diff --git a/lib/mozpkix/include/pkix/pkixutil.h b/lib/mozpkix/include/pkix/pkixutil.h index b224aa1f7..987195e7a 100644 --- a/lib/mozpkix/include/pkix/pkixutil.h +++ b/lib/mozpkix/include/pkix/pkixutil.h @@ -192,18 +192,6 @@ inline unsigned int DaysBeforeYear(unsigned int year) { static const size_t MAX_DIGEST_SIZE_IN_BYTES = 512 / 8; // sha-512 -Result DigestSignedData(TrustDomain& trustDomain, - const der::SignedDataWithSignature& signedData, - /*out*/ uint8_t (&digestBuf)[MAX_DIGEST_SIZE_IN_BYTES], - /*out*/ der::PublicKeyAlgorithm& publicKeyAlg, - /*out*/ SignedDigest& signedDigest); - -Result VerifySignedDigest(TrustDomain& trustDomain, - der::PublicKeyAlgorithm publicKeyAlg, - const SignedDigest& signedDigest, - Input signerSubjectPublicKeyInfo); - -// Combines DigestSignedData and VerifySignedDigest Result VerifySignedData(TrustDomain& trustDomain, const der::SignedDataWithSignature& signedData, Input signerSubjectPublicKeyInfo); diff --git a/lib/mozpkix/lib/pkixbuild.cpp b/lib/mozpkix/lib/pkixbuild.cpp index afe7e2a24..aad74b3d9 100644 --- a/lib/mozpkix/lib/pkixbuild.cpp +++ b/lib/mozpkix/lib/pkixbuild.cpp @@ -61,7 +61,6 @@ public: , stapledOCSPResponse(aStapledOCSPResponse) , subCACount(aSubCACount) , deferredSubjectError(aDeferredSubjectError) - , subjectSignaturePublicKeyAlg(der::PublicKeyAlgorithm::Uninitialized) , result(Result::FATAL_ERROR_LIBRARY_FAILURE) , resultWasSet(false) , buildForwardCallBudget(aBuildForwardCallBudget) @@ -84,11 +83,6 @@ private: const unsigned int subCACount; const Result deferredSubjectError; - // Initialized lazily. - uint8_t subjectSignatureDigestBuf[MAX_DIGEST_SIZE_IN_BYTES]; - der::PublicKeyAlgorithm subjectSignaturePublicKeyAlg; - SignedDigest subjectSignature; - Result RecordResult(Result currentResult, /*out*/ bool& keepGoing); Result result; bool resultWasSet; @@ -215,22 +209,8 @@ PathBuildingStep::Check(Input potentialIssuerDER, return RecordResult(rv, keepGoing); } - // Calculate the digest of the subject's signed data if we haven't already - // done so. We do this lazily to avoid doing it at all if we backtrack before - // getting to this point. We cache the result to avoid recalculating it if we - // backtrack after getting to this point. - if (subjectSignature.digest.GetLength() == 0) { - rv = DigestSignedData(trustDomain, subject.GetSignedData(), - subjectSignatureDigestBuf, - subjectSignaturePublicKeyAlg, subjectSignature); - if (rv != Success) { - return rv; - } - } - - rv = VerifySignedDigest(trustDomain, subjectSignaturePublicKeyAlg, - subjectSignature, - potentialIssuer.GetSubjectPublicKeyInfo()); + rv = VerifySignedData(trustDomain, subject.GetSignedData(), + potentialIssuer.GetSubjectPublicKeyInfo()); if (rv != Success) { return RecordResult(rv, keepGoing); } diff --git a/lib/mozpkix/lib/pkixc.cpp b/lib/mozpkix/lib/pkixc.cpp index ec8cc120a..5b30af33f 100644 --- a/lib/mozpkix/lib/pkixc.cpp +++ b/lib/mozpkix/lib/pkixc.cpp @@ -110,10 +110,11 @@ class CodeSigningTrustDomain final : public TrustDomain { return Success; } - virtual Result VerifyRSAPKCS1SignedDigest( - const SignedDigest& signedDigest, Input subjectPublicKeyInfo) override { - return VerifyRSAPKCS1SignedDigestNSS(signedDigest, subjectPublicKeyInfo, - nullptr); + virtual Result VerifyRSAPKCS1SignedData( + Input data, DigestAlgorithm digestAlgorithm, Input signature, + Input subjectPublicKeyInfo) override { + return VerifyRSAPKCS1SignedDataNSS(data, digestAlgorithm, signature, + subjectPublicKeyInfo, nullptr); } virtual Result CheckECDSACurveIsAcceptable(EndEntityOrCA endEntityOrCA, @@ -128,10 +129,11 @@ class CodeSigningTrustDomain final : public TrustDomain { return Result::ERROR_UNSUPPORTED_ELLIPTIC_CURVE; } - virtual Result VerifyECDSASignedDigest(const SignedDigest& signedDigest, - Input subjectPublicKeyInfo) override { - return VerifyECDSASignedDigestNSS(signedDigest, subjectPublicKeyInfo, - nullptr); + virtual Result VerifyECDSASignedData( + Input data, DigestAlgorithm digestAlgorithm, Input signature, + Input subjectPublicKeyInfo) override { + return VerifyECDSASignedDataNSS(data, digestAlgorithm, signature, + subjectPublicKeyInfo, nullptr); } virtual Result CheckValidityIsAcceptable(Time notBefore, Time notAfter, diff --git a/lib/mozpkix/lib/pkixcheck.cpp b/lib/mozpkix/lib/pkixcheck.cpp index 317db01e2..a0079f305 100644 --- a/lib/mozpkix/lib/pkixcheck.cpp +++ b/lib/mozpkix/lib/pkixcheck.cpp @@ -117,11 +117,6 @@ CheckSignatureAlgorithm(TrustDomain& trustDomain, // for any curve that we support, the chances of us encountering a curve // during path building is too low to be worth bothering with. break; - case der::PublicKeyAlgorithm::Uninitialized: - { - assert(false); - return Result::FATAL_ERROR_LIBRARY_FAILURE; - } MOZILLA_PKIX_UNREACHABLE_DEFAULT_ENUM } diff --git a/lib/mozpkix/lib/pkixder.cpp b/lib/mozpkix/lib/pkixder.cpp index 152d11a23..9dccc9639 100644 --- a/lib/mozpkix/lib/pkixder.cpp +++ b/lib/mozpkix/lib/pkixder.cpp @@ -608,4 +608,58 @@ OptionalVersion(Reader& input, /*out*/ Version& version) }); } +// From RFC 5480 Appendix A: +// ECDSA-Sig-Value ::= SEQUENCE { +// r INTEGER, +// s INTEGER +// } +Result +ECDSASigValue(Input ecdsaSignature, /*out*/ Input& r, /*out*/ Input& s) { + Reader rAndS; + Result rv = ExpectTagAndGetValueAtEnd(ecdsaSignature, SEQUENCE, rAndS); + if (rv != Success) { + return rv; + } + + Input rInput; + Input::size_type rSignificantBytes; + rv = PositiveInteger(rAndS, rInput, &rSignificantBytes); + if (rv != Success) { + return rv; + } + Reader rReader(rInput); + // Address potential leading 0 byte due to DER encoding. + if (rSignificantBytes + 1 == rInput.GetLength()) { + rv = rReader.Skip(1); + if (rv != Success) { + return rv; + } + } + rv = rReader.SkipToEnd(r); + if (rv != Success) { + return rv; + } + + Input sInput; + Input::size_type sSignificantBytes; + rv = PositiveInteger(rAndS, sInput, &sSignificantBytes); + if (rv != Success) { + return rv; + } + Reader sReader(sInput); + // Address potential leading 0 byte due to DER encoding. + if (sSignificantBytes + 1 == sInput.GetLength()) { + rv = sReader.Skip(1); + if (rv != Success) { + return rv; + } + } + rv = sReader.SkipToEnd(s); + if (rv != Success) { + return rv; + } + + return End(rAndS); +} + } } } // namespace mozilla::pkix::der diff --git a/lib/mozpkix/lib/pkixnss.cpp b/lib/mozpkix/lib/pkixnss.cpp index 9b293d5fd..06c1bdcbd 100644 --- a/lib/mozpkix/lib/pkixnss.cpp +++ b/lib/mozpkix/lib/pkixnss.cpp @@ -40,63 +40,181 @@ namespace mozilla { namespace pkix { namespace { Result -VerifySignedDigest(const SignedDigest& sd, - Input subjectPublicKeyInfo, - SECOidTag pubKeyAlg, - void* pkcs11PinArg) +SubjectPublicKeyInfoToSECKEYPublicKey(Input subjectPublicKeyInfo, + ScopedSECKEYPublicKey& publicKey) { - SECOidTag digestAlg; - switch (sd.digestAlgorithm) { - case DigestAlgorithm::sha512: digestAlg = SEC_OID_SHA512; break; - case DigestAlgorithm::sha384: digestAlg = SEC_OID_SHA384; break; - case DigestAlgorithm::sha256: digestAlg = SEC_OID_SHA256; break; - case DigestAlgorithm::sha1: digestAlg = SEC_OID_SHA1; break; - MOZILLA_PKIX_UNREACHABLE_DEFAULT_ENUM - } - - SECItem subjectPublicKeyInfoSECItem = - UnsafeMapInputToSECItem(subjectPublicKeyInfo); - ScopedCERTSubjectPublicKeyInfo - spki(SECKEY_DecodeDERSubjectPublicKeyInfo(&subjectPublicKeyInfoSECItem)); + SECItem subjectPublicKeyInfoSECItem( + UnsafeMapInputToSECItem(subjectPublicKeyInfo)); + ScopedCERTSubjectPublicKeyInfo spki( + SECKEY_DecodeDERSubjectPublicKeyInfo(&subjectPublicKeyInfoSECItem)); if (!spki) { return MapPRErrorCodeToResult(PR_GetError()); } - ScopedSECKEYPublicKey - pubKey(SECKEY_ExtractPublicKey(spki.get())); - if (!pubKey) { + publicKey.reset(SECKEY_ExtractPublicKey(spki.get())); + if (!publicKey) { return MapPRErrorCodeToResult(PR_GetError()); } + return Success; +} - SECItem digestSECItem(UnsafeMapInputToSECItem(sd.digest)); - SECItem signatureSECItem(UnsafeMapInputToSECItem(sd.signature)); - SECStatus srv = VFY_VerifyDigestDirect(&digestSECItem, pubKey.get(), - &signatureSECItem, pubKeyAlg, - digestAlg, pkcs11PinArg); +Result +VerifySignedData(SECKEYPublicKey* publicKey, CK_MECHANISM_TYPE mechanism, + SECItem* params, SECItem* signature, SECItem* data, + SECOidTag (&policyTags)[3], void* pkcs11PinArg) +{ + // Hash and signature algorithms can be disabled by policy in NSS. However, + // the policy engine in NSS is not currently sophisticated enough to, for + // example, infer that disabling SEC_OID_SHA1 (i.e. the hash algorithm SHA1) + // should also disable SEC_OID_PKCS1_SHA1_WITH_RSA_ENCRYPTION. Thus, this + // implementation checks the signature algorithm, the hash algorithm, and the + // signature algorithm with the hash algorithm together. + for (size_t i = 0; i < sizeof(policyTags) / sizeof(policyTags[0]); i++) { + SECOidTag policyTag = policyTags[i]; + uint32_t policyFlags; + if (NSS_GetAlgorithmPolicy(policyTag, &policyFlags) != SECSuccess) { + return MapPRErrorCodeToResult(PR_GetError()); + } + if (!(policyFlags & NSS_USE_ALG_IN_ANY_SIGNATURE)) { + return MapPRErrorCodeToResult(SEC_ERROR_SIGNATURE_ALGORITHM_DISABLED); + } + } + SECStatus srv = PK11_VerifyWithMechanism(publicKey, mechanism, params, + signature, data, pkcs11PinArg); if (srv != SECSuccess) { return MapPRErrorCodeToResult(PR_GetError()); } - return Success; } - } // namespace Result -VerifyRSAPKCS1SignedDigestNSS(const SignedDigest& sd, - Input subjectPublicKeyInfo, - void* pkcs11PinArg) +VerifyRSAPKCS1SignedDataNSS(Input data, DigestAlgorithm digestAlgorithm, + Input signature, Input subjectPublicKeyInfo, void* pkcs11PinArg) { - return VerifySignedDigest(sd, subjectPublicKeyInfo, - SEC_OID_PKCS1_RSA_ENCRYPTION, pkcs11PinArg); + ScopedSECKEYPublicKey publicKey; + Result rv = SubjectPublicKeyInfoToSECKEYPublicKey(subjectPublicKeyInfo, + publicKey); + if (rv != Success) { + return rv; + } + SECItem signatureItem(UnsafeMapInputToSECItem(signature)); + SECItem dataItem(UnsafeMapInputToSECItem(data)); + CK_MECHANISM_TYPE mechanism; + SECOidTag signaturePolicyTag = SEC_OID_PKCS1_RSA_ENCRYPTION; + SECOidTag hashPolicyTag; + SECOidTag combinedPolicyTag; + switch (digestAlgorithm) { + case DigestAlgorithm::sha512: + mechanism = CKM_SHA512_RSA_PKCS; + hashPolicyTag = SEC_OID_SHA512; + combinedPolicyTag = SEC_OID_PKCS1_SHA512_WITH_RSA_ENCRYPTION; + break; + case DigestAlgorithm::sha384: + mechanism = CKM_SHA384_RSA_PKCS; + hashPolicyTag = SEC_OID_SHA384; + combinedPolicyTag = SEC_OID_PKCS1_SHA384_WITH_RSA_ENCRYPTION; + break; + case DigestAlgorithm::sha256: + mechanism = CKM_SHA256_RSA_PKCS; + hashPolicyTag = SEC_OID_SHA256; + combinedPolicyTag = SEC_OID_PKCS1_SHA256_WITH_RSA_ENCRYPTION; + break; + case DigestAlgorithm::sha1: + mechanism = CKM_SHA1_RSA_PKCS; + hashPolicyTag = SEC_OID_SHA1; + combinedPolicyTag = SEC_OID_PKCS1_SHA1_WITH_RSA_ENCRYPTION; + break; + MOZILLA_PKIX_UNREACHABLE_DEFAULT_ENUM + } + SECOidTag policyTags[3] = + { signaturePolicyTag, hashPolicyTag, combinedPolicyTag }; + return VerifySignedData(publicKey.get(), mechanism, nullptr, &signatureItem, + &dataItem, policyTags, pkcs11PinArg); } Result -VerifyECDSASignedDigestNSS(const SignedDigest& sd, - Input subjectPublicKeyInfo, - void* pkcs11PinArg) +EncodedECDSASignatureToRawPoint(Input signature, + const ScopedSECKEYPublicKey& publicKey, ScopedSECItem& result) { + Input r; + Input s; + Result rv = der::ECDSASigValue(signature, r, s); + if (rv != Success) { + return Result::ERROR_BAD_SIGNATURE; + } + size_t signatureLength = SECKEY_SignatureLen(publicKey.get()); + if (signatureLength == 0) { + return MapPRErrorCodeToResult(PR_GetError()); + } + if (signatureLength % 2 != 0) { + return Result::FATAL_ERROR_LIBRARY_FAILURE; + } + size_t coordinateLength = signatureLength / 2; + if (r.GetLength() > coordinateLength || s.GetLength() > coordinateLength) { + return Result::ERROR_BAD_SIGNATURE; + } + ScopedSECItem signatureItem( + SECITEM_AllocItem(nullptr, nullptr, signatureLength)); + if (!signatureItem) { + return Result::FATAL_ERROR_NO_MEMORY; + } + memset(signatureItem->data, 0, signatureLength); + memcpy(signatureItem->data + (coordinateLength - r.GetLength()), + r.UnsafeGetData(), r.GetLength()); + memcpy(signatureItem->data + (2 * coordinateLength - s.GetLength()), + s.UnsafeGetData(), s.GetLength()); + result.swap(signatureItem); + return Success; +} + +Result +VerifyECDSASignedDataNSS(Input data, DigestAlgorithm digestAlgorithm, + Input signature, Input subjectPublicKeyInfo, void* pkcs11PinArg) { - return VerifySignedDigest(sd, subjectPublicKeyInfo, - SEC_OID_ANSIX962_EC_PUBLIC_KEY, pkcs11PinArg); + ScopedSECKEYPublicKey publicKey; + Result rv = SubjectPublicKeyInfoToSECKEYPublicKey(subjectPublicKeyInfo, + publicKey); + if (rv != Success) { + return rv; + } + + ScopedSECItem signatureItem; + rv = EncodedECDSASignatureToRawPoint(signature, publicKey, signatureItem); + if (rv != Success) { + return rv; + } + + SECItem dataItem(UnsafeMapInputToSECItem(data)); + CK_MECHANISM_TYPE mechanism; + SECOidTag signaturePolicyTag = SEC_OID_ANSIX962_EC_PUBLIC_KEY; + SECOidTag hashPolicyTag; + SECOidTag combinedPolicyTag; + switch (digestAlgorithm) { + case DigestAlgorithm::sha512: + mechanism = CKM_ECDSA_SHA512; + hashPolicyTag = SEC_OID_SHA512; + combinedPolicyTag = SEC_OID_ANSIX962_ECDSA_SHA512_SIGNATURE; + break; + case DigestAlgorithm::sha384: + mechanism = CKM_ECDSA_SHA384; + hashPolicyTag = SEC_OID_SHA384; + combinedPolicyTag = SEC_OID_ANSIX962_ECDSA_SHA384_SIGNATURE; + break; + case DigestAlgorithm::sha256: + mechanism = CKM_ECDSA_SHA256; + hashPolicyTag = SEC_OID_SHA256; + combinedPolicyTag = SEC_OID_ANSIX962_ECDSA_SHA256_SIGNATURE; + break; + case DigestAlgorithm::sha1: + mechanism = CKM_ECDSA_SHA1; + hashPolicyTag = SEC_OID_SHA1; + combinedPolicyTag = SEC_OID_ANSIX962_ECDSA_SHA1_SIGNATURE; + break; + MOZILLA_PKIX_UNREACHABLE_DEFAULT_ENUM + } + SECOidTag policyTags[3] = + { signaturePolicyTag, hashPolicyTag, combinedPolicyTag }; + return VerifySignedData(publicKey.get(), mechanism, nullptr, + signatureItem.get(), &dataItem, policyTags, pkcs11PinArg); } Result diff --git a/lib/mozpkix/lib/pkixverify.cpp b/lib/mozpkix/lib/pkixverify.cpp index bec570de6..5658386d2 100644 --- a/lib/mozpkix/lib/pkixverify.cpp +++ b/lib/mozpkix/lib/pkixverify.cpp @@ -27,15 +27,15 @@ namespace mozilla { namespace pkix { Result -DigestSignedData(TrustDomain& trustDomain, +VerifySignedData(TrustDomain& trustDomain, const der::SignedDataWithSignature& signedData, - /*out*/ uint8_t(&digestBuf)[MAX_DIGEST_SIZE_IN_BYTES], - /*out*/ der::PublicKeyAlgorithm& publicKeyAlg, - /*out*/ SignedDigest& signedDigest) + Input signerSubjectPublicKeyInfo) { + der::PublicKeyAlgorithm publicKeyAlg; + DigestAlgorithm digestAlgorithm; Reader signatureAlg(signedData.algorithm); Result rv = der::SignatureAlgorithmIdentifierValue( - signatureAlg, publicKeyAlg, signedDigest.digestAlgorithm); + signatureAlg, publicKeyAlg, digestAlgorithm); if (rv != Success) { return rv; } @@ -43,57 +43,15 @@ DigestSignedData(TrustDomain& trustDomain, return Result::ERROR_BAD_DER; } - size_t digestLen = DigestAlgorithmToSizeInBytes(signedDigest.digestAlgorithm); - assert(digestLen <= sizeof(digestBuf)); - - rv = trustDomain.DigestBuf(signedData.data, signedDigest.digestAlgorithm, - digestBuf, digestLen); - if (rv != Success) { - return rv; - } - rv = signedDigest.digest.Init(digestBuf, digestLen); - if (rv != Success) { - return rv; - } - - return signedDigest.signature.Init(signedData.signature); -} - -Result -VerifySignedDigest(TrustDomain& trustDomain, - der::PublicKeyAlgorithm publicKeyAlg, - const SignedDigest& signedDigest, - Input signerSubjectPublicKeyInfo) -{ switch (publicKeyAlg) { case der::PublicKeyAlgorithm::ECDSA: - return trustDomain.VerifyECDSASignedDigest(signedDigest, - signerSubjectPublicKeyInfo); + return trustDomain.VerifyECDSASignedData(signedData.data, + digestAlgorithm, signedData.signature, signerSubjectPublicKeyInfo); case der::PublicKeyAlgorithm::RSA_PKCS1: - return trustDomain.VerifyRSAPKCS1SignedDigest(signedDigest, - signerSubjectPublicKeyInfo); - case der::PublicKeyAlgorithm::Uninitialized: - assert(false); - return Result::FATAL_ERROR_LIBRARY_FAILURE; + return trustDomain.VerifyRSAPKCS1SignedData(signedData.data, + digestAlgorithm, signedData.signature, signerSubjectPublicKeyInfo); MOZILLA_PKIX_UNREACHABLE_DEFAULT_ENUM } } -Result -VerifySignedData(TrustDomain& trustDomain, - const der::SignedDataWithSignature& signedData, - Input signerSubjectPublicKeyInfo) -{ - uint8_t digestBuf[MAX_DIGEST_SIZE_IN_BYTES]; - der::PublicKeyAlgorithm publicKeyAlg; - SignedDigest signedDigest; - Result rv = DigestSignedData(trustDomain, signedData, digestBuf, - publicKeyAlg, signedDigest); - if (rv != Success) { - return rv; - } - return VerifySignedDigest(trustDomain, publicKeyAlg, signedDigest, - signerSubjectPublicKeyInfo); -} - } } // namespace mozilla::pkix diff --git a/lib/mozpkix/test-lib/pkixtestnss.cpp b/lib/mozpkix/test-lib/pkixtestnss.cpp index 1e50f46f4..45edf3ea7 100644 --- a/lib/mozpkix/test-lib/pkixtestnss.cpp +++ b/lib/mozpkix/test-lib/pkixtestnss.cpp @@ -335,21 +335,21 @@ GenerateDSSKeyPair() } Result -TestVerifyECDSASignedDigest(const SignedDigest& signedDigest, - Input subjectPublicKeyInfo) +TestVerifyECDSASignedData(Input data, DigestAlgorithm digestAlgorithm, + Input signature, Input subjectPublicKeyInfo) { InitNSSIfNeeded(); - return VerifyECDSASignedDigestNSS(signedDigest, subjectPublicKeyInfo, - nullptr); + return VerifyECDSASignedDataNSS(data, digestAlgorithm, signature, + subjectPublicKeyInfo, nullptr); } Result -TestVerifyRSAPKCS1SignedDigest(const SignedDigest& signedDigest, - Input subjectPublicKeyInfo) +TestVerifyRSAPKCS1SignedData(Input data, DigestAlgorithm digestAlgorithm, + Input signature, Input subjectPublicKeyInfo) { InitNSSIfNeeded(); - return VerifyRSAPKCS1SignedDigestNSS(signedDigest, subjectPublicKeyInfo, - nullptr); + return VerifyRSAPKCS1SignedDataNSS(data, digestAlgorithm, signature, + subjectPublicKeyInfo, nullptr); } Result |