Bug 1183822 - fix OCSP verification failures (r=keeler)

Adds a new TrustDomain for OCSP Signers which will always allow all acceptible
signature digest algorithms. Calls to most other TrustDomain methods are passed
through to the owning NSSCertDBTrustDomain.
This commit is contained in:
Mark Goodwin 2015-07-17 10:03:56 +01:00
parent 00edef09b4
commit 80b97ddffc
4 changed files with 202 additions and 1 deletions

View File

@ -10,6 +10,7 @@
#include "ExtendedValidation.h"
#include "OCSPRequestor.h"
#include "OCSPVerificationTrustDomain.h"
#include "certdb.h"
#include "cert.h"
#include "mozilla/UniquePtr.h"
@ -638,7 +639,17 @@ NSSCertDBTrustDomain::VerifyAndMaybeCacheEncodedOCSPResponse(
{
Time thisUpdate(Time::uninitialized);
Time validThrough(Time::uninitialized);
Result rv = VerifyEncodedOCSPResponse(*this, certID, time,
// We use a try and fallback approach which first mandates good signature
// digest algorithms, then falls back to SHA-1 if this fails. If a delegated
// OCSP response signing certificate was issued with a SHA-1 signature,
// verification initially fails. We cache the failure and then re-use that
// result even when doing fallback (i.e. when weak signature digest algorithms
// should succeed). To address this we use an OCSPVerificationTrustDomain
// here, rather than using *this, to ensure verification succeeds for all
// allowed signature digest algorithms.
OCSPVerificationTrustDomain trustDomain(*this);
Result rv = VerifyEncodedOCSPResponse(trustDomain, certID, time,
maxLifetimeInDays, encodedResponse,
expired, &thisUpdate, &validThrough);
// If a response was stapled and expired, we don't want to cache it. Return

View File

@ -0,0 +1,110 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "OCSPVerificationTrustDomain.h"
using namespace mozilla;
using namespace mozilla::pkix;
OCSPVerificationTrustDomain::OCSPVerificationTrustDomain(
NSSCertDBTrustDomain& certDBTrustDomain)
: mCertDBTrustDomain(certDBTrustDomain)
{
}
Result
OCSPVerificationTrustDomain::GetCertTrust(EndEntityOrCA endEntityOrCA,
const CertPolicyId& policy,
Input candidateCertDER,
/*out*/ TrustLevel& trustLevel)
{
return mCertDBTrustDomain.GetCertTrust(endEntityOrCA, policy,
candidateCertDER, trustLevel);
}
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)
{
// 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*,
const Input*)
{
// We do not expect this to be called for OCSP signers
return Result::FATAL_ERROR_LIBRARY_FAILURE;
}
Result
OCSPVerificationTrustDomain::CheckSignatureDigestAlgorithm(
DigestAlgorithm aAlg, EndEntityOrCA aEEOrCA)
{
// The reason for wrapping the NSSCertDBTrustDomain in an
// OCSPVerificationTrustDomain is to allow us to bypass the weaker signature
// algorithm check - thus all allowable signature digest algorithms should
// always be accepted. This is only needed while we gather telemetry on SHA-1.
return Success;
}
Result
OCSPVerificationTrustDomain::CheckRSAPublicKeyModulusSizeInBits(
EndEntityOrCA aEEOrCA, unsigned int aModulusSizeInBits)
{
return mCertDBTrustDomain.
CheckRSAPublicKeyModulusSizeInBits(aEEOrCA, aModulusSizeInBits);
}
Result
OCSPVerificationTrustDomain::VerifyRSAPKCS1SignedDigest(
const SignedDigest& aSignedDigest, Input aSubjectPublicKeyInfo)
{
return mCertDBTrustDomain.VerifyRSAPKCS1SignedDigest(aSignedDigest,
aSubjectPublicKeyInfo);
}
Result
OCSPVerificationTrustDomain::CheckECDSACurveIsAcceptable(
EndEntityOrCA aEEOrCA, NamedCurve aCurve)
{
return mCertDBTrustDomain.CheckECDSACurveIsAcceptable(aEEOrCA, aCurve);
}
Result
OCSPVerificationTrustDomain::VerifyECDSASignedDigest(
const SignedDigest& aSignedDigest, Input aSubjectPublicKeyInfo)
{
return mCertDBTrustDomain.VerifyECDSASignedDigest(aSignedDigest,
aSubjectPublicKeyInfo);
}
Result
OCSPVerificationTrustDomain::CheckValidityIsAcceptable(
Time notBefore, Time notAfter, EndEntityOrCA endEntityOrCA,
KeyPurposeId keyPurpose)
{
return mCertDBTrustDomain.CheckValidityIsAcceptable(notBefore, notAfter,
endEntityOrCA,
keyPurpose);
}
Result
OCSPVerificationTrustDomain::DigestBuf(
Input item, DigestAlgorithm digestAlg,
/*out*/ uint8_t* digestBuf, size_t digestBufLen)
{
return mCertDBTrustDomain.DigestBuf(item, digestAlg, digestBuf, digestBufLen);
}

View File

@ -0,0 +1,79 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef mozilla_psm__OCSPVerificationTrustDomain_h
#define mozilla_psm__OCSPVerificationTrustDomain_h
#include "pkix/pkixtypes.h"
#include "NSSCertDBTrustDomain.h"
namespace mozilla { namespace psm {
class OCSPVerificationTrustDomain : public mozilla::pkix::TrustDomain
{
public:
OCSPVerificationTrustDomain(NSSCertDBTrustDomain& certDBTrustDomain);
virtual Result FindIssuer(mozilla::pkix::Input encodedIssuerName,
IssuerChecker& checker,
mozilla::pkix::Time time) override;
virtual Result GetCertTrust(mozilla::pkix::EndEntityOrCA endEntityOrCA,
const mozilla::pkix::CertPolicyId& policy,
mozilla::pkix::Input candidateCertDER,
/*out*/ mozilla::pkix::TrustLevel& trustLevel)
override;
virtual Result CheckSignatureDigestAlgorithm(
mozilla::pkix::DigestAlgorithm digestAlg,
mozilla::pkix::EndEntityOrCA endEntityOrCA) override;
virtual Result CheckRSAPublicKeyModulusSizeInBits(
mozilla::pkix::EndEntityOrCA endEntityOrCA,
unsigned int modulusSizeInBits) override;
virtual Result VerifyRSAPKCS1SignedDigest(
const mozilla::pkix::SignedDigest& signedDigest,
mozilla::pkix::Input subjectPublicKeyInfo) override;
virtual Result CheckECDSACurveIsAcceptable(
mozilla::pkix::EndEntityOrCA endEntityOrCA,
mozilla::pkix::NamedCurve curve) override;
virtual Result VerifyECDSASignedDigest(
const mozilla::pkix::SignedDigest& signedDigest,
mozilla::pkix::Input subjectPublicKeyInfo) override;
virtual Result DigestBuf(mozilla::pkix::Input item,
mozilla::pkix::DigestAlgorithm digestAlg,
/*out*/ uint8_t* digestBuf,
size_t digestBufLen) override;
virtual Result CheckValidityIsAcceptable(
mozilla::pkix::Time notBefore, mozilla::pkix::Time notAfter,
mozilla::pkix::EndEntityOrCA endEntityOrCA,
mozilla::pkix::KeyPurposeId keyPurpose) 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;
private:
NSSCertDBTrustDomain& mCertDBTrustDomain;
};
} } // namespace mozilla::psm
#endif // mozilla_psm__OCSPVerificationTrustDomain_h

View File

@ -14,6 +14,7 @@ UNIFIED_SOURCES += [
'NSSCertDBTrustDomain.cpp',
'OCSPCache.cpp',
'OCSPRequestor.cpp',
'OCSPVerificationTrustDomain.cpp',
]
if not CONFIG['NSS_NO_EV_CERTS']: