author | David Keeler <dkeeler@mozilla.com> |
Mon, 03 Apr 2017 17:17:38 -0700 | |
changeset 560709 | 65807453af3e6ea0a6936067324561a26ce4e118 |
parent 560546 | abf145ebd05fe105efbc78b761858c34f7690154 |
child 623796 | ac63d5a9b6730bd28961ea5dc82168e690d77b77 |
push id | 53531 |
push user | bmo:dkeeler@mozilla.com |
push date | Tue, 11 Apr 2017 21:51:23 +0000 |
reviewers | jcj, Cykesiopka |
bugs | 1349762 |
milestone | 55.0a1 |
--- a/security/apps/AppTrustDomain.cpp +++ b/security/apps/AppTrustDomain.cpp @@ -254,18 +254,20 @@ AppTrustDomain::CheckRevocation(EndEntit /*optional*/ const Input*) { // We don't currently do revocation checking. If we need to distrust an Apps // certificate, we will use the active distrust mechanism. return Success; } Result -AppTrustDomain::IsChainValid(const DERArray& certChain, Time time) +AppTrustDomain::IsChainValid(const DERArray& certChain, Time time, + const CertPolicyId& requiredPolicy) { + MOZ_ASSERT(requiredPolicy.IsAnyPolicy()); SECStatus srv = ConstructCERTCertListFromReversedDERArray(certChain, mCertChain); if (srv != SECSuccess) { return MapPRErrorCodeToResult(PR_GetError()); } return Success; }
--- a/security/apps/AppTrustDomain.h +++ b/security/apps/AppTrustDomain.h @@ -35,17 +35,19 @@ public: mozilla::pkix::Time time) override; virtual Result CheckRevocation(mozilla::pkix::EndEntityOrCA endEntityOrCA, const mozilla::pkix::CertID& certID, mozilla::pkix::Time time, mozilla::pkix::Duration validityDuration, /*optional*/ const mozilla::pkix::Input* stapledOCSPresponse, /*optional*/ const mozilla::pkix::Input* aiaExtension) override; virtual Result IsChainValid(const mozilla::pkix::DERArray& certChain, - mozilla::pkix::Time time) override; + mozilla::pkix::Time time, + const mozilla::pkix::CertPolicyId& requiredPolicy) + override; virtual Result CheckSignatureDigestAlgorithm( mozilla::pkix::DigestAlgorithm digestAlg, mozilla::pkix::EndEntityOrCA endEntityOrCA, mozilla::pkix::Time notBefore) override; virtual Result CheckRSAPublicKeyModulusSizeInBits( mozilla::pkix::EndEntityOrCA endEntityOrCA, unsigned int modulusSizeInBits) override; virtual Result VerifyRSAPKCS1SignedDigest(
--- a/security/certverifier/CTLogVerifier.cpp +++ b/security/certverifier/CTLogVerifier.cpp @@ -45,17 +45,17 @@ public: } Result CheckRevocation(EndEntityOrCA, const CertID&, Time, Duration, const Input*, const Input*) override { return Result::FATAL_ERROR_LIBRARY_FAILURE; } - Result IsChainValid(const DERArray&, Time) override + Result IsChainValid(const DERArray&, Time, const CertPolicyId&) override { return Result::FATAL_ERROR_LIBRARY_FAILURE; } Result DigestBuf(Input, DigestAlgorithm, uint8_t*, size_t) override { return Result::FATAL_ERROR_LIBRARY_FAILURE; }
--- a/security/certverifier/ExtendedValidation.cpp +++ b/security/certverifier/ExtendedValidation.cpp @@ -870,27 +870,16 @@ static const struct nsMyTrustedEVInfo my 0x57, 0x12, 0xE0, 0x40, 0x0D, 0x2B, 0xED, 0x3F, 0xBC, 0x4D, 0x4F, 0xBD, 0xAA, 0x86, 0xE0, 0x6A, 0xDC, 0xD2, 0xA9, 0xAD, 0x7A }, "MIGIMQswCQYDVQQGEwJVUzETMBEGA1UECBMKTmV3IEplcnNleTEUMBIGA1UEBxML" "SmVyc2V5IENpdHkxHjAcBgNVBAoTFVRoZSBVU0VSVFJVU1QgTmV0d29yazEuMCwG" "A1UEAxMlVVNFUlRydXN0IEVDQyBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eQ==", "XIuZxVqUxdJxVt7NiYDMJg==", }, { - // CN=GlobalSign,O=GlobalSign,OU=GlobalSign ECC Root CA - R4 - "1.3.6.1.4.1.4146.1.1", - "GlobalSign EV OID", - { 0xBE, 0xC9, 0x49, 0x11, 0xC2, 0x95, 0x56, 0x76, 0xDB, 0x6C, 0x0A, - 0x55, 0x09, 0x86, 0xD7, 0x6E, 0x3B, 0xA0, 0x05, 0x66, 0x7C, 0x44, - 0x2C, 0x97, 0x62, 0xB4, 0xFB, 0xB7, 0x73, 0xDE, 0x22, 0x8C }, - "MFAxJDAiBgNVBAsTG0dsb2JhbFNpZ24gRUNDIFJvb3QgQ0EgLSBSNDETMBEGA1UE" - "ChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbg==", - "KjikHJYKBN5CsiilC+g0mAI=", - }, - { // CN=GlobalSign,O=GlobalSign,OU=GlobalSign ECC Root CA - R5 "1.3.6.1.4.1.4146.1.1", "GlobalSign EV OID", { 0x17, 0x9F, 0xBC, 0x14, 0x8A, 0x3D, 0xD0, 0x0F, 0xD2, 0x4E, 0xA1, 0x34, 0x58, 0xCC, 0x43, 0xBF, 0xA7, 0xF5, 0x9C, 0x81, 0x82, 0xD7, 0x83, 0xA5, 0x13, 0xF6, 0xEB, 0xEC, 0x10, 0x0C, 0x89, 0x24 }, "MFAxJDAiBgNVBAsTG0dsb2JhbFNpZ24gRUNDIFJvb3QgQ0EgLSBSNTETMBEGA1UE" "ChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbg==",
--- a/security/certverifier/NSSCertDBTrustDomain.cpp +++ b/security/certverifier/NSSCertDBTrustDomain.cpp @@ -787,18 +787,118 @@ CheckForStartComOrWoSign(const UniqueCER } if (CertIsStartComOrWoSign(node->cert)) { return Result::ERROR_REVOKED_CERTIFICATE; } } return Success; } +// python DottedOIDToCode.py sGlobalSignEVPolicyBytes 1.3.6.1.4.1.4146.1.1 +static const uint8_t sGlobalSignEVPolicyBytes[] = { + 0x2b, 0x06, 0x01, 0x04, 0x01, 0xa0, 0x32, 0x01, 0x01 +}; + +static const CertPolicyId sGlobalSignEVPolicy = { + sizeof(sGlobalSignEVPolicyBytes), + // It's unfortunate, but there isn't a nice way to do this. + // Just make sure these bytes match sGlobalSignEVPolicyBytes. + { 0x2b, 0x06, 0x01, 0x04, 0x01, 0xa0, 0x32, 0x01, 0x01 } +}; + +static const unsigned char sGlobalSignRootCAR2SubjectBytes[] = { + 0x30, 0x4c, 0x31, 0x20, 0x30, 0x1e, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x17, + 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x53, 0x69, 0x67, 0x6e, 0x20, 0x52, 0x6f, + 0x6f, 0x74, 0x20, 0x43, 0x41, 0x20, 0x2d, 0x20, 0x52, 0x32, 0x31, 0x13, 0x30, + 0x11, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0a, 0x47, 0x6c, 0x6f, 0x62, 0x61, + 0x6c, 0x53, 0x69, 0x67, 0x6e, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, + 0x03, 0x13, 0x0a, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x53, 0x69, 0x67, 0x6e, +}; + +static const unsigned char sGlobalSignRootCAR2SPKIBytes[] = { + 0x30, 0x82, 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, + 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00, 0x30, 0x82, + 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01, 0x00, 0xa6, 0xcf, 0x24, 0x0e, 0xbe, 0x2e, + 0x6f, 0x28, 0x99, 0x45, 0x42, 0xc4, 0xab, 0x3e, 0x21, 0x54, 0x9b, 0x0b, 0xd3, + 0x7f, 0x84, 0x70, 0xfa, 0x12, 0xb3, 0xcb, 0xbf, 0x87, 0x5f, 0xc6, 0x7f, 0x86, + 0xd3, 0xb2, 0x30, 0x5c, 0xd6, 0xfd, 0xad, 0xf1, 0x7b, 0xdc, 0xe5, 0xf8, 0x60, + 0x96, 0x09, 0x92, 0x10, 0xf5, 0xd0, 0x53, 0xde, 0xfb, 0x7b, 0x7e, 0x73, 0x88, + 0xac, 0x52, 0x88, 0x7b, 0x4a, 0xa6, 0xca, 0x49, 0xa6, 0x5e, 0xa8, 0xa7, 0x8c, + 0x5a, 0x11, 0xbc, 0x7a, 0x82, 0xeb, 0xbe, 0x8c, 0xe9, 0xb3, 0xac, 0x96, 0x25, + 0x07, 0x97, 0x4a, 0x99, 0x2a, 0x07, 0x2f, 0xb4, 0x1e, 0x77, 0xbf, 0x8a, 0x0f, + 0xb5, 0x02, 0x7c, 0x1b, 0x96, 0xb8, 0xc5, 0xb9, 0x3a, 0x2c, 0xbc, 0xd6, 0x12, + 0xb9, 0xeb, 0x59, 0x7d, 0xe2, 0xd0, 0x06, 0x86, 0x5f, 0x5e, 0x49, 0x6a, 0xb5, + 0x39, 0x5e, 0x88, 0x34, 0xec, 0xbc, 0x78, 0x0c, 0x08, 0x98, 0x84, 0x6c, 0xa8, + 0xcd, 0x4b, 0xb4, 0xa0, 0x7d, 0x0c, 0x79, 0x4d, 0xf0, 0xb8, 0x2d, 0xcb, 0x21, + 0xca, 0xd5, 0x6c, 0x5b, 0x7d, 0xe1, 0xa0, 0x29, 0x84, 0xa1, 0xf9, 0xd3, 0x94, + 0x49, 0xcb, 0x24, 0x62, 0x91, 0x20, 0xbc, 0xdd, 0x0b, 0xd5, 0xd9, 0xcc, 0xf9, + 0xea, 0x27, 0x0a, 0x2b, 0x73, 0x91, 0xc6, 0x9d, 0x1b, 0xac, 0xc8, 0xcb, 0xe8, + 0xe0, 0xa0, 0xf4, 0x2f, 0x90, 0x8b, 0x4d, 0xfb, 0xb0, 0x36, 0x1b, 0xf6, 0x19, + 0x7a, 0x85, 0xe0, 0x6d, 0xf2, 0x61, 0x13, 0x88, 0x5c, 0x9f, 0xe0, 0x93, 0x0a, + 0x51, 0x97, 0x8a, 0x5a, 0xce, 0xaf, 0xab, 0xd5, 0xf7, 0xaa, 0x09, 0xaa, 0x60, + 0xbd, 0xdc, 0xd9, 0x5f, 0xdf, 0x72, 0xa9, 0x60, 0x13, 0x5e, 0x00, 0x01, 0xc9, + 0x4a, 0xfa, 0x3f, 0xa4, 0xea, 0x07, 0x03, 0x21, 0x02, 0x8e, 0x82, 0xca, 0x03, + 0xc2, 0x9b, 0x8f, 0x02, 0x03, 0x01, 0x00, 0x01, +}; + +static const unsigned char sGlobalSignExtendedValidationCASHA256G2SubjectBytes[] = { + 0x30, 0x62, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, + 0x42, 0x45, 0x31, 0x19, 0x30, 0x17, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x10, + 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x53, 0x69, 0x67, 0x6e, 0x20, 0x6e, 0x76, + 0x2d, 0x73, 0x61, 0x31, 0x38, 0x30, 0x36, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, + 0x2f, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x53, 0x69, 0x67, 0x6e, 0x20, 0x45, + 0x78, 0x74, 0x65, 0x6e, 0x64, 0x65, 0x64, 0x20, 0x56, 0x61, 0x6c, 0x69, 0x64, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x43, 0x41, 0x20, 0x2d, 0x20, 0x53, 0x48, + 0x41, 0x32, 0x35, 0x36, 0x20, 0x2d, 0x20, 0x47, 0x32, +}; + +static const unsigned char sGlobalSignExtendedValidationCASHA256G2SPKIBytes[] = { + 0x30, 0x82, 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, + 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00, 0x30, 0x82, + 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01, 0x00, 0xa3, 0xea, 0xa1, 0xd2, 0xc3, 0x49, + 0xe5, 0xf7, 0x1c, 0x5d, 0xaf, 0xc3, 0x92, 0x42, 0xaf, 0x8a, 0x3c, 0xdc, 0xef, + 0x4c, 0xe6, 0x2f, 0x5f, 0x0c, 0x2b, 0x9f, 0x8a, 0x50, 0x30, 0x66, 0xef, 0x4e, + 0xc8, 0x4f, 0x21, 0x4a, 0xf6, 0xe7, 0xf2, 0x4e, 0x1b, 0x8c, 0x53, 0x57, 0xb0, + 0x9e, 0xc8, 0x5b, 0xf7, 0xb8, 0x46, 0x55, 0xb3, 0x1a, 0xed, 0xc2, 0x6a, 0xfe, + 0xf4, 0x1b, 0xec, 0x48, 0x46, 0x0e, 0x8f, 0xe0, 0xfb, 0xe0, 0x91, 0x19, 0xdf, + 0x99, 0x18, 0x6f, 0x2e, 0x51, 0xaf, 0xda, 0xf6, 0x9a, 0xca, 0x64, 0x6f, 0x99, + 0x54, 0x10, 0x74, 0xea, 0x3c, 0xc8, 0xaa, 0x80, 0x4d, 0x43, 0x37, 0xfb, 0xc8, + 0xa4, 0x7f, 0x05, 0x9d, 0x37, 0x92, 0xbd, 0x98, 0x00, 0x35, 0x5a, 0xaf, 0xbb, + 0x5b, 0x74, 0x15, 0x0e, 0xbc, 0xbc, 0xc6, 0xe9, 0xb7, 0x86, 0xe7, 0xee, 0xae, + 0x4d, 0x4b, 0x04, 0x4c, 0x2b, 0xa0, 0xb4, 0x65, 0x48, 0xb8, 0xc3, 0x3a, 0xcd, + 0x75, 0xbb, 0x37, 0xc9, 0x4a, 0xc0, 0x01, 0x11, 0xd9, 0xbf, 0x3f, 0x15, 0x86, + 0x60, 0x19, 0x6b, 0x34, 0x20, 0x46, 0xf5, 0x86, 0x66, 0x0f, 0x24, 0xf4, 0xcc, + 0x62, 0x9f, 0x9f, 0x9e, 0x1d, 0xfd, 0x10, 0xa4, 0x99, 0x5e, 0xf0, 0x41, 0xeb, + 0xb0, 0x94, 0xff, 0x2c, 0xb3, 0x36, 0xd6, 0xeb, 0x1d, 0xa7, 0x17, 0x5f, 0xdf, + 0xce, 0x6a, 0x77, 0xc7, 0x9a, 0xc4, 0x32, 0x63, 0xa7, 0x06, 0xad, 0xf3, 0x12, + 0x1b, 0x9d, 0x30, 0x72, 0x59, 0x0b, 0xeb, 0x72, 0xeb, 0x2a, 0xd2, 0x77, 0x7b, + 0x91, 0x77, 0xdb, 0x00, 0xfc, 0xd8, 0x6f, 0xf5, 0x2f, 0xd8, 0x7a, 0xc5, 0x0c, + 0x3a, 0xa0, 0x7b, 0x5e, 0x90, 0xf3, 0x9d, 0x84, 0x59, 0xc8, 0x01, 0xd9, 0x91, + 0x37, 0x56, 0xe5, 0x3a, 0x53, 0x93, 0xad, 0x60, 0x49, 0x27, 0x25, 0xd9, 0xe1, + 0xda, 0x82, 0xd7, 0x02, 0x03, 0x01, 0x00, 0x01, +}; + +template<size_t T, size_t R> +static bool +CertMatchesStaticData(const CERTCertificate* cert, + const unsigned char (&subject)[T], + const unsigned char (&spki)[R]) { + MOZ_ASSERT(cert); + if (!cert) { + return false; + } + return cert->derSubject.len == T && + mozilla::PodEqual(cert->derSubject.data, subject, T) && + cert->derPublicKey.len == R && + mozilla::PodEqual(cert->derPublicKey.data, spki, R); +} + Result -NSSCertDBTrustDomain::IsChainValid(const DERArray& certArray, Time time) +NSSCertDBTrustDomain::IsChainValid(const DERArray& certArray, Time time, + const CertPolicyId& requiredPolicy) { MOZ_LOG(gCertVerifierLog, LogLevel::Debug, ("NSSCertDBTrustDomain: IsChainValid")); UniqueCERTCertList certList; SECStatus srv = ConstructCERTCertListFromReversedDERArray(certArray, certList); if (srv != SECSuccess) { @@ -876,16 +976,40 @@ NSSCertDBTrustDomain::IsChainValid(const if (NS_FAILED(nsrv)) { return Result::FATAL_ERROR_LIBRARY_FAILURE; } if (!chainHasValidPins) { return Result::ERROR_KEY_PINNING_FAILURE; } } + // See bug 1349762. If the root is "GlobalSign Root CA - R2", don't consider + // the end-entity valid for EV unless the + // "GlobalSign Extended Validation CA - SHA256 - G2" intermediate is in the + // chain as well. It should be possible to remove this workaround after + // January 2019 as per bug 1349727 comment 17. + if (requiredPolicy == sGlobalSignEVPolicy && + CertMatchesStaticData(root, sGlobalSignRootCAR2SubjectBytes, + sGlobalSignRootCAR2SPKIBytes)) { + bool foundRequiredIntermediate = false; + for (CERTCertListNode* node = CERT_LIST_HEAD(certList); + !CERT_LIST_END(node, certList); node = CERT_LIST_NEXT(node)) { + if (CertMatchesStaticData( + node->cert, + sGlobalSignExtendedValidationCASHA256G2SubjectBytes, + sGlobalSignExtendedValidationCASHA256G2SPKIBytes)) { + foundRequiredIntermediate = true; + break; + } + } + if (!foundRequiredIntermediate) { + return Result::ERROR_POLICY_VALIDATION_FAILED; + } + } + mBuiltChain = Move(certList); return Success; } Result NSSCertDBTrustDomain::CheckSignatureDigestAlgorithm(DigestAlgorithm aAlg, EndEntityOrCA endEntityOrCA,
--- a/security/certverifier/NSSCertDBTrustDomain.h +++ b/security/certverifier/NSSCertDBTrustDomain.h @@ -138,17 +138,19 @@ public: const mozilla::pkix::CertID& certID, mozilla::pkix::Time time, mozilla::pkix::Duration validityDuration, /*optional*/ const mozilla::pkix::Input* stapledOCSPResponse, /*optional*/ const mozilla::pkix::Input* aiaExtension) override; virtual Result IsChainValid(const mozilla::pkix::DERArray& certChain, - mozilla::pkix::Time time) override; + mozilla::pkix::Time time, + const mozilla::pkix::CertPolicyId& requiredPolicy) + override; virtual void NoteAuxiliaryExtension( mozilla::pkix::AuxiliaryExtension extension, mozilla::pkix::Input extensionData) override; // Resets the OCSP stapling status and SCT lists accumulated during // the chain building. void ResetAccumulatedState();
--- a/security/certverifier/OCSPVerificationTrustDomain.cpp +++ b/security/certverifier/OCSPVerificationTrustDomain.cpp @@ -31,17 +31,18 @@ OCSPVerificationTrustDomain::GetCertTrus Result OCSPVerificationTrustDomain::FindIssuer(Input, IssuerChecker&, Time) { // We do not expect this to be called for OCSP signers return Result::FATAL_ERROR_LIBRARY_FAILURE; } Result -OCSPVerificationTrustDomain::IsChainValid(const DERArray&, Time) +OCSPVerificationTrustDomain::IsChainValid(const DERArray&, Time, + const CertPolicyId&) { // We do not expect this to be called for OCSP signers return Result::FATAL_ERROR_LIBRARY_FAILURE; } Result OCSPVerificationTrustDomain::CheckRevocation(EndEntityOrCA, const CertID&, Time, Duration, const Input*,
--- a/security/certverifier/OCSPVerificationTrustDomain.h +++ b/security/certverifier/OCSPVerificationTrustDomain.h @@ -68,17 +68,19 @@ public: const mozilla::pkix::CertID& certID, mozilla::pkix::Time time, mozilla::pkix::Duration validityDuration, /*optional*/ const mozilla::pkix::Input* stapledOCSPResponse, /*optional*/ const mozilla::pkix::Input* aiaExtension) override; virtual Result IsChainValid(const mozilla::pkix::DERArray& certChain, - mozilla::pkix::Time time) override; + mozilla::pkix::Time time, + const mozilla::pkix::CertPolicyId& requiredPolicy) + override; virtual void NoteAuxiliaryExtension( mozilla::pkix::AuxiliaryExtension extension, mozilla::pkix::Input extensionData) override; private: NSSCertDBTrustDomain& mCertDBTrustDomain; };
--- a/security/certverifier/tests/gtest/CTTestUtils.cpp +++ b/security/certverifier/tests/gtest/CTTestUtils.cpp @@ -592,17 +592,17 @@ public: Result CheckRevocation(EndEntityOrCA, const CertID&, Time, Duration, const Input*, const Input*) override { ADD_FAILURE(); return Result::FATAL_ERROR_LIBRARY_FAILURE; } - Result IsChainValid(const DERArray&, Time) override + Result IsChainValid(const DERArray&, Time, const CertPolicyId&) override { ADD_FAILURE(); return Result::FATAL_ERROR_LIBRARY_FAILURE; } Result DigestBuf(Input item, DigestAlgorithm digestAlg, /*out*/ uint8_t* digestBuf, size_t digestBufLen) override {
--- a/security/manager/ssl/CSTrustDomain.cpp +++ b/security/manager/ssl/CSTrustDomain.cpp @@ -133,18 +133,20 @@ CSTrustDomain::CheckRevocation(EndEntity /*optional*/ const Input* aiaExtension) { // We're relying solely on the CertBlocklist for revocation - and we're // performing checks on this in GetCertTrust (as per nsNSSCertDBTrustDomain) return Success; } Result -CSTrustDomain::IsChainValid(const DERArray& certChain, Time time) +CSTrustDomain::IsChainValid(const DERArray& certChain, Time time, + const CertPolicyId& requiredPolicy) { + MOZ_ASSERT(requiredPolicy.IsAnyPolicy()); // Check that our chain is not empty if (certChain.GetLength() == 0) { return Result::FATAL_ERROR_LIBRARY_FAILURE; } return Success; }
--- a/security/manager/ssl/CSTrustDomain.h +++ b/security/manager/ssl/CSTrustDomain.h @@ -34,17 +34,19 @@ public: mozilla::pkix::Time time) override; virtual Result CheckRevocation( mozilla::pkix::EndEntityOrCA endEntityOrCA, const mozilla::pkix::CertID& certID, mozilla::pkix::Time time, mozilla::pkix::Duration validityDuration, /*optional*/ const mozilla::pkix::Input* stapledOCSPresponse, /*optional*/ const mozilla::pkix::Input* aiaExtension) override; virtual Result IsChainValid(const mozilla::pkix::DERArray& certChain, - mozilla::pkix::Time time) override; + mozilla::pkix::Time time, + const mozilla::pkix::CertPolicyId& requiredPolicy) + override; virtual Result CheckSignatureDigestAlgorithm( mozilla::pkix::DigestAlgorithm digestAlg, mozilla::pkix::EndEntityOrCA endEntityOrCA, mozilla::pkix::Time notBefore) override; virtual Result CheckRSAPublicKeyModulusSizeInBits( mozilla::pkix::EndEntityOrCA endEntityOrCA, unsigned int modulusSizeInBits) override; virtual Result VerifyRSAPKCS1SignedDigest(
--- a/security/pkix/include/pkix/pkixtypes.h +++ b/security/pkix/include/pkix/pkixtypes.h @@ -88,16 +88,17 @@ enum class KeyPurposeId struct CertPolicyId final { uint16_t numBytes; static const uint16_t MAX_BYTES = 24; uint8_t bytes[MAX_BYTES]; bool IsAnyPolicy() const; + bool operator==(const CertPolicyId& other) const; static const CertPolicyId anyPolicy; }; enum class TrustLevel { TrustAnchor = 1, // certificate is a trusted root CA certificate or // equivalent *for the given policy*. @@ -274,17 +275,18 @@ public: // Keep in mind, in particular, that if the application saves a copy of the // certificate chain the last invocation of IsChainValid during a validation, // it is still possible for BuildCertChain to fail, in which case the // application must not assume anything about the validity of the last // certificate chain passed to IsChainValid; especially, it would be very // wrong to assume that the certificate chain is valid. // // certChain.GetDER(0) is the trust anchor. - virtual Result IsChainValid(const DERArray& certChain, Time time) = 0; + virtual Result IsChainValid(const DERArray& certChain, Time time, + const CertPolicyId& requiredPolicy) = 0; virtual Result CheckRevocation(EndEntityOrCA endEntityOrCA, const CertID& certID, Time time, Duration validityDuration, /*optional*/ const Input* stapledOCSPresponse, /*optional*/ const Input* aiaExtension) = 0; // Check that the given digest algorithm is acceptable for use in signatures.
--- a/security/pkix/lib/pkixbuild.cpp +++ b/security/pkix/lib/pkixbuild.cpp @@ -306,17 +306,17 @@ BuildForward(TrustDomain& trustDomain, rv = chain.Append(cert->GetDER()); if (rv != Success) { return NotReached("NonOwningDERArray::SetItem failed.", rv); } } // This must be done here, after the chain is built but before any // revocation checks have been done. - return trustDomain.IsChainValid(chain, time); + return trustDomain.IsChainValid(chain, time, requiredPolicy); } if (subject.endEntityOrCA == EndEntityOrCA::MustBeCA) { // Avoid stack overflows and poor performance by limiting cert chain // length. static const unsigned int MAX_SUBCA_COUNT = 6; static_assert(1/*end-entity*/ + MAX_SUBCA_COUNT + 1/*root*/ == NonOwningDERArray::MAX_LENGTH,
--- a/security/pkix/lib/pkixcheck.cpp +++ b/security/pkix/lib/pkixcheck.cpp @@ -527,16 +527,23 @@ bool CertPolicyId::IsAnyPolicy() const { if (this == &CertPolicyId::anyPolicy) { return true; } return numBytes == sizeof(::mozilla::pkix::anyPolicy) && std::equal(bytes, bytes + numBytes, ::mozilla::pkix::anyPolicy); } +bool +CertPolicyId::operator==(const CertPolicyId& other) const +{ + return numBytes == other.numBytes && + std::equal(bytes, bytes + numBytes, other.bytes); +} + // certificatePolicies ::= SEQUENCE SIZE (1..MAX) OF PolicyInformation Result CheckCertificatePolicies(EndEntityOrCA endEntityOrCA, const Input* encodedCertificatePolicies, const Input* encodedInhibitAnyPolicy, TrustLevel trustLevel, const CertPolicyId& requiredPolicy) {
--- a/security/pkix/test/gtest/pkixbuild_tests.cpp +++ b/security/pkix/test/gtest/pkixbuild_tests.cpp @@ -149,17 +149,17 @@ private: Result CheckRevocation(EndEntityOrCA, const CertID&, Time, Duration, /*optional*/ const Input*, /*optional*/ const Input*) override { return Success; } - Result IsChainValid(const DERArray&, Time) override + Result IsChainValid(const DERArray&, Time, const CertPolicyId&) override { return Success; } std::map<ByteString, ByteString> subjectDERToCertDER; ByteString leafCACertDER; ByteString rootCACertDER; }; @@ -286,17 +286,17 @@ public: Input rootCert; Result rv = rootCert.Init(rootDER.data(), rootDER.length()); if (rv != Success) { return rv; } return checker.Check(rootCert, nullptr, keepGoing); } - Result IsChainValid(const DERArray&, Time) override + Result IsChainValid(const DERArray&, Time, const CertPolicyId&) override { return Success; } Result CheckRevocation(EndEntityOrCA, const CertID&, Time, Duration, /*optional*/ const Input*, /*optional*/ const Input*) override { @@ -439,17 +439,17 @@ public: Result CheckRevocation(EndEntityOrCA, const CertID&, Time, Duration, /*optional*/ const Input*, /*optional*/ const Input*) override { return Success; } - Result IsChainValid(const DERArray&, Time) override + Result IsChainValid(const DERArray&, Time, const CertPolicyId&) override { return Success; } private: const ByteString issuer; const bool expectedKeepGoing; };
--- a/security/pkix/test/gtest/pkixcert_extension_tests.cpp +++ b/security/pkix/test/gtest/pkixcert_extension_tests.cpp @@ -71,17 +71,17 @@ private: Result CheckRevocation(EndEntityOrCA, const CertID&, Time, Duration, /*optional*/ const Input*, /*optional*/ const Input*) override { return Success; } - Result IsChainValid(const DERArray&, Time) override + Result IsChainValid(const DERArray&, Time, const CertPolicyId&) override { return Success; } }; // python DottedOIDToCode.py --tlv unknownExtensionOID 1.3.6.1.4.1.13769.666.666.666.1.500.9.3 static const uint8_t tlv_unknownExtensionOID[] = { 0x06, 0x12, 0x2b, 0x06, 0x01, 0x04, 0x01, 0xeb, 0x49, 0x85, 0x1a, 0x85, 0x1a,
--- a/security/pkix/test/gtest/pkixcert_signature_algorithm_tests.cpp +++ b/security/pkix/test/gtest/pkixcert_signature_algorithm_tests.cpp @@ -92,17 +92,17 @@ private: } Result CheckRevocation(EndEntityOrCA, const CertID&, Time, Duration, const Input*, const Input*) override { return Success; } - Result IsChainValid(const DERArray&, Time) override + Result IsChainValid(const DERArray&, Time, const CertPolicyId&) override { return Success; } ByteString rootDER; ByteString rootSubjectDER; ByteString intDER; ByteString intSubjectDER;
--- a/security/pkix/test/gtest/pkixcheck_CheckExtendedKeyUsage_tests.cpp +++ b/security/pkix/test/gtest/pkixcheck_CheckExtendedKeyUsage_tests.cpp @@ -558,17 +558,17 @@ private: } Result CheckRevocation(EndEntityOrCA, const CertID&, Time, Duration, const Input*, const Input*) override { return Success; } - Result IsChainValid(const DERArray&, Time) override + Result IsChainValid(const DERArray&, Time, const CertPolicyId&) override { return Success; } ByteString mIssuerCertDER; }; TEST_P(CheckExtendedKeyUsageChainTest, EKUChainTestcase)
--- a/security/pkix/test/gtest/pkixcheck_CheckSignatureAlgorithm_tests.cpp +++ b/security/pkix/test/gtest/pkixcheck_CheckSignatureAlgorithm_tests.cpp @@ -303,17 +303,17 @@ public: Result CheckRevocation(EndEntityOrCA, const CertID&, Time, Duration, /*optional*/ const Input*, /*optional*/ const Input*) override { return Success; } - Result IsChainValid(const DERArray&, Time) override + Result IsChainValid(const DERArray&, Time, const CertPolicyId&) override { return Success; } ByteString issuer; }; // Test that CheckSignatureAlgorithm actually gets called at some point when
--- a/security/pkix/test/gtest/pkixgtest.h +++ b/security/pkix/test/gtest/pkixgtest.h @@ -107,17 +107,17 @@ public: /*optional*/ const Input*, /*optional*/ const Input*) override { ADD_FAILURE(); return NotReached("CheckRevocation should not be called", Result::FATAL_ERROR_LIBRARY_FAILURE); } - Result IsChainValid(const DERArray&, Time) override + Result IsChainValid(const DERArray&, Time, const CertPolicyId&) override { ADD_FAILURE(); return NotReached("IsChainValid should not be called", Result::FATAL_ERROR_LIBRARY_FAILURE); } Result DigestBuf(Input, DigestAlgorithm, /*out*/ uint8_t*, size_t) override {