mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 1033563, Part 3: Change mozilla::pkix::TrustDomain::FindPotentialIssuers API to be iterator-like, r=keeler
--HG-- extra : rebase_source : e8c734ecb2de2c52dd8909c8b48f4bdb09d0128e
This commit is contained in:
parent
b79a1c89fd
commit
5a21cfd0b8
@ -86,9 +86,9 @@ AppTrustDomain::SetTrustedRoot(AppTrustedRoot trustedRoot)
|
||||
}
|
||||
|
||||
SECStatus
|
||||
AppTrustDomain::FindPotentialIssuers(const SECItem* encodedIssuerName,
|
||||
PRTime time,
|
||||
/*out*/ mozilla::pkix::ScopedCERTCertList& results)
|
||||
AppTrustDomain::FindIssuer(const SECItem& encodedIssuerName,
|
||||
IssuerChecker& checker, PRTime time)
|
||||
|
||||
{
|
||||
MOZ_ASSERT(mTrustedRoot);
|
||||
if (!mTrustedRoot) {
|
||||
@ -96,8 +96,31 @@ AppTrustDomain::FindPotentialIssuers(const SECItem* encodedIssuerName,
|
||||
return SECFailure;
|
||||
}
|
||||
|
||||
results = CERT_CreateSubjectCertList(nullptr, CERT_GetDefaultCertDB(),
|
||||
encodedIssuerName, time, true);
|
||||
// TODO(bug 1035418): If/when mozilla::pkix relaxes the restriction that
|
||||
// FindIssuer must only pass certificates with a matching subject name to
|
||||
// checker.Check, we can stop using CERT_CreateSubjectCertList and instead
|
||||
// use logic like this:
|
||||
//
|
||||
// 1. First, try the trusted trust anchor.
|
||||
// 2. Secondly, iterate through the certificates that were stored in the CMS
|
||||
// message, passing each one to checker.Check.
|
||||
mozilla::pkix::ScopedCERTCertList
|
||||
candidates(CERT_CreateSubjectCertList(nullptr, CERT_GetDefaultCertDB(),
|
||||
&encodedIssuerName, time, true));
|
||||
if (candidates) {
|
||||
for (CERTCertListNode* n = CERT_LIST_HEAD(candidates);
|
||||
!CERT_LIST_END(n, candidates); n = CERT_LIST_NEXT(n)) {
|
||||
bool keepGoing;
|
||||
SECStatus srv = checker.Check(n->cert->derCert, keepGoing);
|
||||
if (srv != SECSuccess) {
|
||||
return SECFailure;
|
||||
}
|
||||
if (!keepGoing) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return SECSuccess;
|
||||
}
|
||||
|
||||
|
@ -24,10 +24,8 @@ public:
|
||||
const mozilla::pkix::CertPolicyId& policy,
|
||||
const SECItem& candidateCertDER,
|
||||
/*out*/ mozilla::pkix::TrustLevel* trustLevel) MOZ_OVERRIDE;
|
||||
SECStatus FindPotentialIssuers(const SECItem* encodedIssuerName,
|
||||
PRTime time,
|
||||
/*out*/ mozilla::pkix::ScopedCERTCertList& results)
|
||||
MOZ_OVERRIDE;
|
||||
SECStatus FindIssuer(const SECItem& encodedIssuerName,
|
||||
IssuerChecker& checker, PRTime time) MOZ_OVERRIDE;
|
||||
SECStatus VerifySignedData(const CERTSignedData& signedData,
|
||||
const SECItem& subjectPublicKeyInfo) MOZ_OVERRIDE;
|
||||
SECStatus CheckRevocation(mozilla::pkix::EndEntityOrCA endEntityOrCA,
|
||||
|
@ -56,15 +56,28 @@ NSSCertDBTrustDomain::NSSCertDBTrustDomain(SECTrustType certDBTrustType,
|
||||
}
|
||||
|
||||
SECStatus
|
||||
NSSCertDBTrustDomain::FindPotentialIssuers(
|
||||
const SECItem* encodedIssuerName, PRTime time,
|
||||
/*out*/ mozilla::pkix::ScopedCERTCertList& results)
|
||||
NSSCertDBTrustDomain::FindIssuer(const SECItem& encodedIssuerName,
|
||||
IssuerChecker& checker, PRTime time)
|
||||
{
|
||||
// TODO: normalize encodedIssuerName
|
||||
// TODO: NSS seems to be ambiguous between "no potential issuers found" and
|
||||
// "there was an error trying to retrieve the potential issuers."
|
||||
results = CERT_CreateSubjectCertList(nullptr, CERT_GetDefaultCertDB(),
|
||||
encodedIssuerName, time, true);
|
||||
mozilla::pkix::ScopedCERTCertList
|
||||
candidates(CERT_CreateSubjectCertList(nullptr, CERT_GetDefaultCertDB(),
|
||||
&encodedIssuerName, time, true));
|
||||
if (candidates) {
|
||||
for (CERTCertListNode* n = CERT_LIST_HEAD(candidates);
|
||||
!CERT_LIST_END(n, candidates); n = CERT_LIST_NEXT(n)) {
|
||||
bool keepGoing;
|
||||
SECStatus srv = checker.Check(n->cert->derCert, keepGoing);
|
||||
if (srv != SECSuccess) {
|
||||
return SECFailure;
|
||||
}
|
||||
if (!keepGoing) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return SECSuccess;
|
||||
}
|
||||
|
||||
|
@ -53,10 +53,8 @@ public:
|
||||
CertVerifier::ocsp_get_config ocspGETConfig,
|
||||
CERTChainVerifyCallback* checkChainCallback = nullptr);
|
||||
|
||||
virtual SECStatus FindPotentialIssuers(
|
||||
const SECItem* encodedIssuerName,
|
||||
PRTime time,
|
||||
/*out*/ mozilla::pkix::ScopedCERTCertList& results);
|
||||
virtual SECStatus FindIssuer(const SECItem& encodedIssuerName,
|
||||
IssuerChecker& checker, PRTime time);
|
||||
|
||||
virtual SECStatus GetCertTrust(mozilla::pkix::EndEntityOrCA endEntityOrCA,
|
||||
const mozilla::pkix::CertPolicyId& policy,
|
||||
|
@ -142,17 +142,62 @@ public:
|
||||
const SECItem& candidateCertDER,
|
||||
/*out*/ TrustLevel* trustLevel) = 0;
|
||||
|
||||
// Find all certificates (intermediate and/or root) in the certificate
|
||||
// database that have a subject name matching |encodedIssuerName| at
|
||||
// the given time. Certificates where the given time is not within the
|
||||
// certificate's validity period may be excluded. On input, |results|
|
||||
// will be null on input. If no potential issuers are found, then this
|
||||
// function should return SECSuccess with results being either null or
|
||||
// an empty list. Otherwise, this function should construct a
|
||||
// CERTCertList and return it in |results|, transfering ownership.
|
||||
virtual SECStatus FindPotentialIssuers(const SECItem* encodedIssuerName,
|
||||
PRTime time,
|
||||
/*out*/ ScopedCERTCertList& results) = 0;
|
||||
class IssuerChecker
|
||||
{
|
||||
public:
|
||||
virtual SECStatus Check(const SECItem& potentialIssuerDER,
|
||||
/*out*/ bool& keepGoing) = 0;
|
||||
protected:
|
||||
IssuerChecker();
|
||||
virtual ~IssuerChecker();
|
||||
private:
|
||||
IssuerChecker(const IssuerChecker&) /*= delete*/;
|
||||
void operator=(const IssuerChecker&) /*= delete*/;
|
||||
};
|
||||
|
||||
// Search for a CA certificate with the given name. The implementation must
|
||||
// call checker.Check with the DER encoding of the potential issuer
|
||||
// certificate. The implementation must follow these rules:
|
||||
//
|
||||
// * The subject name of the certificate given to checker.Check must be equal
|
||||
// to encodedIssuerName.
|
||||
// * The implementation must be reentrant and must limit the amount of stack
|
||||
// space it uses; see the note on reentrancy and stack usage below.
|
||||
// * When checker.Check does not return SECSuccess then immediately return
|
||||
// SECFailure.
|
||||
// * When checker.Check returns SECSuccess and sets keepGoing = false, then
|
||||
// immediately return SECSuccess.
|
||||
// * When checker.Check returns SECSuccess and sets keepGoing = true, then
|
||||
// call checker.Check again with a different potential issuer certificate,
|
||||
// if any more are available.
|
||||
// * When no more potential issuer certificates are available, return
|
||||
// SECSuccess.
|
||||
// * Don't call checker.Check with the same potential issuer certificate more
|
||||
// than once in a given call of FindIssuer.
|
||||
// * The given time parameter may be used to filter out certificates that are
|
||||
// not valid at the given time, or it may be ignored.
|
||||
//
|
||||
// Note on reentrancy and stack usage: checker.Check will attempt to
|
||||
// recursively build a certificate path from the potential issuer it is given
|
||||
// to a trusted root, as determined by this TrustDomain. That means that
|
||||
// checker.Check may call any/all of the methods on this TrustDomain. In
|
||||
// particular, there will be call stacks that look like this:
|
||||
//
|
||||
// BuildCertChain
|
||||
// [...]
|
||||
// TrustDomain::FindIssuer
|
||||
// [...]
|
||||
// IssuerChecker::Check
|
||||
// [...]
|
||||
// TrustDomain::FindIssuer
|
||||
// [...]
|
||||
// IssuerChecker::Check
|
||||
// [...]
|
||||
//
|
||||
// checker.Check is responsible for limiting the recursion to a reasonable
|
||||
// limit.
|
||||
virtual SECStatus FindIssuer(const SECItem& encodedIssuerName,
|
||||
IssuerChecker& checker, PRTime time) = 0;
|
||||
|
||||
// Verify the given signature using the given public key.
|
||||
//
|
||||
|
@ -41,7 +41,12 @@ static Result BuildForward(TrustDomain& trustDomain,
|
||||
unsigned int subCACount,
|
||||
/*out*/ ScopedCERTCertList& results);
|
||||
|
||||
class PathBuildingStep
|
||||
TrustDomain::IssuerChecker::IssuerChecker() { }
|
||||
TrustDomain::IssuerChecker::~IssuerChecker() { }
|
||||
|
||||
// The implementation of TrustDomain::IssuerTracker is in a subclass only to
|
||||
// hide the implementation from external users.
|
||||
class PathBuildingStep : public TrustDomain::IssuerChecker
|
||||
{
|
||||
public:
|
||||
PathBuildingStep(TrustDomain& trustDomain, const BackCert& subject,
|
||||
@ -65,7 +70,7 @@ public:
|
||||
{
|
||||
}
|
||||
|
||||
SECStatus Build(const SECItem& potentialIssuerDER,
|
||||
SECStatus Check(const SECItem& potentialIssuerDER,
|
||||
/*out*/ bool& keepGoing);
|
||||
|
||||
Result CheckResult() const;
|
||||
@ -132,7 +137,7 @@ PathBuildingStep::CheckResult() const
|
||||
|
||||
// The code that executes in the inner loop of BuildForward
|
||||
SECStatus
|
||||
PathBuildingStep::Build(const SECItem& potentialIssuerDER,
|
||||
PathBuildingStep::Check(const SECItem& potentialIssuerDER,
|
||||
/*out*/ bool& keepGoing)
|
||||
{
|
||||
BackCert potentialIssuer(potentialIssuerDER, &subject,
|
||||
@ -191,7 +196,7 @@ PathBuildingStep::Build(const SECItem& potentialIssuerDER,
|
||||
return RecordResult(PR_GetError(), keepGoing);
|
||||
}
|
||||
|
||||
return RecordResult(0, keepGoing);
|
||||
return RecordResult(0/*PRErrorCode::success*/, keepGoing);
|
||||
}
|
||||
|
||||
// Recursively build the path from the given subject certificate to the root.
|
||||
@ -281,25 +286,10 @@ BuildForward(TrustDomain& trustDomain,
|
||||
stapledOCSPResponse, subCACount, results);
|
||||
|
||||
// TODO(bug 965136): Add SKI/AKI matching optimizations
|
||||
ScopedCERTCertList candidates;
|
||||
if (trustDomain.FindPotentialIssuers(&subject.GetIssuer(), time,
|
||||
candidates) != SECSuccess) {
|
||||
if (trustDomain.FindIssuer(subject.GetIssuer(), pathBuilder, time)
|
||||
!= SECSuccess) {
|
||||
return MapSECStatus(SECFailure);
|
||||
}
|
||||
if (!candidates) {
|
||||
return Fail(RecoverableError, SEC_ERROR_UNKNOWN_ISSUER);
|
||||
}
|
||||
for (CERTCertListNode* n = CERT_LIST_HEAD(candidates);
|
||||
!CERT_LIST_END(n, candidates); n = CERT_LIST_NEXT(n)) {
|
||||
bool keepGoing;
|
||||
SECStatus srv = pathBuilder.Build(n->cert->derCert, keepGoing);
|
||||
if (srv != SECSuccess) {
|
||||
return MapSECStatus(SECFailure);
|
||||
}
|
||||
if (!keepGoing) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
rv = pathBuilder.CheckResult();
|
||||
if (rv != Success) {
|
||||
|
@ -126,12 +126,26 @@ private:
|
||||
return SECSuccess;
|
||||
}
|
||||
|
||||
SECStatus FindPotentialIssuers(const SECItem* encodedIssuerName,
|
||||
PRTime time,
|
||||
/*out*/ ScopedCERTCertList& results)
|
||||
SECStatus FindIssuer(const SECItem& encodedIssuerName,
|
||||
IssuerChecker& checker, PRTime time)
|
||||
{
|
||||
results = CERT_CreateSubjectCertList(nullptr, CERT_GetDefaultCertDB(),
|
||||
encodedIssuerName, time, true);
|
||||
mozilla::pkix::ScopedCERTCertList
|
||||
candidates(CERT_CreateSubjectCertList(nullptr, CERT_GetDefaultCertDB(),
|
||||
&encodedIssuerName, time, true));
|
||||
if (candidates) {
|
||||
for (CERTCertListNode* n = CERT_LIST_HEAD(candidates);
|
||||
!CERT_LIST_END(n, candidates); n = CERT_LIST_NEXT(n)) {
|
||||
bool keepGoing;
|
||||
SECStatus srv = checker.Check(n->cert->derCert, keepGoing);
|
||||
if (srv != SECSuccess) {
|
||||
return SECFailure;
|
||||
}
|
||||
if (!keepGoing) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return SECSuccess;
|
||||
}
|
||||
|
||||
|
@ -81,11 +81,12 @@ private:
|
||||
return SECSuccess;
|
||||
}
|
||||
|
||||
SECStatus FindPotentialIssuers(const SECItem* encodedIssuerName,
|
||||
PRTime time,
|
||||
/*out*/ ScopedCERTCertList& results)
|
||||
SECStatus FindIssuer(const SECItem& /*encodedIssuerName*/,
|
||||
IssuerChecker& /*checker*/, PRTime /*time*/)
|
||||
{
|
||||
return SECSuccess;
|
||||
PR_NOT_REACHED("FindIssuer should not be called");
|
||||
PR_SetError(SEC_ERROR_LIBRARY_FAILURE, 0);
|
||||
return SECFailure;
|
||||
}
|
||||
|
||||
SECStatus VerifySignedData(const CERTSignedData& signedData,
|
||||
|
Loading…
Reference in New Issue
Block a user