// BasicOCSPResponse ::= SEQUENCE { // tbsResponseData ResponseData, // signatureAlgorithm AlgorithmIdentifier, // signature BIT STRING, // certs [0] EXPLICIT SEQUENCE OF Certificate OPTIONAL } Result BasicResponse(Reader& input, Context& context) { Reader tbsResponseData; SignedDataWithSignature signedData; Result rv = der::SignedData(input, tbsResponseData, signedData); if (rv != Success) { if (rv == Result::ERROR_BAD_SIGNATURE) { return Result::ERROR_OCSP_BAD_SIGNATURE; } return rv; } // Parse certificates, if any NonOwningDERArray certs; if (!input.AtEnd()) { // We ignore the lengths of the wrappers because we'll detect bad lengths // during parsing--too short and we'll run out of input for parsing a cert, // and too long and we'll have leftover data that won't parse as a cert. // [0] wrapper Reader wrapped; rv = der::ExpectTagAndGetValue( input, der::CONTEXT_SPECIFIC | der::CONSTRUCTED | 0, wrapped); if (rv != Success) { return rv; } rv = der::End(input); if (rv != Success) { return rv; } // SEQUENCE wrapper Reader certsSequence; rv = der::ExpectTagAndGetValue(wrapped, der::SEQUENCE, certsSequence); if (rv != Success) { return rv; } rv = der::End(wrapped); if (rv != Success) { return rv; } // sequence of certificates while (!certsSequence.AtEnd()) { Input cert; rv = der::ExpectTagAndGetTLV(certsSequence, der::SEQUENCE, cert); if (rv != Success) { return rv; } rv = certs.Append(cert); if (rv != Success) { return rv; } } } return ResponseData(tbsResponseData, context, signedData, certs); }
// Recursively build the path from the given subject certificate to the root. // // Be very careful about changing the order of checks. The order is significant // because it affects which error we return when a certificate or certificate // chain has multiple problems. See the error ranking documentation in // pkix/pkix.h. static Result BuildForward(TrustDomain& trustDomain, const BackCert& subject, Time time, KeyUsage requiredKeyUsageIfPresent, KeyPurposeId requiredEKUIfPresent, const CertPolicyId& requiredPolicy, /*optional*/ const Input* stapledOCSPResponse, unsigned int subCACount) { Result rv; TrustLevel trustLevel; // If this is an end-entity and not a trust anchor, we defer reporting // any error found here until after attempting to find a valid chain. // See the explanation of error prioritization in pkix.h. rv = CheckIssuerIndependentProperties(trustDomain, subject, time, requiredKeyUsageIfPresent, requiredEKUIfPresent, requiredPolicy, subCACount, trustLevel); Result deferredEndEntityError = Success; if (rv != Success) { if (subject.endEntityOrCA == EndEntityOrCA::MustBeEndEntity && trustLevel != TrustLevel::TrustAnchor) { deferredEndEntityError = rv; } else { return rv; } } if (trustLevel == TrustLevel::TrustAnchor) { // End of the recursion. NonOwningDERArray chain; for (const BackCert* cert = &subject; cert; cert = cert->childCert) { 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); } 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, "MAX_SUBCA_COUNT and NonOwningDERArray::MAX_LENGTH mismatch."); if (subCACount >= MAX_SUBCA_COUNT) { return Result::ERROR_UNKNOWN_ISSUER; } ++subCACount; } else { assert(subCACount == 0); } // Find a trusted issuer. PathBuildingStep pathBuilder(trustDomain, subject, time, requiredEKUIfPresent, requiredPolicy, stapledOCSPResponse, subCACount); // TODO(bug 965136): Add SKI/AKI matching optimizations rv = trustDomain.FindIssuer(subject.GetIssuer(), pathBuilder, time); if (rv != Success) { return rv; } rv = pathBuilder.CheckResult(); if (rv != Success) { return rv; } // If we found a valid chain but deferred reporting an error with the // end-entity certificate, report it now. if (deferredEndEntityError != Success) { return deferredEndEntityError; } // We've built a valid chain from the subject cert up to a trusted root. return Success; }