// The code that executes in the inner loop of BuildForward static Result BuildForwardInner(TrustDomain& trustDomain, BackCert& subject, PRTime time, KeyPurposeId requiredEKUIfPresent, const CertPolicyId& requiredPolicy, const SECItem& potentialIssuerDER, unsigned int subCACount, ScopedCERTCertList& results) { BackCert potentialIssuer(&subject, BackCert::IncludeCN::No); Result rv = potentialIssuer.Init(potentialIssuerDER); if (rv != Success) { return rv; } // RFC5280 4.2.1.1. Authority Key Identifier // RFC5280 4.2.1.2. Subject Key Identifier // Loop prevention, done as recommended by RFC4158 Section 5.2 // TODO: this doesn't account for subjectAltNames! // TODO(perf): This probably can and should be optimized in some way. bool loopDetected = false; for (BackCert* prev = potentialIssuer.childCert; !loopDetected && prev != nullptr; prev = prev->childCert) { if (SECITEM_ItemsAreEqual(&potentialIssuer.GetSubjectPublicKeyInfo(), &prev->GetSubjectPublicKeyInfo()) && SECITEM_ItemsAreEqual(&potentialIssuer.GetSubject(), &prev->GetSubject())) { return Fail(RecoverableError, SEC_ERROR_UNKNOWN_ISSUER); // XXX: error code } } rv = CheckNameConstraints(potentialIssuer); if (rv != Success) { return rv; } rv = BuildForward(trustDomain, potentialIssuer, time, EndEntityOrCA::MustBeCA, KU_KEY_CERT_SIGN, requiredEKUIfPresent, requiredPolicy, nullptr, subCACount, results); if (rv != Success) { return rv; } return subject.VerifyOwnSignatureWithKey( trustDomain, potentialIssuer.GetSubjectPublicKeyInfo()); }
// The code that executes in the inner loop of BuildForward Result PathBuildingStep::Check(Input potentialIssuerDER, /*optional*/ const Input* additionalNameConstraints, /*out*/ bool& keepGoing) { BackCert potentialIssuer(potentialIssuerDER, EndEntityOrCA::MustBeCA, &subject); Result rv = potentialIssuer.Init(); if (rv != Success) { return RecordResult(rv, keepGoing); } // RFC5280 4.2.1.1. Authority Key Identifier // RFC5280 4.2.1.2. Subject Key Identifier // Loop prevention, done as recommended by RFC4158 Section 5.2 // TODO: this doesn't account for subjectAltNames! // TODO(perf): This probably can and should be optimized in some way. bool loopDetected = false; for (const BackCert* prev = potentialIssuer.childCert; !loopDetected && prev != nullptr; prev = prev->childCert) { if (InputsAreEqual(potentialIssuer.GetSubjectPublicKeyInfo(), prev->GetSubjectPublicKeyInfo()) && InputsAreEqual(potentialIssuer.GetSubject(), prev->GetSubject())) { // XXX: error code return RecordResult(Result::ERROR_UNKNOWN_ISSUER, keepGoing); } } if (potentialIssuer.GetNameConstraints()) { rv = CheckNameConstraints(*potentialIssuer.GetNameConstraints(), subject, requiredEKUIfPresent); if (rv != Success) { return RecordResult(rv, keepGoing); } } if (additionalNameConstraints) { rv = CheckNameConstraints(*additionalNameConstraints, subject, requiredEKUIfPresent); if (rv != Success) { return RecordResult(rv, keepGoing); } } // RFC 5280, Section 4.2.1.3: "If the keyUsage extension is present, then the // subject public key MUST NOT be used to verify signatures on certificates // or CRLs unless the corresponding keyCertSign or cRLSign bit is set." rv = BuildForward(trustDomain, potentialIssuer, time, KeyUsage::keyCertSign, requiredEKUIfPresent, requiredPolicy, nullptr, subCACount); if (rv != Success) { return RecordResult(rv, keepGoing); } rv = trustDomain.VerifySignedData(subject.GetSignedData(), potentialIssuer.GetSubjectPublicKeyInfo()); if (rv != Success) { return RecordResult(rv, keepGoing); } CertID certID(subject.GetIssuer(), potentialIssuer.GetSubjectPublicKeyInfo(), subject.GetSerialNumber()); rv = trustDomain.CheckRevocation(subject.endEntityOrCA, certID, time, stapledOCSPResponse, subject.GetAuthorityInfoAccess()); if (rv != Success) { return RecordResult(rv, keepGoing); } return RecordResult(Success, keepGoing); }
// The code that executes in the inner loop of BuildForward static Result BuildForwardInner(TrustDomain& trustDomain, BackCert& subject, PRTime time, EndEntityOrCA endEntityOrCA, SECOidTag requiredEKUIfPresent, SECOidTag requiredPolicy, CERTCertificate* potentialIssuerCertToDup, /*optional*/ const SECItem* stapledOCSPResponse, unsigned int subCACount, ScopedCERTCertList& results) { PORT_Assert(potentialIssuerCertToDup); BackCert potentialIssuer(potentialIssuerCertToDup, &subject, BackCert::ExcludeCN); Result rv = potentialIssuer.Init(); if (rv != Success) { return rv; } // RFC5280 4.2.1.1. Authority Key Identifier // RFC5280 4.2.1.2. Subject Key Identifier // Loop prevention, done as recommended by RFC4158 Section 5.2 // TODO: this doesn't account for subjectAltNames! // TODO(perf): This probably can and should be optimized in some way. bool loopDetected = false; for (BackCert* prev = potentialIssuer.childCert; !loopDetected && prev != nullptr; prev = prev->childCert) { if (SECITEM_ItemsAreEqual(&potentialIssuer.GetNSSCert()->derPublicKey, &prev->GetNSSCert()->derPublicKey) && SECITEM_ItemsAreEqual(&potentialIssuer.GetNSSCert()->derSubject, &prev->GetNSSCert()->derSubject)) { return Fail(RecoverableError, SEC_ERROR_UNKNOWN_ISSUER); // XXX: error code } } rv = CheckNameConstraints(potentialIssuer); if (rv != Success) { return rv; } unsigned int newSubCACount = subCACount; if (endEntityOrCA == MustBeCA) { newSubCACount = subCACount + 1; } else { PR_ASSERT(newSubCACount == 0); } rv = BuildForward(trustDomain, potentialIssuer, time, MustBeCA, KU_KEY_CERT_SIGN, requiredEKUIfPresent, requiredPolicy, nullptr, newSubCACount, results); if (rv != Success) { return rv; } if (trustDomain.VerifySignedData(&subject.GetNSSCert()->signatureWrap, potentialIssuer.GetNSSCert()) != SECSuccess) { return MapSECStatus(SECFailure); } return Success; }