Home | History | Annotate | Download | only in cert
      1 // Copyright 2013 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "net/cert/ct_objects_extractor.h"
      6 
      7 #include <cert.h>
      8 #include <secasn1.h>
      9 #include <secitem.h>
     10 #include <secoid.h>
     11 
     12 #include "base/lazy_instance.h"
     13 #include "base/sha1.h"
     14 #include "crypto/scoped_nss_types.h"
     15 #include "crypto/sha2.h"
     16 #include "net/cert/asn1_util.h"
     17 #include "net/cert/scoped_nss_types.h"
     18 #include "net/cert/signed_certificate_timestamp.h"
     19 
     20 namespace net {
     21 
     22 namespace ct {
     23 
     24 namespace {
     25 
     26 // NSS black magic to get the address of externally defined template at runtime.
     27 SEC_ASN1_MKSUB(SEC_IntegerTemplate)
     28 SEC_ASN1_MKSUB(SECOID_AlgorithmIDTemplate)
     29 SEC_ASN1_MKSUB(SEC_GeneralizedTimeTemplate)
     30 SEC_ASN1_MKSUB(CERT_SequenceOfCertExtensionTemplate)
     31 
     32 // Wrapper class to convert a X509Certificate::OSCertHandle directly
     33 // into a CERTCertificate* usable with other NSS functions. This is used for
     34 // platforms where X509Certificate::OSCertHandle refers to a different type
     35 // than a CERTCertificate*.
     36 struct NSSCertWrapper {
     37   explicit NSSCertWrapper(X509Certificate::OSCertHandle cert_handle);
     38   ~NSSCertWrapper() {}
     39 
     40   ScopedCERTCertificate cert;
     41 };
     42 
     43 NSSCertWrapper::NSSCertWrapper(X509Certificate::OSCertHandle cert_handle) {
     44 #if defined(USE_NSS)
     45   cert.reset(CERT_DupCertificate(cert_handle));
     46 #else
     47   SECItem der_cert;
     48   std::string der_data;
     49   if (!X509Certificate::GetDEREncoded(cert_handle, &der_data))
     50     return;
     51   der_cert.data =
     52       reinterpret_cast<unsigned char*>(const_cast<char*>(der_data.data()));
     53   der_cert.len = der_data.size();
     54 
     55   // Note: CERT_NewTempCertificate may return NULL if the certificate
     56   // shares a serial number with another cert issued by the same CA,
     57   // which is not supposed to happen.
     58   cert.reset(CERT_NewTempCertificate(
     59       CERT_GetDefaultCertDB(), &der_cert, NULL, PR_FALSE, PR_TRUE));
     60 #endif
     61   DCHECK(cert.get() != NULL);
     62 }
     63 
     64 // The wire form of the OID 1.3.6.1.4.1.11129.2.4.2. See Section 3.3 of
     65 // RFC6962.
     66 const unsigned char kEmbeddedSCTOid[] = {0x2B, 0x06, 0x01, 0x04, 0x01,
     67                                          0xD6, 0x79, 0x02, 0x04, 0x02};
     68 const char kEmbeddedSCTDescription[] =
     69     "X.509v3 Certificate Transparency Embedded Signed Certificate Timestamp "
     70     "List";
     71 
     72 // The wire form of the OID 1.3.6.1.4.1.11129.2.4.5 - OCSP SingleExtension for
     73 // X.509v3 Certificate Transparency Signed Certificate Timestamp List, see
     74 // Section 3.3 of RFC6962.
     75 const unsigned char kOCSPExtensionOid[] = {0x2B, 0x06, 0x01, 0x04, 0x01,
     76                                            0xD6, 0x79, 0x02, 0x04, 0x05};
     77 
     78 const SECItem kOCSPExtensionOidItem = {
     79   siBuffer, const_cast<unsigned char*>(kOCSPExtensionOid),
     80   sizeof(kOCSPExtensionOid)
     81 };
     82 
     83 // id-ad-ocsp: 1.3.6.1.5.5.7.48.1.1
     84 const unsigned char kBasicOCSPResponseOid[] = {0x2B, 0x06, 0x01, 0x05, 0x05,
     85                                                0x07, 0x30, 0x01, 0x01};
     86 
     87 const SECItem kBasicOCSPResponseOidItem = {
     88   siBuffer, const_cast<unsigned char*>(kBasicOCSPResponseOid),
     89   sizeof(kBasicOCSPResponseOid)
     90 };
     91 
     92 
     93 // Initializes the necessary NSS internals for use with Certificate
     94 // Transparency.
     95 class CTInitSingleton {
     96  public:
     97   SECOidTag embedded_oid() const { return embedded_oid_; }
     98 
     99  private:
    100   friend struct base::DefaultLazyInstanceTraits<CTInitSingleton>;
    101 
    102   CTInitSingleton() : embedded_oid_(SEC_OID_UNKNOWN) {
    103     embedded_oid_ = RegisterOid(
    104         kEmbeddedSCTOid, sizeof(kEmbeddedSCTOid), kEmbeddedSCTDescription);
    105   }
    106 
    107   ~CTInitSingleton() {}
    108 
    109   SECOidTag RegisterOid(const unsigned char* oid,
    110                         unsigned int oid_len,
    111                         const char* description) {
    112     SECOidData oid_data;
    113     oid_data.oid.len = oid_len;
    114     oid_data.oid.data = const_cast<unsigned char*>(oid);
    115     oid_data.offset = SEC_OID_UNKNOWN;
    116     oid_data.desc = description;
    117     oid_data.mechanism = CKM_INVALID_MECHANISM;
    118     // Setting this to SUPPORTED_CERT_EXTENSION ensures that if a certificate
    119     // contains this extension with the critical bit set, NSS will not reject
    120     // it. However, because verification of this extension happens after NSS,
    121     // it is currently left as INVALID_CERT_EXTENSION.
    122     oid_data.supportedExtension = INVALID_CERT_EXTENSION;
    123 
    124     SECOidTag result = SECOID_AddEntry(&oid_data);
    125     CHECK_NE(SEC_OID_UNKNOWN, result);
    126 
    127     return result;
    128   }
    129 
    130   SECOidTag embedded_oid_;
    131 
    132   DISALLOW_COPY_AND_ASSIGN(CTInitSingleton);
    133 };
    134 
    135 base::LazyInstance<CTInitSingleton>::Leaky g_ct_singleton =
    136     LAZY_INSTANCE_INITIALIZER;
    137 
    138 // Obtains the data for an X.509v3 certificate extension identified by |oid|
    139 // and encoded as an OCTET STRING. Returns true if the extension was found in
    140 // the certificate, updating |ext_data| to be the extension data after removing
    141 // the DER encoding of OCTET STRING.
    142 bool GetCertOctetStringExtension(CERTCertificate* cert,
    143                                  SECOidTag oid,
    144                                  std::string* extension_data) {
    145   SECItem extension;
    146   SECStatus rv = CERT_FindCertExtension(cert, oid, &extension);
    147   if (rv != SECSuccess)
    148     return false;
    149 
    150   base::StringPiece raw_data(reinterpret_cast<char*>(extension.data),
    151                              extension.len);
    152   base::StringPiece parsed_data;
    153   if (!asn1::GetElement(&raw_data, asn1::kOCTETSTRING, &parsed_data) ||
    154       raw_data.size() > 0) { // Decoding failure or raw data left
    155     rv = SECFailure;
    156   } else {
    157     parsed_data.CopyToString(extension_data);
    158   }
    159 
    160   SECITEM_FreeItem(&extension, PR_FALSE);
    161   return rv == SECSuccess;
    162 }
    163 
    164 // NSS offers CERT_FindCertExtension for certificates, but that only accepts
    165 // CERTCertificate* inputs, so the method below extracts the SCT extension
    166 // directly from the CERTCertExtension** of an OCSP response.
    167 //
    168 // Obtains the data for an OCSP extension identified by kOCSPExtensionOidItem
    169 // and encoded as an OCTET STRING. Returns true if the extension was found in
    170 // |extensions|, updating |extension_data| to be the extension data after
    171 // removing the DER encoding of OCTET STRING.
    172 bool GetSCTListFromOCSPExtension(PLArenaPool* arena,
    173                                  const CERTCertExtension* const* extensions,
    174                                  std::string* extension_data) {
    175   if (!extensions)
    176     return false;
    177 
    178   const CERTCertExtension* match = NULL;
    179 
    180   for (const CERTCertExtension* const* exts = extensions; *exts; ++exts) {
    181     const CERTCertExtension* ext = *exts;
    182     if (SECITEM_ItemsAreEqual(&kOCSPExtensionOidItem, &ext->id)) {
    183       match = ext;
    184       break;
    185     }
    186   }
    187 
    188   if (!match)
    189     return false;
    190 
    191   SECItem contents;
    192   // SEC_QuickDERDecodeItem sets |contents| to point to |match|, so it is not
    193   // necessary to free the contents of |contents|.
    194   SECStatus rv = SEC_QuickDERDecodeItem(arena, &contents,
    195                                         SEC_ASN1_GET(SEC_OctetStringTemplate),
    196                                         &match->value);
    197   if (rv != SECSuccess)
    198     return false;
    199 
    200   base::StringPiece parsed_data(reinterpret_cast<char*>(contents.data),
    201                                 contents.len);
    202   parsed_data.CopyToString(extension_data);
    203   return true;
    204 }
    205 
    206 // Given a |cert|, extract the TBSCertificate from this certificate, also
    207 // removing the X.509 extension with OID 1.3.6.1.4.1.11129.2.4.2 (that is,
    208 // the embedded SCT)
    209 bool ExtractTBSCertWithoutSCTs(CERTCertificate* cert,
    210                                std::string* to_be_signed) {
    211   SECOidData* oid = SECOID_FindOIDByTag(g_ct_singleton.Get().embedded_oid());
    212   if (!oid)
    213     return false;
    214 
    215   // This is a giant hack, due to the fact that NSS does not expose a good API
    216   // for simply removing certificate fields from existing certificates.
    217   CERTCertificate temp_cert;
    218   temp_cert = *cert;
    219   temp_cert.extensions = NULL;
    220 
    221   // Strip out the embedded SCT OID from the new certificate by directly
    222   // mutating the extensions in place.
    223   std::vector<CERTCertExtension*> new_extensions;
    224   if (cert->extensions) {
    225     for (CERTCertExtension** exts = cert->extensions; *exts; ++exts) {
    226       CERTCertExtension* ext = *exts;
    227       SECComparison result = SECITEM_CompareItem(&oid->oid, &ext->id);
    228       if (result != SECEqual)
    229         new_extensions.push_back(ext);
    230     }
    231   }
    232   if (!new_extensions.empty()) {
    233     new_extensions.push_back(NULL);
    234     temp_cert.extensions = &new_extensions[0];
    235   }
    236 
    237   crypto::ScopedPLArenaPool arena(PORT_NewArena(DER_DEFAULT_CHUNKSIZE));
    238 
    239   SECItem tbs_data;
    240   tbs_data.len = 0;
    241   tbs_data.data = NULL;
    242   void* result = SEC_ASN1EncodeItem(arena.get(),
    243                                     &tbs_data,
    244                                     &temp_cert,
    245                                     SEC_ASN1_GET(CERT_CertificateTemplate));
    246   if (!result)
    247     return false;
    248 
    249   to_be_signed->assign(reinterpret_cast<char*>(tbs_data.data), tbs_data.len);
    250   return true;
    251 }
    252 
    253 // The following code is adapted from the NSS OCSP module, in order to expose
    254 // the internal structure of an OCSP response.
    255 
    256 // ResponseBytes ::=       SEQUENCE {
    257 //     responseType   OBJECT IDENTIFIER,
    258 //     response       OCTET STRING }
    259 struct ResponseBytes {
    260   SECItem response_type;
    261   SECItem der_response;
    262 };
    263 
    264 const SEC_ASN1Template kResponseBytesTemplate[] = {
    265   { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(ResponseBytes) },
    266   { SEC_ASN1_OBJECT_ID, offsetof(ResponseBytes, response_type) },
    267   { SEC_ASN1_OCTET_STRING, offsetof(ResponseBytes, der_response) },
    268   { 0 }
    269 };
    270 
    271 // OCSPResponse ::=     SEQUENCE {
    272 //      responseStatus          OCSPResponseStatus,
    273 //      responseBytes           [0] EXPLICIT ResponseBytes OPTIONAL }
    274 struct OCSPResponse {
    275   SECItem response_status;
    276   // This indirection is needed because |response_bytes| is an optional
    277   // component and we need a way to determine if it is missing.
    278   ResponseBytes* response_bytes;
    279 };
    280 
    281 const SEC_ASN1Template kPointerToResponseBytesTemplate[] = {
    282   { SEC_ASN1_POINTER, 0, kResponseBytesTemplate }
    283 };
    284 
    285 const SEC_ASN1Template kOCSPResponseTemplate[] = {
    286   { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(OCSPResponse) },
    287   { SEC_ASN1_ENUMERATED, offsetof(OCSPResponse, response_status) },
    288   { SEC_ASN1_OPTIONAL | SEC_ASN1_EXPLICIT | SEC_ASN1_CONSTRUCTED |
    289     SEC_ASN1_CONTEXT_SPECIFIC | 0, offsetof(OCSPResponse, response_bytes),
    290     kPointerToResponseBytesTemplate },
    291   { 0 }
    292 };
    293 
    294 // CertID          ::=     SEQUENCE {
    295 //   hashAlgorithm       AlgorithmIdentifier,
    296 //   issuerNameHash      OCTET STRING, -- Hash of Issuer's DN
    297 //   issuerKeyHash       OCTET STRING, -- Hash of Issuers public key
    298 //   serialNumber        CertificateSerialNumber }
    299 struct CertID {
    300   SECAlgorithmID hash_algorithm;
    301   SECItem issuer_name_hash;
    302   SECItem issuer_key_hash;
    303   SECItem serial_number;
    304 };
    305 
    306 const SEC_ASN1Template kCertIDTemplate[] = {
    307   { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(CertID) },
    308   { SEC_ASN1_INLINE | SEC_ASN1_XTRN, offsetof(CertID, hash_algorithm),
    309     SEC_ASN1_SUB(SECOID_AlgorithmIDTemplate) },
    310   { SEC_ASN1_OCTET_STRING, offsetof(CertID, issuer_name_hash) },
    311   { SEC_ASN1_OCTET_STRING, offsetof(CertID, issuer_key_hash) },
    312   { SEC_ASN1_INTEGER, offsetof(CertID, serial_number) },
    313   { 0 }
    314 };
    315 
    316 // SingleResponse ::= SEQUENCE {
    317 //   certID                       CertID,
    318 //   certStatus                   CertStatus,
    319 //   thisUpdate                   GeneralizedTime,
    320 //   nextUpdate           [0]     EXPLICIT GeneralizedTime OPTIONAL,
    321 //   singleExtensions     [1]     EXPLICIT Extensions OPTIONAL }
    322 struct SingleResponse {
    323   CertID cert_id;
    324   // The following three fields are not used.
    325   SECItem der_cert_status;
    326   SECItem this_update;
    327   SECItem next_update;
    328   CERTCertExtension** single_extensions;
    329 };
    330 
    331 const SEC_ASN1Template kSingleResponseTemplate[] = {
    332   { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(SingleResponse) },
    333   { SEC_ASN1_INLINE, offsetof(SingleResponse, cert_id), kCertIDTemplate },
    334   // Really a CHOICE but we make it an ANY because  we don't care about the
    335   // contents of this field.
    336   // TODO(ekasper): use SEC_ASN1_CHOICE.
    337   { SEC_ASN1_ANY, offsetof(SingleResponse, der_cert_status) },
    338   { SEC_ASN1_GENERALIZED_TIME, offsetof(SingleResponse, this_update) },
    339   { SEC_ASN1_OPTIONAL | SEC_ASN1_EXPLICIT |
    340     SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_XTRN | 0,
    341     offsetof(SingleResponse, next_update),
    342     SEC_ASN1_SUB(SEC_GeneralizedTimeTemplate) },
    343   { SEC_ASN1_OPTIONAL | SEC_ASN1_EXPLICIT | SEC_ASN1_CONSTRUCTED |
    344     SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_XTRN | 1,
    345     offsetof(SingleResponse, single_extensions),
    346     SEC_ASN1_SUB(CERT_SequenceOfCertExtensionTemplate) },
    347   { 0 }
    348 };
    349 
    350 // ResponseData ::= SEQUENCE {
    351 //   version              [0] EXPLICIT Version DEFAULT v1,
    352 //   responderID              ResponderID,
    353 //   producedAt               GeneralizedTime,
    354 //   responses                SEQUENCE OF SingleResponse,
    355 //   responseExtensions   [1] EXPLICIT Extensions OPTIONAL }
    356 struct ResponseData {
    357   // The first three fields are not used.
    358   SECItem version;
    359   SECItem der_responder_id;
    360   SECItem produced_at;
    361   SingleResponse** single_responses;
    362   // Skip extensions.
    363 };
    364 
    365 const SEC_ASN1Template kResponseDataTemplate[] = {
    366   { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(ResponseData) },
    367   { SEC_ASN1_OPTIONAL | SEC_ASN1_EXPLICIT | SEC_ASN1_CONSTRUCTED |
    368     SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_XTRN | 0,
    369     offsetof(ResponseData, version), SEC_ASN1_SUB(SEC_IntegerTemplate) },
    370   // Really a CHOICE but we make it an ANY because  we don't care about the
    371   // contents of this field.
    372   // TODO(ekasper): use SEC_ASN1_CHOICE.
    373   { SEC_ASN1_ANY, offsetof(ResponseData, der_responder_id) },
    374   { SEC_ASN1_GENERALIZED_TIME, offsetof(ResponseData, produced_at) },
    375   { SEC_ASN1_SEQUENCE_OF, offsetof(ResponseData, single_responses),
    376     kSingleResponseTemplate },
    377   { SEC_ASN1_SKIP_REST },
    378   { 0 }
    379 };
    380 
    381 // BasicOCSPResponse       ::= SEQUENCE {
    382 //   tbsResponseData      ResponseData,
    383 //   signatureAlgorithm   AlgorithmIdentifier,
    384 //   signature            BIT STRING,
    385 //   certs                [0] EXPLICIT SEQUENCE OF Certificate OPTIONAL }
    386 struct BasicOCSPResponse {
    387   ResponseData tbs_response_data;
    388   // We do not care about the rest.
    389 };
    390 
    391 const SEC_ASN1Template kBasicOCSPResponseTemplate[] = {
    392   { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(BasicOCSPResponse) },
    393   { SEC_ASN1_INLINE, offsetof(BasicOCSPResponse, tbs_response_data),
    394     kResponseDataTemplate },
    395   { SEC_ASN1_SKIP_REST },
    396   { 0 }
    397 };
    398 
    399 bool StringEqualToSECItem(const std::string& value1, const SECItem& value2) {
    400   if (value1.size() != value2.len)
    401     return false;
    402   return memcmp(value1.data(), value2.data, value2.len) == 0;
    403 }
    404 
    405 // TODO(ekasper): also use the issuer name hash in matching.
    406 bool CertIDMatches(const CertID& cert_id,
    407                    const std::string& serial_number,
    408                    const std::string& issuer_key_sha1_hash,
    409                    const std::string& issuer_key_sha256_hash) {
    410   if (!StringEqualToSECItem(serial_number, cert_id.serial_number))
    411     return false;
    412 
    413   SECOidTag hash_alg = SECOID_FindOIDTag(&cert_id.hash_algorithm.algorithm);
    414   switch (hash_alg) {
    415     case SEC_OID_SHA1:
    416       return StringEqualToSECItem(issuer_key_sha1_hash,
    417                                   cert_id.issuer_key_hash);
    418     case SEC_OID_SHA256:
    419       return StringEqualToSECItem(issuer_key_sha256_hash,
    420                                   cert_id.issuer_key_hash);
    421     default:
    422       return false;
    423   }
    424 }
    425 
    426 }  // namespace
    427 
    428 bool ExtractEmbeddedSCTList(X509Certificate::OSCertHandle cert,
    429                             std::string* sct_list) {
    430   DCHECK(cert);
    431 
    432   NSSCertWrapper leaf_cert(cert);
    433   if (!leaf_cert.cert)
    434     return false;
    435 
    436   return GetCertOctetStringExtension(leaf_cert.cert.get(),
    437                                      g_ct_singleton.Get().embedded_oid(),
    438                                      sct_list);
    439 }
    440 
    441 bool GetPrecertLogEntry(X509Certificate::OSCertHandle leaf,
    442                         X509Certificate::OSCertHandle issuer,
    443                         LogEntry* result) {
    444   DCHECK(leaf);
    445   DCHECK(issuer);
    446 
    447   NSSCertWrapper leaf_cert(leaf);
    448   NSSCertWrapper issuer_cert(issuer);
    449 
    450   result->Reset();
    451   // XXX(rsleevi): This check may be overkill, since we should be able to
    452   // generate precerts for certs without the extension. For now, just a sanity
    453   // check to match the reference implementation.
    454   SECItem extension;
    455   SECStatus rv = CERT_FindCertExtension(
    456       leaf_cert.cert.get(), g_ct_singleton.Get().embedded_oid(), &extension);
    457   if (rv != SECSuccess)
    458     return false;
    459   SECITEM_FreeItem(&extension, PR_FALSE);
    460 
    461   std::string to_be_signed;
    462   if (!ExtractTBSCertWithoutSCTs(leaf_cert.cert.get(), &to_be_signed))
    463     return false;
    464 
    465   if (!issuer_cert.cert) {
    466     // This can happen when the issuer and leaf certs share the same serial
    467     // number and are from the same CA, which should never be the case
    468     // (but happened with bad test certs).
    469     VLOG(1) << "Issuer cert is null, cannot generate Precert entry.";
    470     return false;
    471   }
    472 
    473   SECKEYPublicKey* issuer_pub_key =
    474       SECKEY_ExtractPublicKey(&(issuer_cert.cert->subjectPublicKeyInfo));
    475   if (!issuer_pub_key) {
    476     VLOG(1) << "Could not extract issuer public key, "
    477             << "cannot generate Precert entry.";
    478     return false;
    479   }
    480 
    481   SECItem* encoded_issuer_pubKey =
    482       SECKEY_EncodeDERSubjectPublicKeyInfo(issuer_pub_key);
    483   if (!encoded_issuer_pubKey) {
    484     SECKEY_DestroyPublicKey(issuer_pub_key);
    485     return false;
    486   }
    487 
    488   result->type = ct::LogEntry::LOG_ENTRY_TYPE_PRECERT;
    489   result->tbs_certificate.swap(to_be_signed);
    490 
    491   crypto::SHA256HashString(
    492       base::StringPiece(reinterpret_cast<char*>(encoded_issuer_pubKey->data),
    493                         encoded_issuer_pubKey->len),
    494       result->issuer_key_hash.data,
    495       sizeof(result->issuer_key_hash.data));
    496 
    497   SECITEM_FreeItem(encoded_issuer_pubKey, PR_TRUE);
    498   SECKEY_DestroyPublicKey(issuer_pub_key);
    499 
    500   return true;
    501 }
    502 
    503 bool GetX509LogEntry(X509Certificate::OSCertHandle leaf, LogEntry* result) {
    504   DCHECK(leaf);
    505 
    506   std::string encoded;
    507   if (!X509Certificate::GetDEREncoded(leaf, &encoded))
    508     return false;
    509 
    510   result->Reset();
    511   result->type = ct::LogEntry::LOG_ENTRY_TYPE_X509;
    512   result->leaf_certificate.swap(encoded);
    513   return true;
    514 }
    515 
    516 bool ExtractSCTListFromOCSPResponse(X509Certificate::OSCertHandle issuer,
    517                                     const std::string& cert_serial_number,
    518                                     const std::string& ocsp_response,
    519                                     std::string* sct_list) {
    520   DCHECK(issuer);
    521 
    522   // Any OCSP response is unlikely to be even close to 2^24 bytes; further, CT
    523   // only uses stapled OCSP responses which have this limit imposed by the TLS
    524   // protocol.
    525   if (ocsp_response.size() > 0xffffff)
    526     return false;
    527 
    528   crypto::ScopedPLArenaPool arena(PORT_NewArena(DER_DEFAULT_CHUNKSIZE));
    529 
    530   OCSPResponse response;
    531   memset(&response, 0, sizeof(response));
    532 
    533   SECItem src = { siBuffer,
    534                   reinterpret_cast<unsigned char*>(const_cast<char*>(
    535                       ocsp_response.data())),
    536                   static_cast<unsigned int>(ocsp_response.size()) };
    537 
    538   // |response| will point directly into |src|, so it's not necessary to
    539   // free the |response| contents, but they may only be used while |src|
    540   // is valid (i.e., in this method).
    541   SECStatus rv = SEC_QuickDERDecodeItem(arena.get(), &response,
    542                                         kOCSPResponseTemplate, &src);
    543   if (rv != SECSuccess)
    544     return false;
    545 
    546   if (!response.response_bytes)
    547     return false;
    548 
    549   if (!SECITEM_ItemsAreEqual(&kBasicOCSPResponseOidItem,
    550                              &response.response_bytes->response_type)) {
    551     return false;
    552   }
    553 
    554   BasicOCSPResponse basic_response;
    555   memset(&basic_response, 0, sizeof(basic_response));
    556 
    557   rv = SEC_QuickDERDecodeItem(arena.get(), &basic_response,
    558                               kBasicOCSPResponseTemplate,
    559                               &response.response_bytes->der_response);
    560   if (rv != SECSuccess)
    561     return false;
    562 
    563   SingleResponse** responses =
    564       basic_response.tbs_response_data.single_responses;
    565   if (!responses)
    566     return false;
    567 
    568   std::string issuer_der;
    569   if (!X509Certificate::GetDEREncoded(issuer, &issuer_der))
    570     return false;
    571 
    572   base::StringPiece issuer_spki;
    573   if (!asn1::ExtractSPKIFromDERCert(issuer_der, &issuer_spki))
    574     return false;
    575 
    576   // In OCSP, only the key itself is under hash.
    577   base::StringPiece issuer_spk;
    578   if (!asn1::ExtractSubjectPublicKeyFromSPKI(issuer_spki, &issuer_spk))
    579     return false;
    580 
    581   // ExtractSubjectPublicKey... does not remove the initial octet encoding the
    582   // number of unused bits in the ASN.1 BIT STRING so we do it here. For public
    583   // keys, the bitstring is in practice always byte-aligned.
    584   if (issuer_spk.empty() || issuer_spk[0] != 0)
    585     return false;
    586   issuer_spk.remove_prefix(1);
    587 
    588   // NSS OCSP lib recognizes SHA1, MD5 and MD2; MD5 and MD2 are dead but
    589   // https://bugzilla.mozilla.org/show_bug.cgi?id=663315 will add SHA-256
    590   // and SHA-384.
    591   // TODO(ekasper): add SHA-384 to crypto/sha2.h and here if it proves
    592   // necessary.
    593   // TODO(ekasper): only compute the hashes on demand.
    594   std::string issuer_key_sha256_hash = crypto::SHA256HashString(issuer_spk);
    595   std::string issuer_key_sha1_hash = base::SHA1HashString(
    596       issuer_spk.as_string());
    597 
    598   const SingleResponse* match = NULL;
    599   for (const SingleResponse* const* resps = responses; *resps; ++resps) {
    600     const SingleResponse* resp = *resps;
    601     if (CertIDMatches(resp->cert_id, cert_serial_number,
    602                       issuer_key_sha1_hash, issuer_key_sha256_hash)) {
    603       match = resp;
    604       break;
    605     }
    606   }
    607 
    608   if (!match)
    609     return false;
    610 
    611   return GetSCTListFromOCSPExtension(arena.get(), match->single_extensions,
    612                                      sct_list);
    613 }
    614 
    615 }  // namespace ct
    616 
    617 }  // namespace net
    618