mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
bug 1071308 - (2/2) remove libpkix-style chain validation callback from CertVerifier r=cviecco
This commit is contained in:
parent
7aec2677f9
commit
28cf64b8af
@ -238,7 +238,7 @@ AppTrustDomain::CheckRevocation(EndEntityOrCA, const CertID&, Time,
|
||||
}
|
||||
|
||||
Result
|
||||
AppTrustDomain::IsChainValid(const DERArray& certChain)
|
||||
AppTrustDomain::IsChainValid(const DERArray& certChain, Time time)
|
||||
{
|
||||
SECStatus srv = ConstructCERTCertListFromReversedDERArray(certChain,
|
||||
mCertChain);
|
||||
|
@ -36,8 +36,8 @@ public:
|
||||
mozilla::pkix::Time time,
|
||||
/*optional*/ const mozilla::pkix::Input* stapledOCSPresponse,
|
||||
/*optional*/ const mozilla::pkix::Input* aiaExtension);
|
||||
virtual Result IsChainValid(const mozilla::pkix::DERArray& certChain)
|
||||
MOZ_OVERRIDE;
|
||||
virtual Result IsChainValid(const mozilla::pkix::DERArray& certChain,
|
||||
mozilla::pkix::Time time) MOZ_OVERRIDE;
|
||||
virtual Result CheckPublicKey(mozilla::pkix::Input subjectPublicKeyInfo)
|
||||
MOZ_OVERRIDE;
|
||||
virtual Result VerifySignedData(
|
||||
|
@ -81,78 +81,45 @@ IsCertBuiltInRoot(CERTCertificate* cert, bool& result) {
|
||||
return SECSuccess;
|
||||
}
|
||||
|
||||
struct ChainValidationCallbackState
|
||||
Result
|
||||
CertListContainsExpectedKeys(const CERTCertList* certList,
|
||||
const char* hostname, Time time,
|
||||
CertVerifier::PinningMode pinningMode)
|
||||
{
|
||||
const char* hostname;
|
||||
const CertVerifier::PinningMode pinningMode;
|
||||
const SECCertificateUsage usage;
|
||||
const Time time;
|
||||
};
|
||||
if (pinningMode == CertVerifier::pinningDisabled) {
|
||||
PR_LOG(gCertVerifierLog, PR_LOG_DEBUG,
|
||||
("Pinning is disabled; not checking keys."));
|
||||
return Success;
|
||||
}
|
||||
|
||||
SECStatus chainValidationCallback(void* state, const CERTCertList* certList,
|
||||
PRBool* chainOK)
|
||||
{
|
||||
ChainValidationCallbackState* callbackState =
|
||||
reinterpret_cast<ChainValidationCallbackState*>(state);
|
||||
|
||||
*chainOK = PR_FALSE;
|
||||
|
||||
PR_LOG(gCertVerifierLog, PR_LOG_DEBUG,
|
||||
("verifycert: Inside the Callback \n"));
|
||||
|
||||
// On sanity failure we fail closed.
|
||||
if (!certList) {
|
||||
PR_LOG(gCertVerifierLog, PR_LOG_DEBUG,
|
||||
("verifycert: Short circuit, callback, sanity check failed \n"));
|
||||
PR_SetError(PR_INVALID_STATE_ERROR, 0);
|
||||
return SECFailure;
|
||||
}
|
||||
if (!callbackState) {
|
||||
PR_LOG(gCertVerifierLog, PR_LOG_DEBUG,
|
||||
("verifycert: Short circuit, callback, no state! \n"));
|
||||
PR_SetError(PR_INVALID_STATE_ERROR, 0);
|
||||
return SECFailure;
|
||||
return Result::FATAL_ERROR_INVALID_ARGS;
|
||||
}
|
||||
|
||||
if (callbackState->usage != certificateUsageSSLServer ||
|
||||
callbackState->pinningMode == CertVerifier::pinningDisabled) {
|
||||
PR_LOG(gCertVerifierLog, PR_LOG_DEBUG,
|
||||
("verifycert: Callback shortcut pel=%d \n",
|
||||
callbackState->pinningMode));
|
||||
*chainOK = PR_TRUE;
|
||||
return SECSuccess;
|
||||
CERTCertListNode* rootNode = CERT_LIST_TAIL(certList);
|
||||
if (CERT_LIST_END(rootNode, certList)) {
|
||||
return Result::FATAL_ERROR_INVALID_ARGS;
|
||||
}
|
||||
|
||||
for (CERTCertListNode* node = CERT_LIST_HEAD(certList);
|
||||
!CERT_LIST_END(node, certList);
|
||||
node = CERT_LIST_NEXT(node)) {
|
||||
CERTCertificate* currentCert = node->cert;
|
||||
if (CERT_LIST_END(CERT_LIST_NEXT(node), certList)) {
|
||||
bool isBuiltInRoot = false;
|
||||
SECStatus srv = IsCertBuiltInRoot(currentCert, isBuiltInRoot);
|
||||
if (srv != SECSuccess) {
|
||||
PR_LOG(gCertVerifierLog, PR_LOG_DEBUG, ("Is BuiltInRoot failure"));
|
||||
return srv;
|
||||
}
|
||||
// If desired, the user can enable "allow user CA MITM mode", in which
|
||||
// case key pinning is not enforced for certificates that chain to trust
|
||||
// anchors that are not in Mozilla's root program
|
||||
if (!isBuiltInRoot &&
|
||||
(callbackState->pinningMode ==
|
||||
CertVerifier::pinningAllowUserCAMITM)) {
|
||||
*chainOK = PR_TRUE;
|
||||
return SECSuccess;
|
||||
}
|
||||
}
|
||||
bool isBuiltInRoot = false;
|
||||
SECStatus srv = IsCertBuiltInRoot(rootNode->cert, isBuiltInRoot);
|
||||
if (srv != SECSuccess) {
|
||||
return MapPRErrorCodeToResult(PR_GetError());
|
||||
}
|
||||
// If desired, the user can enable "allow user CA MITM mode", in which
|
||||
// case key pinning is not enforced for certificates that chain to trust
|
||||
// anchors that are not in Mozilla's root program
|
||||
if (!isBuiltInRoot && pinningMode == CertVerifier::pinningAllowUserCAMITM) {
|
||||
return Success;
|
||||
}
|
||||
|
||||
bool enforceTestMode = (callbackState->pinningMode ==
|
||||
CertVerifier::pinningEnforceTestMode);
|
||||
*chainOK = PublicKeyPinningService::
|
||||
ChainHasValidPins(certList, callbackState->hostname, callbackState->time,
|
||||
enforceTestMode);
|
||||
bool enforceTestMode = (pinningMode == CertVerifier::pinningEnforceTestMode);
|
||||
if (PublicKeyPinningService::ChainHasValidPins(certList, hostname, time,
|
||||
enforceTestMode)) {
|
||||
return Success;
|
||||
}
|
||||
|
||||
return SECSuccess;
|
||||
return Result::ERROR_KEY_PINNING_FAILURE;
|
||||
}
|
||||
|
||||
static Result
|
||||
@ -216,13 +183,6 @@ CertVerifier::VerifyCert(CERTCertificate* cert, SECCertificateUsage usage,
|
||||
return SECFailure;
|
||||
}
|
||||
|
||||
ChainValidationCallbackState callbackState = {
|
||||
hostname, mPinningMode, usage, time
|
||||
};
|
||||
CERTChainVerifyCallback callbackContainer;
|
||||
callbackContainer.isChainValid = chainValidationCallback;
|
||||
callbackContainer.isChainValidArg = &callbackState;
|
||||
|
||||
NSSCertDBTrustDomain::OCSPFetching ocspFetching
|
||||
= !mOCSPDownloadEnabled ||
|
||||
(flags & FLAG_LOCAL_ONLY) ? NSSCertDBTrustDomain::NeverFetchOCSP
|
||||
@ -250,8 +210,8 @@ CertVerifier::VerifyCert(CERTCertificate* cert, SECCertificateUsage usage,
|
||||
// XXX: We don't really have a trust bit for SSL client authentication so
|
||||
// just use trustEmail as it is the closest alternative.
|
||||
NSSCertDBTrustDomain trustDomain(trustEmail, ocspFetching, mOCSPCache,
|
||||
pinArg, ocspGETConfig, nullptr,
|
||||
builtChain);
|
||||
pinArg, ocspGETConfig, pinningDisabled,
|
||||
nullptr, builtChain);
|
||||
rv = BuildCertChain(trustDomain, certDER, time,
|
||||
EndEntityOrCA::MustBeEndEntity,
|
||||
KeyUsage::digitalSignature,
|
||||
@ -276,8 +236,8 @@ CertVerifier::VerifyCert(CERTCertificate* cert, SECCertificateUsage usage,
|
||||
ocspFetching == NSSCertDBTrustDomain::NeverFetchOCSP
|
||||
? NSSCertDBTrustDomain::LocalOnlyOCSPForEV
|
||||
: NSSCertDBTrustDomain::FetchOCSPForEV,
|
||||
mOCSPCache, pinArg, ocspGETConfig,
|
||||
&callbackContainer, builtChain);
|
||||
mOCSPCache, pinArg, ocspGETConfig, mPinningMode,
|
||||
hostname, builtChain);
|
||||
rv = BuildCertChainForOneKeyUsage(trustDomain, certDER, time,
|
||||
KeyUsage::digitalSignature,// (EC)DHE
|
||||
KeyUsage::keyEncipherment, // RSA
|
||||
@ -300,8 +260,8 @@ CertVerifier::VerifyCert(CERTCertificate* cert, SECCertificateUsage usage,
|
||||
|
||||
// Now try non-EV.
|
||||
NSSCertDBTrustDomain trustDomain(trustSSL, ocspFetching, mOCSPCache,
|
||||
pinArg, ocspGETConfig, &callbackContainer,
|
||||
builtChain);
|
||||
pinArg, ocspGETConfig, mPinningMode,
|
||||
hostname, builtChain);
|
||||
rv = BuildCertChainForOneKeyUsage(trustDomain, certDER, time,
|
||||
KeyUsage::digitalSignature, // (EC)DHE
|
||||
KeyUsage::keyEncipherment, // RSA
|
||||
@ -314,8 +274,8 @@ CertVerifier::VerifyCert(CERTCertificate* cert, SECCertificateUsage usage,
|
||||
|
||||
case certificateUsageSSLCA: {
|
||||
NSSCertDBTrustDomain trustDomain(trustSSL, ocspFetching, mOCSPCache,
|
||||
pinArg, ocspGETConfig, nullptr,
|
||||
builtChain);
|
||||
pinArg, ocspGETConfig, pinningDisabled,
|
||||
nullptr, builtChain);
|
||||
rv = BuildCertChain(trustDomain, certDER, time,
|
||||
EndEntityOrCA::MustBeCA, KeyUsage::keyCertSign,
|
||||
KeyPurposeId::id_kp_serverAuth,
|
||||
@ -325,8 +285,8 @@ CertVerifier::VerifyCert(CERTCertificate* cert, SECCertificateUsage usage,
|
||||
|
||||
case certificateUsageEmailSigner: {
|
||||
NSSCertDBTrustDomain trustDomain(trustEmail, ocspFetching, mOCSPCache,
|
||||
pinArg, ocspGETConfig, nullptr,
|
||||
builtChain);
|
||||
pinArg, ocspGETConfig, pinningDisabled,
|
||||
nullptr, builtChain);
|
||||
rv = BuildCertChain(trustDomain, certDER, time,
|
||||
EndEntityOrCA::MustBeEndEntity,
|
||||
KeyUsage::digitalSignature,
|
||||
@ -340,8 +300,8 @@ CertVerifier::VerifyCert(CERTCertificate* cert, SECCertificateUsage usage,
|
||||
// usage it is trying to verify for, and base its algorithm choices
|
||||
// based on the result of the verification(s).
|
||||
NSSCertDBTrustDomain trustDomain(trustEmail, ocspFetching, mOCSPCache,
|
||||
pinArg, ocspGETConfig, nullptr,
|
||||
builtChain);
|
||||
pinArg, ocspGETConfig, pinningDisabled,
|
||||
nullptr, builtChain);
|
||||
rv = BuildCertChain(trustDomain, certDER, time,
|
||||
EndEntityOrCA::MustBeEndEntity,
|
||||
KeyUsage::keyEncipherment, // RSA
|
||||
@ -360,7 +320,7 @@ CertVerifier::VerifyCert(CERTCertificate* cert, SECCertificateUsage usage,
|
||||
case certificateUsageObjectSigner: {
|
||||
NSSCertDBTrustDomain trustDomain(trustObjectSigning, ocspFetching,
|
||||
mOCSPCache, pinArg, ocspGETConfig,
|
||||
nullptr, builtChain);
|
||||
pinningDisabled, nullptr, builtChain);
|
||||
rv = BuildCertChain(trustDomain, certDER, time,
|
||||
EndEntityOrCA::MustBeEndEntity,
|
||||
KeyUsage::digitalSignature,
|
||||
@ -388,14 +348,15 @@ CertVerifier::VerifyCert(CERTCertificate* cert, SECCertificateUsage usage,
|
||||
}
|
||||
|
||||
NSSCertDBTrustDomain sslTrust(trustSSL, ocspFetching, mOCSPCache, pinArg,
|
||||
ocspGETConfig, nullptr, builtChain);
|
||||
ocspGETConfig, pinningDisabled, nullptr,
|
||||
builtChain);
|
||||
rv = BuildCertChain(sslTrust, certDER, time, endEntityOrCA,
|
||||
keyUsage, eku, CertPolicyId::anyPolicy,
|
||||
stapledOCSPResponse);
|
||||
if (rv == Result::ERROR_UNKNOWN_ISSUER) {
|
||||
NSSCertDBTrustDomain emailTrust(trustEmail, ocspFetching, mOCSPCache,
|
||||
pinArg, ocspGETConfig, nullptr,
|
||||
builtChain);
|
||||
pinArg, ocspGETConfig, pinningDisabled,
|
||||
nullptr, builtChain);
|
||||
rv = BuildCertChain(emailTrust, certDER, time, endEntityOrCA,
|
||||
keyUsage, eku, CertPolicyId::anyPolicy,
|
||||
stapledOCSPResponse);
|
||||
@ -403,7 +364,8 @@ CertVerifier::VerifyCert(CERTCertificate* cert, SECCertificateUsage usage,
|
||||
NSSCertDBTrustDomain objectSigningTrust(trustObjectSigning,
|
||||
ocspFetching, mOCSPCache,
|
||||
pinArg, ocspGETConfig,
|
||||
nullptr, builtChain);
|
||||
pinningDisabled, nullptr,
|
||||
builtChain);
|
||||
rv = BuildCertChain(objectSigningTrust, certDER, time,
|
||||
endEntityOrCA, keyUsage, eku,
|
||||
CertPolicyId::anyPolicy, stapledOCSPResponse);
|
||||
@ -418,7 +380,8 @@ CertVerifier::VerifyCert(CERTCertificate* cert, SECCertificateUsage usage,
|
||||
}
|
||||
|
||||
if (rv != Success) {
|
||||
if (rv != Result::ERROR_KEY_PINNING_FAILURE) {
|
||||
if (rv != Result::ERROR_KEY_PINNING_FAILURE &&
|
||||
usage == certificateUsageSSLServer) {
|
||||
ScopedCERTCertificate certCopy(CERT_DupCertificate(cert));
|
||||
if (!certCopy) {
|
||||
return SECFailure;
|
||||
@ -432,13 +395,10 @@ CertVerifier::VerifyCert(CERTCertificate* cert, SECCertificateUsage usage,
|
||||
return SECFailure;
|
||||
}
|
||||
certCopy.forget(); // now owned by certList
|
||||
PRBool chainOK = false;
|
||||
srv = chainValidationCallback(&callbackState, certList, &chainOK);
|
||||
if (srv != SECSuccess) {
|
||||
return SECFailure;
|
||||
}
|
||||
if (!chainOK) {
|
||||
rv = Result::ERROR_KEY_PINNING_FAILURE;
|
||||
Result pinningResult = CertListContainsExpectedKeys(certList, hostname,
|
||||
time, mPinningMode);
|
||||
if (pinningResult != Success) {
|
||||
rv = pinningResult;
|
||||
}
|
||||
}
|
||||
PR_SetError(MapResultToPRErrorCode(rv), 0);
|
||||
|
@ -79,6 +79,9 @@ private:
|
||||
|
||||
void InitCertVerifierLog();
|
||||
SECStatus IsCertBuiltInRoot(CERTCertificate* cert, bool& result);
|
||||
mozilla::pkix::Result CertListContainsExpectedKeys(
|
||||
const CERTCertList* certList, const char* hostname, mozilla::pkix::Time time,
|
||||
CertVerifier::PinningMode pinningMode);
|
||||
|
||||
} } // namespace mozilla::psm
|
||||
|
||||
|
@ -52,14 +52,16 @@ NSSCertDBTrustDomain::NSSCertDBTrustDomain(SECTrustType certDBTrustType,
|
||||
OCSPCache& ocspCache,
|
||||
/*optional but shouldn't be*/ void* pinArg,
|
||||
CertVerifier::ocsp_get_config ocspGETConfig,
|
||||
/*optional*/ CERTChainVerifyCallback* checkChainCallback,
|
||||
CertVerifier::PinningMode pinningMode,
|
||||
/*optional*/ const char* hostname,
|
||||
/*optional*/ ScopedCERTCertList* builtChain)
|
||||
: mCertDBTrustType(certDBTrustType)
|
||||
, mOCSPFetching(ocspFetching)
|
||||
, mOCSPCache(ocspCache)
|
||||
, mPinArg(pinArg)
|
||||
, mOCSPGetConfig(ocspGETConfig)
|
||||
, mCheckChainCallback(checkChainCallback)
|
||||
, mPinningMode(pinningMode)
|
||||
, mHostname(hostname)
|
||||
, mBuiltChain(builtChain)
|
||||
{
|
||||
}
|
||||
@ -633,16 +635,10 @@ NSSCertDBTrustDomain::VerifyAndMaybeCacheEncodedOCSPResponse(
|
||||
}
|
||||
|
||||
Result
|
||||
NSSCertDBTrustDomain::IsChainValid(const DERArray& certArray)
|
||||
NSSCertDBTrustDomain::IsChainValid(const DERArray& certArray, Time time)
|
||||
{
|
||||
PR_LOG(gCertVerifierLog, PR_LOG_DEBUG,
|
||||
("NSSCertDBTrustDomain: Top of IsChainValid mCheckChainCallback=%p",
|
||||
mCheckChainCallback));
|
||||
|
||||
if (!mBuiltChain && !mCheckChainCallback) {
|
||||
// No need to create a CERTCertList, and nothing else to do.
|
||||
return Success;
|
||||
}
|
||||
("NSSCertDBTrustDomain: IsChainValid"));
|
||||
|
||||
ScopedCERTCertList certList;
|
||||
SECStatus srv = ConstructCERTCertListFromReversedDERArray(certArray,
|
||||
@ -651,19 +647,10 @@ NSSCertDBTrustDomain::IsChainValid(const DERArray& certArray)
|
||||
return MapPRErrorCodeToResult(PR_GetError());
|
||||
}
|
||||
|
||||
if (mCheckChainCallback) {
|
||||
if (!mCheckChainCallback->isChainValid) {
|
||||
return Result::FATAL_ERROR_INVALID_ARGS;
|
||||
}
|
||||
PRBool chainOK;
|
||||
srv = (mCheckChainCallback->isChainValid)(
|
||||
mCheckChainCallback->isChainValidArg, certList.get(), &chainOK);
|
||||
if (srv != SECSuccess) {
|
||||
return MapPRErrorCodeToResult(PR_GetError());
|
||||
}
|
||||
if (!chainOK) {
|
||||
return Result::ERROR_KEY_PINNING_FAILURE;
|
||||
}
|
||||
Result result = CertListContainsExpectedKeys(certList, mHostname, time,
|
||||
mPinningMode);
|
||||
if (result != Success) {
|
||||
return result;
|
||||
}
|
||||
|
||||
if (mBuiltChain) {
|
||||
|
@ -53,8 +53,9 @@ public:
|
||||
NSSCertDBTrustDomain(SECTrustType certDBTrustType, OCSPFetching ocspFetching,
|
||||
OCSPCache& ocspCache, void* pinArg,
|
||||
CertVerifier::ocsp_get_config ocspGETConfig,
|
||||
/*optional*/ CERTChainVerifyCallback* checkChainCallback = nullptr,
|
||||
/*optional*/ ScopedCERTCertList* builtChain = nullptr);
|
||||
CertVerifier::PinningMode pinningMode,
|
||||
/*optional*/ const char* hostname = nullptr,
|
||||
/*optional out*/ ScopedCERTCertList* builtChain = nullptr);
|
||||
|
||||
virtual Result FindIssuer(mozilla::pkix::Input encodedIssuerName,
|
||||
IssuerChecker& checker,
|
||||
@ -86,8 +87,8 @@ public:
|
||||
/*optional*/ const mozilla::pkix::Input* aiaExtension)
|
||||
MOZ_OVERRIDE;
|
||||
|
||||
virtual Result IsChainValid(const mozilla::pkix::DERArray& certChain)
|
||||
MOZ_OVERRIDE;
|
||||
virtual Result IsChainValid(const mozilla::pkix::DERArray& certChain,
|
||||
mozilla::pkix::Time time) MOZ_OVERRIDE;
|
||||
|
||||
private:
|
||||
enum EncodedResponseSource {
|
||||
@ -104,7 +105,8 @@ private:
|
||||
OCSPCache& mOCSPCache; // non-owning!
|
||||
void* mPinArg; // non-owning!
|
||||
const CertVerifier::ocsp_get_config mOCSPGetConfig;
|
||||
CERTChainVerifyCallback* mCheckChainCallback; // non-owning!
|
||||
CertVerifier::PinningMode mPinningMode;
|
||||
const char* mHostname; // non-owning - only used for pinning checks
|
||||
ScopedCERTCertList* mBuiltChain; // non-owning
|
||||
};
|
||||
|
||||
|
@ -282,7 +282,7 @@ public:
|
||||
// very wrong to assume that the certificate chain is valid.
|
||||
//
|
||||
// certChain.GetDER(0) is the trust anchor.
|
||||
virtual Result IsChainValid(const DERArray& certChain) = 0;
|
||||
virtual Result IsChainValid(const DERArray& certChain, Time time) = 0;
|
||||
|
||||
// issuerCertToDup is only non-const so CERT_DupCertificate can be called on
|
||||
// it.
|
||||
|
@ -246,7 +246,7 @@ BuildForward(TrustDomain& trustDomain,
|
||||
|
||||
// This must be done here, after the chain is built but before any
|
||||
// revocation checks have been done.
|
||||
return trustDomain.IsChainValid(chain);
|
||||
return trustDomain.IsChainValid(chain, time);
|
||||
}
|
||||
|
||||
if (subject.endEntityOrCA == EndEntityOrCA::MustBeCA) {
|
||||
|
@ -165,7 +165,7 @@ private:
|
||||
return Success;
|
||||
}
|
||||
|
||||
virtual Result IsChainValid(const DERArray&)
|
||||
virtual Result IsChainValid(const DERArray&, Time)
|
||||
{
|
||||
return Success;
|
||||
}
|
||||
|
@ -87,7 +87,7 @@ private:
|
||||
return Success;
|
||||
}
|
||||
|
||||
virtual Result IsChainValid(const DERArray&)
|
||||
virtual Result IsChainValid(const DERArray&, Time)
|
||||
{
|
||||
return Success;
|
||||
}
|
||||
|
@ -53,7 +53,7 @@ private:
|
||||
return Result::FATAL_ERROR_LIBRARY_FAILURE;
|
||||
}
|
||||
|
||||
virtual Result IsChainValid(const DERArray&)
|
||||
virtual Result IsChainValid(const DERArray&, Time)
|
||||
{
|
||||
ADD_FAILURE();
|
||||
return Result::FATAL_ERROR_LIBRARY_FAILURE;
|
||||
|
@ -63,7 +63,7 @@ public:
|
||||
return Result::FATAL_ERROR_LIBRARY_FAILURE;
|
||||
}
|
||||
|
||||
virtual Result IsChainValid(const DERArray&)
|
||||
virtual Result IsChainValid(const DERArray&, Time)
|
||||
{
|
||||
ADD_FAILURE();
|
||||
return Result::FATAL_ERROR_LIBRARY_FAILURE;
|
||||
|
Loading…
Reference in New Issue
Block a user