| Index: net/cert/ct_objects_extractor.cc
|
| diff --git a/net/cert/ct_objects_extractor.cc b/net/cert/ct_objects_extractor.cc
|
| index 7c9eb719ee7dde3f84af837b106a8623bb06c2ff..25c8219fb5e04a587ff378c18536b26abbfce2ea 100644
|
| --- a/net/cert/ct_objects_extractor.cc
|
| +++ b/net/cert/ct_objects_extractor.cc
|
| @@ -13,8 +13,7 @@
|
| #include "net/cert/asn1_util.h"
|
| #include "net/cert/signed_certificate_timestamp.h"
|
| #include "third_party/boringssl/src/include/openssl/bytestring.h"
|
| -#include "third_party/boringssl/src/include/openssl/obj.h"
|
| -#include "third_party/boringssl/src/include/openssl/x509.h"
|
| +#include "third_party/boringssl/src/include/openssl/mem.h"
|
|
|
| namespace net {
|
|
|
| @@ -33,52 +32,141 @@ const uint8_t kEmbeddedSCTOid[] = {0x2B, 0x06, 0x01, 0x04, 0x01,
|
| const uint8_t kOCSPExtensionOid[] = {0x2B, 0x06, 0x01, 0x04, 0x01,
|
| 0xD6, 0x79, 0x02, 0x04, 0x05};
|
|
|
| +// The wire form of the OID 1.3.6.1.5.5.7.48.1.1. See RFC 6960.
|
| +const uint8_t kOCSPBasicResponseOid[] = {0x2b, 0x06, 0x01, 0x05, 0x05,
|
| + 0x07, 0x30, 0x01, 0x01};
|
| +
|
| +// The wire form of the OID 1.3.14.3.2.26.
|
| +const uint8_t kSHA1Oid[] = {0x2b, 0x0e, 0x03, 0x02, 0x1a};
|
| +
|
| +// The wire form of the OID 2.16.840.1.101.3.4.2.1.
|
| +const uint8_t kSHA256Oid[] = {0x60, 0x86, 0x48, 0x01, 0x65,
|
| + 0x03, 0x04, 0x02, 0x01};
|
| +
|
| bool StringEqualToCBS(const std::string& value1, const CBS* value2) {
|
| if (CBS_len(value2) != value1.size())
|
| return false;
|
| return memcmp(value1.data(), CBS_data(value2), CBS_len(value2)) == 0;
|
| }
|
|
|
| -bssl::UniquePtr<X509> OSCertHandleToOpenSSL(
|
| - X509Certificate::OSCertHandle os_handle) {
|
| -#if defined(USE_OPENSSL_CERTS)
|
| - return bssl::UniquePtr<X509>(X509Certificate::DupOSCertHandle(os_handle));
|
| -#else
|
| - std::string der_encoded;
|
| - if (!X509Certificate::GetDEREncoded(os_handle, &der_encoded))
|
| - return bssl::UniquePtr<X509>();
|
| - const uint8_t* bytes = reinterpret_cast<const uint8_t*>(der_encoded.data());
|
| - return bssl::UniquePtr<X509>(d2i_X509(NULL, &bytes, der_encoded.size()));
|
| -#endif
|
| +bool SkipElements(CBS* cbs, int count) {
|
| + for (int i = 0; i < count; i++) {
|
| + if (!CBS_get_any_asn1_element(cbs, nullptr, nullptr, nullptr))
|
| + return false;
|
| + }
|
| + return true;
|
| }
|
|
|
| -// Finds the SignedCertificateTimestampList in an extension with OID |oid| in
|
| -// |x509_exts|. If found, returns true and sets |*out_sct_list| to the encoded
|
| -// SCT list. |out_sct_list| may be NULL.
|
| -bool GetSCTListFromX509_EXTENSIONS(const X509_EXTENSIONS* x509_exts,
|
| - const uint8_t* oid,
|
| - size_t oid_len,
|
| - std::string* out_sct_list) {
|
| - for (size_t i = 0; i < sk_X509_EXTENSION_num(x509_exts); i++) {
|
| - X509_EXTENSION* x509_ext = sk_X509_EXTENSION_value(x509_exts, i);
|
| - if (static_cast<size_t>(x509_ext->object->length) == oid_len &&
|
| - memcmp(x509_ext->object->data, oid, oid_len) == 0) {
|
| - // The SCT list is an OCTET STRING inside the extension.
|
| - CBS ext_value, sct_list;
|
| - CBS_init(&ext_value, x509_ext->value->data, x509_ext->value->length);
|
| - if (!CBS_get_asn1(&ext_value, &sct_list, CBS_ASN1_OCTETSTRING) ||
|
| - CBS_len(&ext_value) != 0) {
|
| +bool SkipOptionalElement(CBS* cbs, unsigned tag) {
|
| + CBS unused;
|
| + return !CBS_peek_asn1_tag(cbs, tag) || CBS_get_asn1(cbs, &unused, tag);
|
| +}
|
| +
|
| +// Copies all the bytes in |outer| which are before |inner| to |out|. |inner|
|
| +// must be a subset of |outer|.
|
| +bool CopyBefore(const CBS& outer, const CBS& inner, CBB* out) {
|
| + CHECK_LE(CBS_data(&outer), CBS_data(&inner));
|
| + CHECK_LE(CBS_data(&inner) + CBS_len(&inner),
|
| + CBS_data(&outer) + CBS_len(&outer));
|
| +
|
| + return !!CBB_add_bytes(out, CBS_data(&outer),
|
| + CBS_data(&inner) - CBS_data(&outer));
|
| +}
|
| +
|
| +// Copies all the bytes in |outer| which are after |inner| to |out|. |inner|
|
| +// must be a subset of |outer|.
|
| +bool CopyAfter(const CBS& outer, const CBS& inner, CBB* out) {
|
| + CHECK_LE(CBS_data(&outer), CBS_data(&inner));
|
| + CHECK_LE(CBS_data(&inner) + CBS_len(&inner),
|
| + CBS_data(&outer) + CBS_len(&outer));
|
| +
|
| + return !!CBB_add_bytes(
|
| + out, CBS_data(&inner) + CBS_len(&inner),
|
| + CBS_data(&outer) + CBS_len(&outer) - CBS_data(&inner) - CBS_len(&inner));
|
| +}
|
| +
|
| +// Skips |tbs_cert|, which must be a TBSCertificate body, to just before the
|
| +// extensions element.
|
| +bool SkipTBSCertificateToExtensions(CBS* tbs_cert) {
|
| + constexpr unsigned kVersionTag =
|
| + CBS_ASN1_CONTEXT_SPECIFIC | CBS_ASN1_CONSTRUCTED | 0;
|
| + constexpr unsigned kIssuerUniqueIDTag =
|
| + CBS_ASN1_CONTEXT_SPECIFIC | CBS_ASN1_CONSTRUCTED | 1;
|
| + constexpr unsigned kSubjectUniqueIDTag =
|
| + CBS_ASN1_CONTEXT_SPECIFIC | CBS_ASN1_CONSTRUCTED | 2;
|
| + return SkipOptionalElement(tbs_cert, kVersionTag) &&
|
| + SkipElements(tbs_cert,
|
| + 6 /* serialNumber through subjectPublicKeyInfo */) &&
|
| + SkipOptionalElement(tbs_cert, kIssuerUniqueIDTag) &&
|
| + SkipOptionalElement(tbs_cert, kSubjectUniqueIDTag);
|
| +}
|
| +
|
| +// Looks for the extension with the specified OID in |extensions|, which must
|
| +// contain the contents of a SEQUENCE of X.509 extension structures. If found,
|
| +// returns true and sets |*out| to the full extension element.
|
| +bool FindExtensionElement(const CBS& extensions,
|
| + const uint8_t* oid,
|
| + size_t oid_len,
|
| + CBS* out) {
|
| + CBS extensions_copy = extensions;
|
| + CBS result;
|
| + CBS_init(&result, nullptr, 0);
|
| + bool found = false;
|
| + while (CBS_len(&extensions_copy) > 0) {
|
| + CBS extension_element;
|
| + if (!CBS_get_asn1_element(&extensions_copy, &extension_element,
|
| + CBS_ASN1_SEQUENCE)) {
|
| + return false;
|
| + }
|
| +
|
| + CBS copy = extension_element;
|
| + CBS extension, extension_oid;
|
| + if (!CBS_get_asn1(©, &extension, CBS_ASN1_SEQUENCE) ||
|
| + !CBS_get_asn1(&extension, &extension_oid, CBS_ASN1_OBJECT)) {
|
| + return false;
|
| + }
|
| +
|
| + if (CBS_mem_equal(&extension_oid, oid, oid_len)) {
|
| + if (found)
|
| return false;
|
| - }
|
| - if (out_sct_list) {
|
| - *out_sct_list =
|
| - std::string(reinterpret_cast<const char*>(CBS_data(&sct_list)),
|
| - CBS_len(&sct_list));
|
| - }
|
| - return true;
|
| + found = true;
|
| + result = extension_element;
|
| }
|
| }
|
| - return false;
|
| + if (!found)
|
| + return false;
|
| +
|
| + *out = result;
|
| + return true;
|
| +}
|
| +
|
| +// Finds the SignedCertificateTimestampList in an extension with OID |oid| in
|
| +// |x509_exts|. If found, returns true and sets |*out_sct_list| to the encoded
|
| +// SCT list.
|
| +bool ParseSCTListFromExtensions(const CBS& extensions,
|
| + const uint8_t* oid,
|
| + size_t oid_len,
|
| + std::string* out_sct_list) {
|
| + CBS extension_element, extension, extension_oid, value, sct_list;
|
| + if (!FindExtensionElement(extensions, oid, oid_len, &extension_element) ||
|
| + !CBS_get_asn1(&extension_element, &extension, CBS_ASN1_SEQUENCE) ||
|
| + !CBS_get_asn1(&extension, &extension_oid, CBS_ASN1_OBJECT) ||
|
| + // Skip the optional critical element.
|
| + !SkipOptionalElement(&extension, CBS_ASN1_BOOLEAN) ||
|
| + // The extension value is stored in an OCTET STRING.
|
| + !CBS_get_asn1(&extension, &value, CBS_ASN1_OCTETSTRING) ||
|
| + CBS_len(&extension) != 0 ||
|
| + // The extension value itself is an OCTET STRING containing the
|
| + // serialized SCT list.
|
| + !CBS_get_asn1(&value, &sct_list, CBS_ASN1_OCTETSTRING) ||
|
| + CBS_len(&value) != 0) {
|
| + return false;
|
| + }
|
| +
|
| + DCHECK(CBS_mem_equal(&extension_oid, oid, oid_len));
|
| + *out_sct_list = std::string(
|
| + reinterpret_cast<const char*>(CBS_data(&sct_list)), CBS_len(&sct_list));
|
| + return true;
|
| }
|
|
|
| // Finds the SingleResponse in |responses| which matches |issuer| and
|
| @@ -102,9 +190,9 @@ bool FindMatchingSingleResponse(CBS* responses,
|
| if (!asn1::ExtractSubjectPublicKeyFromSPKI(issuer_spki, &issuer_spk))
|
| return false;
|
|
|
| - // ExtractSubjectPublicKey... does not remove the initial octet encoding the
|
| - // number of unused bits in the ASN.1 BIT STRING so we do it here. For public
|
| - // keys, the bitstring is in practice always byte-aligned.
|
| + // ExtractSubjectPublicKeyFromSPKI does not remove the initial octet encoding
|
| + // the number of unused bits in the ASN.1 BIT STRING so we do it here. For
|
| + // public keys, the bitstring is in practice always byte-aligned.
|
| if (issuer_spk.empty() || issuer_spk[0] != 0)
|
| return false;
|
| issuer_spk.remove_prefix(1);
|
| @@ -139,19 +227,16 @@ bool FindMatchingSingleResponse(CBS* responses,
|
|
|
| // Check if the issuer_key_hash matches.
|
| // TODO(ekasper): also use the issuer name hash in matching.
|
| - switch (OBJ_cbs2nid(&hash)) {
|
| - case NID_sha1:
|
| - if (StringEqualToCBS(issuer_key_sha1_hash, &issuer_key_hash)) {
|
| - *out_single_response = single_response;
|
| - return true;
|
| - }
|
| - break;
|
| - case NID_sha256:
|
| - if (StringEqualToCBS(issuer_key_sha256_hash, &issuer_key_hash)) {
|
| - *out_single_response = single_response;
|
| - return true;
|
| - }
|
| - break;
|
| + if (CBS_mem_equal(&hash, kSHA1Oid, sizeof(kSHA1Oid))) {
|
| + if (StringEqualToCBS(issuer_key_sha1_hash, &issuer_key_hash)) {
|
| + *out_single_response = single_response;
|
| + return true;
|
| + }
|
| + } else if (CBS_mem_equal(&hash, kSHA256Oid, sizeof(kSHA256Oid))) {
|
| + if (StringEqualToCBS(issuer_key_sha256_hash, &issuer_key_hash)) {
|
| + *out_single_response = single_response;
|
| + return true;
|
| + }
|
| }
|
| }
|
|
|
| @@ -162,15 +247,26 @@ bool FindMatchingSingleResponse(CBS* responses,
|
|
|
| bool ExtractEmbeddedSCTList(X509Certificate::OSCertHandle cert,
|
| std::string* sct_list) {
|
| - bssl::UniquePtr<X509> x509(OSCertHandleToOpenSSL(cert));
|
| - if (!x509)
|
| + std::string der;
|
| + if (!X509Certificate::GetDEREncoded(cert, &der))
|
| return false;
|
| - X509_EXTENSIONS* x509_exts = x509->cert_info->extensions;
|
| - if (!x509_exts)
|
| + CBS cert_cbs;
|
| + CBS_init(&cert_cbs, reinterpret_cast<const uint8_t*>(der.data()), der.size());
|
| + CBS cert_body, tbs_cert, extensions_wrap, extensions;
|
| + if (!CBS_get_asn1(&cert_cbs, &cert_body, CBS_ASN1_SEQUENCE) ||
|
| + CBS_len(&cert_cbs) != 0 ||
|
| + !CBS_get_asn1(&cert_body, &tbs_cert, CBS_ASN1_SEQUENCE) ||
|
| + !SkipTBSCertificateToExtensions(&tbs_cert) ||
|
| + // Extract the extensions list.
|
| + !CBS_get_asn1(&tbs_cert, &extensions_wrap,
|
| + CBS_ASN1_CONTEXT_SPECIFIC | CBS_ASN1_CONSTRUCTED | 3) ||
|
| + !CBS_get_asn1(&extensions_wrap, &extensions, CBS_ASN1_SEQUENCE) ||
|
| + CBS_len(&extensions_wrap) != 0 || CBS_len(&tbs_cert) != 0) {
|
| return false;
|
| - return GetSCTListFromX509_EXTENSIONS(x509->cert_info->extensions,
|
| - kEmbeddedSCTOid, sizeof(kEmbeddedSCTOid),
|
| - sct_list);
|
| + }
|
| +
|
| + return ParseSCTListFromExtensions(extensions, kEmbeddedSCTOid,
|
| + sizeof(kEmbeddedSCTOid), sct_list);
|
| }
|
|
|
| bool GetPrecertSignedEntry(X509Certificate::OSCertHandle leaf,
|
| @@ -178,59 +274,79 @@ bool GetPrecertSignedEntry(X509Certificate::OSCertHandle leaf,
|
| SignedEntryData* result) {
|
| result->Reset();
|
|
|
| - bssl::UniquePtr<X509> leaf_x509(OSCertHandleToOpenSSL(leaf));
|
| - if (!leaf_x509)
|
| + std::string leaf_der;
|
| + if (!X509Certificate::GetDEREncoded(leaf, &leaf_der))
|
| return false;
|
|
|
| - // XXX(rsleevi): This check may be overkill, since we should be able to
|
| - // generate precerts for certs without the extension. For now, just a sanity
|
| - // check to match the reference implementation.
|
| - if (!leaf_x509->cert_info->extensions ||
|
| - !GetSCTListFromX509_EXTENSIONS(leaf_x509->cert_info->extensions,
|
| - kEmbeddedSCTOid, sizeof(kEmbeddedSCTOid),
|
| - NULL)) {
|
| + // Parse the TBSCertificate.
|
| + CBS cert_cbs;
|
| + CBS_init(&cert_cbs, reinterpret_cast<const uint8_t*>(leaf_der.data()),
|
| + leaf_der.size());
|
| + CBS cert_body, tbs_cert;
|
| + if (!CBS_get_asn1(&cert_cbs, &cert_body, CBS_ASN1_SEQUENCE) ||
|
| + CBS_len(&cert_cbs) != 0 ||
|
| + !CBS_get_asn1(&cert_body, &tbs_cert, CBS_ASN1_SEQUENCE)) {
|
| return false;
|
| }
|
|
|
| - // The Precertificate log entry is the final certificate's TBSCertificate
|
| - // without the SCT extension (RFC6962, section 3.2).
|
| - bssl::UniquePtr<X509> leaf_copy(X509_dup(leaf_x509.get()));
|
| - if (!leaf_copy || !leaf_copy->cert_info->extensions) {
|
| - NOTREACHED();
|
| + CBS tbs_cert_copy = tbs_cert;
|
| + if (!SkipTBSCertificateToExtensions(&tbs_cert))
|
| + return false;
|
| +
|
| + // Start filling in a new TBSCertificate. Copy everything parsed or skipped
|
| + // so far to the |new_tbs_cert|.
|
| + bssl::ScopedCBB cbb;
|
| + CBB new_tbs_cert;
|
| + if (!CBB_init(cbb.get(), CBS_len(&tbs_cert_copy)) ||
|
| + !CBB_add_asn1(cbb.get(), &new_tbs_cert, CBS_ASN1_SEQUENCE) ||
|
| + !CopyBefore(tbs_cert_copy, tbs_cert, &new_tbs_cert)) {
|
| return false;
|
| }
|
| - X509_EXTENSIONS* leaf_copy_exts = leaf_copy->cert_info->extensions;
|
| - for (size_t i = 0; i < sk_X509_EXTENSION_num(leaf_copy_exts); i++) {
|
| - X509_EXTENSION* ext = sk_X509_EXTENSION_value(leaf_copy_exts, i);
|
| - if (static_cast<size_t>(ext->object->length) == sizeof(kEmbeddedSCTOid) &&
|
| - memcmp(ext->object->data, kEmbeddedSCTOid, sizeof(kEmbeddedSCTOid)) ==
|
| - 0) {
|
| - X509_EXTENSION_free(sk_X509_EXTENSION_delete(leaf_copy_exts, i));
|
| - X509_CINF_set_modified(leaf_copy->cert_info);
|
| - break;
|
| - }
|
| +
|
| + // Parse the extensions list and find the SCT extension.
|
| + //
|
| + // XXX(rsleevi): We could generate precerts for certs without the extension
|
| + // by leaving the TBSCertificate as-is. The reference implementation does not
|
| + // do this.
|
| + constexpr unsigned kExtensionsTag =
|
| + CBS_ASN1_CONTEXT_SPECIFIC | CBS_ASN1_CONSTRUCTED | 3;
|
| + CBS extensions_wrap, extensions, sct_extension;
|
| + if (!CBS_get_asn1(&tbs_cert, &extensions_wrap, kExtensionsTag) ||
|
| + !CBS_get_asn1(&extensions_wrap, &extensions, CBS_ASN1_SEQUENCE) ||
|
| + CBS_len(&extensions_wrap) != 0 || CBS_len(&tbs_cert) != 0 ||
|
| + !FindExtensionElement(extensions, kEmbeddedSCTOid,
|
| + sizeof(kEmbeddedSCTOid), &sct_extension)) {
|
| + return false;
|
| }
|
|
|
| - std::string to_be_signed;
|
| - int len = i2d_X509_CINF(leaf_copy->cert_info, NULL);
|
| - if (len < 0)
|
| + // Add extensions to the TBSCertificate. Copy all extensions except the
|
| + // embedded SCT extension.
|
| + CBB new_extensions_wrap, new_extensions;
|
| + if (!CBB_add_asn1(&new_tbs_cert, &new_extensions_wrap, kExtensionsTag) ||
|
| + !CBB_add_asn1(&new_extensions_wrap, &new_extensions, CBS_ASN1_SEQUENCE) ||
|
| + !CopyBefore(extensions, sct_extension, &new_extensions) ||
|
| + !CopyAfter(extensions, sct_extension, &new_extensions)) {
|
| return false;
|
| - uint8_t* ptr =
|
| - reinterpret_cast<uint8_t*>(base::WriteInto(&to_be_signed, len + 1));
|
| - if (i2d_X509_CINF(leaf_copy->cert_info, &ptr) < 0)
|
| + }
|
| +
|
| + uint8_t* new_tbs_cert_der;
|
| + size_t new_tbs_cert_len;
|
| + if (!CBB_finish(cbb.get(), &new_tbs_cert_der, &new_tbs_cert_len))
|
| return false;
|
| + bssl::UniquePtr<uint8_t> scoped_new_tbs_cert_der(new_tbs_cert_der);
|
|
|
| // Extract the issuer's public key.
|
| std::string issuer_der;
|
| - if (!X509Certificate::GetDEREncoded(issuer, &issuer_der))
|
| - return false;
|
| base::StringPiece issuer_key;
|
| - if (!asn1::ExtractSPKIFromDERCert(issuer_der, &issuer_key))
|
| + if (!X509Certificate::GetDEREncoded(issuer, &issuer_der) ||
|
| + !asn1::ExtractSPKIFromDERCert(issuer_der, &issuer_key)) {
|
| return false;
|
| + }
|
|
|
| // Fill in the SignedEntryData.
|
| result->type = ct::SignedEntryData::LOG_ENTRY_TYPE_PRECERT;
|
| - result->tbs_certificate.swap(to_be_signed);
|
| + result->tbs_certificate.assign(
|
| + reinterpret_cast<const char*>(new_tbs_cert_der), new_tbs_cert_len);
|
| crypto::SHA256HashString(issuer_key, result->issuer_key_hash.data,
|
| sizeof(result->issuer_key_hash.data));
|
|
|
| @@ -264,10 +380,9 @@ bool ExtractSCTListFromOCSPResponse(X509Certificate::OSCertHandle issuer,
|
|
|
| // Parse down to the ResponseBytes. The ResponseBytes is optional, but if it's
|
| // missing, this can't include an SCT list.
|
| - CBS sequence, response_status, tagged_response_bytes, response_bytes;
|
| - CBS response_type, response;
|
| + CBS sequence, tagged_response_bytes, response_bytes, response_type, response;
|
| if (!CBS_get_asn1(&cbs, &sequence, CBS_ASN1_SEQUENCE) || CBS_len(&cbs) != 0 ||
|
| - !CBS_get_asn1(&sequence, &response_status, CBS_ASN1_ENUMERATED) ||
|
| + !SkipElements(&sequence, 1 /* responseStatus */) ||
|
| !CBS_get_asn1(&sequence, &tagged_response_bytes,
|
| CBS_ASN1_CONTEXT_SPECIFIC | CBS_ASN1_CONSTRUCTED | 0) ||
|
| CBS_len(&sequence) != 0 ||
|
| @@ -281,29 +396,24 @@ bool ExtractSCTListFromOCSPResponse(X509Certificate::OSCertHandle issuer,
|
| }
|
|
|
| // The only relevant ResponseType is id-pkix-ocsp-basic.
|
| - if (OBJ_cbs2nid(&response_type) != NID_id_pkix_OCSP_basic)
|
| + if (!CBS_mem_equal(&response_type, kOCSPBasicResponseOid,
|
| + sizeof(kOCSPBasicResponseOid))) {
|
| return false;
|
| + }
|
|
|
| // Parse the ResponseData out of the BasicOCSPResponse. Ignore the rest.
|
| + constexpr unsigned kVersionTag =
|
| + CBS_ASN1_CONTEXT_SPECIFIC | CBS_ASN1_CONSTRUCTED | 0;
|
| CBS basic_response, response_data, responses;
|
| if (!CBS_get_asn1(&response, &basic_response, CBS_ASN1_SEQUENCE) ||
|
| CBS_len(&response) != 0 ||
|
| !CBS_get_asn1(&basic_response, &response_data, CBS_ASN1_SEQUENCE)) {
|
| - }
|
| -
|
| - // Skip the optional version.
|
| - const int kVersionTag = CBS_ASN1_CONTEXT_SPECIFIC | CBS_ASN1_CONSTRUCTED | 0;
|
| - if (CBS_len(&response_data) > 0 &&
|
| - CBS_data(&response_data)[0] == kVersionTag &&
|
| - !CBS_get_asn1(&response_data, NULL /* version */, kVersionTag)) {
|
| return false;
|
| }
|
|
|
| - // Extract the list of SingleResponses.
|
| - if (!CBS_get_any_asn1_element(&response_data, NULL /* responderID */, NULL,
|
| - NULL) ||
|
| - !CBS_get_any_asn1_element(&response_data, NULL /* producedAt */, NULL,
|
| - NULL) ||
|
| + // Extract the list of SingleResponses from the ResponseData.
|
| + if (!SkipOptionalElement(&response_data, kVersionTag) ||
|
| + !SkipElements(&response_data, 2 /* responderID, producedAt */) ||
|
| !CBS_get_asn1(&response_data, &responses, CBS_ASN1_SEQUENCE)) {
|
| return false;
|
| }
|
| @@ -314,37 +424,22 @@ bool ExtractSCTListFromOCSPResponse(X509Certificate::OSCertHandle issuer,
|
| return false;
|
| }
|
|
|
| - // Skip the certStatus and thisUpdate fields.
|
| - if (!CBS_get_any_asn1_element(&single_response, NULL /* certStatus */, NULL,
|
| - NULL) ||
|
| - !CBS_get_any_asn1_element(&single_response, NULL /* thisUpdate */, NULL,
|
| - NULL)) {
|
| - return false;
|
| - }
|
| -
|
| - const int kNextUpdateTag =
|
| + // Parse the extensions out of the SingleResponse.
|
| + constexpr unsigned kNextUpdateTag =
|
| CBS_ASN1_CONTEXT_SPECIFIC | CBS_ASN1_CONSTRUCTED | 0;
|
| - const int kSingleExtensionsTag =
|
| + constexpr unsigned kSingleExtensionsTag =
|
| CBS_ASN1_CONTEXT_SPECIFIC | CBS_ASN1_CONSTRUCTED | 1;
|
| -
|
| - // Skip the optional nextUpdate field.
|
| - if (CBS_len(&single_response) > 0 &&
|
| - CBS_data(&single_response)[0] == kNextUpdateTag &&
|
| - !CBS_get_asn1(&single_response, NULL /* nextUpdate */, kNextUpdateTag)) {
|
| + CBS extensions_wrap, extensions;
|
| + if (!SkipElements(&single_response, 2 /* certStatus, thisUpdate */) ||
|
| + !SkipOptionalElement(&single_response, kNextUpdateTag) ||
|
| + !CBS_get_asn1(&single_response, &extensions_wrap, kSingleExtensionsTag) ||
|
| + !CBS_get_asn1(&extensions_wrap, &extensions, CBS_ASN1_SEQUENCE) ||
|
| + CBS_len(&extensions_wrap) != 0) {
|
| return false;
|
| }
|
|
|
| - CBS extensions;
|
| - if (!CBS_get_asn1(&single_response, &extensions, kSingleExtensionsTag))
|
| - return false;
|
| - const uint8_t* ptr = CBS_data(&extensions);
|
| - bssl::UniquePtr<X509_EXTENSIONS> x509_exts(
|
| - d2i_X509_EXTENSIONS(NULL, &ptr, CBS_len(&extensions)));
|
| - if (!x509_exts || ptr != CBS_data(&extensions) + CBS_len(&extensions))
|
| - return false;
|
| -
|
| - return GetSCTListFromX509_EXTENSIONS(x509_exts.get(), kOCSPExtensionOid,
|
| - sizeof(kOCSPExtensionOid), sct_list);
|
| + return ParseSCTListFromExtensions(extensions, kOCSPExtensionOid,
|
| + sizeof(kOCSPExtensionOid), sct_list);
|
| }
|
|
|
| } // namespace ct
|
|
|