// Copyright 2016 The Chromium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "ocsp.h" #include <openssl/bytestring.h> #include <openssl/digest.h> #include <openssl/mem.h> #include <openssl/pool.h> #include <openssl/sha.h> #include "cert_errors.h" #include "extended_key_usage.h" #include "parsed_certificate.h" #include "revocation_util.h" #include "string_util.h" #include "verify_name_match.h" #include "verify_signed_data.h" BSSL_NAMESPACE_BEGIN OCSPCertID::OCSPCertID() = default; OCSPCertID::~OCSPCertID() = default; OCSPSingleResponse::OCSPSingleResponse() = default; OCSPSingleResponse::~OCSPSingleResponse() = default; OCSPResponseData::OCSPResponseData() = default; OCSPResponseData::~OCSPResponseData() = default; OCSPResponse::OCSPResponse() = default; OCSPResponse::~OCSPResponse() = default; // CertID ::= SEQUENCE { // hashAlgorithm AlgorithmIdentifier, // issuerNameHash OCTET STRING, -- Hash of issuer's DN // issuerKeyHash OCTET STRING, -- Hash of issuer's public key // serialNumber CertificateSerialNumber // } bool ParseOCSPCertID(der::Input raw_tlv, OCSPCertID *out) { … } namespace { // Parses |raw_tlv| to extract an OCSP RevokedInfo (RFC 6960) and stores the // result in the OCSPCertStatus |out|. Returns whether the parsing was // successful. // // RevokedInfo ::= SEQUENCE { // revocationTime GeneralizedTime, // revocationReason [0] EXPLICIT CRLReason OPTIONAL // } bool ParseRevokedInfo(der::Input raw_tlv, OCSPCertStatus *out) { … } // Parses |raw_tlv| to extract an OCSP CertStatus (RFC 6960) and stores the // result in the OCSPCertStatus |out|. Returns whether the parsing was // successful. // // CertStatus ::= CHOICE { // good [0] IMPLICIT NULL, // revoked [1] IMPLICIT RevokedInfo, // unknown [2] IMPLICIT UnknownInfo // } // // UnknownInfo ::= NULL bool ParseCertStatus(der::Input raw_tlv, OCSPCertStatus *out) { … } // Writes the hash of |value| as an OCTET STRING to |cbb|, using |hash_type| as // the algorithm. Returns true on success. bool AppendHashAsOctetString(const EVP_MD *hash_type, CBB *cbb, der::Input value) { … } } // namespace // SingleResponse ::= SEQUENCE { // certID CertID, // certStatus CertStatus, // thisUpdate GeneralizedTime, // nextUpdate [0] EXPLICIT GeneralizedTime OPTIONAL, // singleExtensions [1] EXPLICIT Extensions OPTIONAL // } bool ParseOCSPSingleResponse(der::Input raw_tlv, OCSPSingleResponse *out) { … } namespace { // Parses |raw_tlv| to extract a ResponderID (RFC 6960) and stores the // result in the ResponderID |out|. Returns whether the parsing was successful. // // ResponderID ::= CHOICE { // byName [1] Name, // byKey [2] KeyHash // } bool ParseResponderID(der::Input raw_tlv, OCSPResponseData::ResponderID *out) { … } } // namespace // ResponseData ::= SEQUENCE { // version [0] EXPLICIT Version DEFAULT v1, // responderID ResponderID, // producedAt GeneralizedTime, // responses SEQUENCE OF SingleResponse, // responseExtensions [1] EXPLICIT Extensions OPTIONAL // } bool ParseOCSPResponseData(der::Input raw_tlv, OCSPResponseData *out) { … } namespace { // Parses |raw_tlv| to extract a BasicOCSPResponse (RFC 6960) and stores the // result in the OCSPResponse |out|. Returns whether the parsing was // successful. // // BasicOCSPResponse ::= SEQUENCE { // tbsResponseData ResponseData, // signatureAlgorithm AlgorithmIdentifier, // signature BIT STRING, // certs [0] EXPLICIT SEQUENCE OF Certificate OPTIONAL // } bool ParseBasicOCSPResponse(der::Input raw_tlv, OCSPResponse *out) { … } } // namespace // OCSPResponse ::= SEQUENCE { // responseStatus OCSPResponseStatus, // responseBytes [0] EXPLICIT ResponseBytes OPTIONAL // } // // ResponseBytes ::= SEQUENCE { // responseType OBJECT IDENTIFIER, // response OCTET STRING // } bool ParseOCSPResponse(der::Input raw_tlv, OCSPResponse *out) { … } namespace { // Checks that the |type| hash of |value| is equal to |hash| bool VerifyHash(const EVP_MD *type, der::Input hash, der::Input value) { … } // Extracts the bytes of the SubjectPublicKey bit string given an SPKI. That is // to say, the value of subjectPublicKey without the leading unused bit // count octet. // // Returns true on success and fills |*spk_tlv| with the result. // // From RFC 5280, Section 4.1 // SubjectPublicKeyInfo ::= SEQUENCE { // algorithm AlgorithmIdentifier, // subjectPublicKey BIT STRING } // // AlgorithmIdentifier ::= SEQUENCE { // algorithm OBJECT IDENTIFIER, // parameters ANY DEFINED BY algorithm OPTIONAL } // bool GetSubjectPublicKeyBytes(der::Input spki_tlv, der::Input *spk_tlv) { … } // Checks the OCSPCertID |id| identifies |certificate|. bool CheckCertIDMatchesCertificate( const OCSPCertID &id, const ParsedCertificate *certificate, const ParsedCertificate *issuer_certificate) { … } // TODO(eroman): Revisit how certificate parsing is used by this file. Ideally // would either pass in the parsed bits, or have a better abstraction for lazily // parsing. std::shared_ptr<const ParsedCertificate> OCSPParseCertificate( std::string_view der) { … } // Checks that the ResponderID |id| matches the certificate |cert| either // by verifying the name matches that of the certificate or that the hash // matches the certificate's public key hash (RFC 6960, 4.2.2.3). [[nodiscard]] bool CheckResponderIDMatchesCertificate( const OCSPResponseData::ResponderID &id, const ParsedCertificate *cert) { … } // Verifies that |responder_certificate| has been authority for OCSP signing, // delegated to it by |issuer_certificate|. // // TODO(eroman): No revocation checks are done (see id-pkix-ocsp-nocheck in the // spec). extension). // // TODO(eroman): Not all properties of the certificate are verified, only the // signature and EKU. Can full RFC 5280 validation be used, or are there // compatibility concerns? [[nodiscard]] bool VerifyAuthorizedResponderCert( const ParsedCertificate *responder_certificate, const ParsedCertificate *issuer_certificate) { … } [[nodiscard]] bool VerifyOCSPResponseSignatureGivenCert( const OCSPResponse &response, const ParsedCertificate *cert) { … } // Verifies that the OCSP response has a valid signature using // |issuer_certificate|, or an authorized responder issued by // |issuer_certificate| for OCSP signing. [[nodiscard]] bool VerifyOCSPResponseSignature( const OCSPResponse &response, const OCSPResponseData &response_data, const ParsedCertificate *issuer_certificate) { … } // Parse ResponseData and return false if any unhandled critical extensions are // found. No known critical ResponseData extensions exist. bool ParseOCSPResponseDataExtensions( der::Input response_extensions, OCSPVerifyResult::ResponseStatus *response_details) { … } // Parse SingleResponse and return false if any unhandled critical extensions // (other than the CT extension) are found. The CT-SCT extension is not required // to be marked critical, but since it is handled by Chrome, we will overlook // the flag setting. bool ParseOCSPSingleResponseExtensions( der::Input single_extensions, OCSPVerifyResult::ResponseStatus *response_details) { … } // Loops through the OCSPSingleResponses to find the best match for |cert|. OCSPRevocationStatus GetRevocationStatusForCert( const OCSPResponseData &response_data, const ParsedCertificate *cert, const ParsedCertificate *issuer_certificate, int64_t verify_time_epoch_seconds, std::optional<int64_t> max_age_seconds, OCSPVerifyResult::ResponseStatus *response_details) { … } OCSPRevocationStatus CheckOCSP( std::string_view raw_response, std::string_view certificate_der, const ParsedCertificate *certificate, std::string_view issuer_certificate_der, const ParsedCertificate *issuer_certificate, int64_t verify_time_epoch_seconds, std::optional<int64_t> max_age_seconds, OCSPVerifyResult::ResponseStatus *response_details) { … } } // namespace OCSPRevocationStatus CheckOCSP( std::string_view raw_response, std::string_view certificate_der, std::string_view issuer_certificate_der, int64_t verify_time_epoch_seconds, std::optional<int64_t> max_age_seconds, OCSPVerifyResult::ResponseStatus *response_details) { … } OCSPRevocationStatus CheckOCSP( std::string_view raw_response, const ParsedCertificate *certificate, const ParsedCertificate *issuer_certificate, int64_t verify_time_epoch_seconds, std::optional<int64_t> max_age_seconds, OCSPVerifyResult::ResponseStatus *response_details) { … } bool CreateOCSPRequest(const ParsedCertificate *cert, const ParsedCertificate *issuer, std::vector<uint8_t> *request_der) { … } // From RFC 2560 section A.1.1: // // An OCSP request using the GET method is constructed as follows: // // GET {url}/{url-encoding of base-64 encoding of the DER encoding of // the OCSPRequest} std::optional<std::string> CreateOCSPGetURL( const ParsedCertificate *cert, const ParsedCertificate *issuer, std::string_view ocsp_responder_url) { … } BSSL_NAMESPACE_END