• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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);
~NSSCertWrappernet::ct::__anone500fc570111::NSSCertWrapper38   ~NSSCertWrapper() {}
39 
40   ScopedCERTCertificate cert;
41 };
42 
NSSCertWrapper(X509Certificate::OSCertHandle cert_handle)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:
embedded_oid() const97   SECOidTag embedded_oid() const { return embedded_oid_; }
98 
99  private:
100   friend struct base::DefaultLazyInstanceTraits<CTInitSingleton>;
101 
CTInitSingleton()102   CTInitSingleton() : embedded_oid_(SEC_OID_UNKNOWN) {
103     embedded_oid_ = RegisterOid(
104         kEmbeddedSCTOid, sizeof(kEmbeddedSCTOid), kEmbeddedSCTDescription);
105   }
106 
~CTInitSingleton()107   ~CTInitSingleton() {}
108 
RegisterOid(const unsigned char * oid,unsigned int oid_len,const char * description)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.
GetCertOctetStringExtension(CERTCertificate * cert,SECOidTag oid,std::string * extension_data)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.
GetSCTListFromOCSPExtension(PLArenaPool * arena,const CERTCertExtension * const * extensions,std::string * extension_data)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)
ExtractTBSCertWithoutSCTs(CERTCertificate * cert,std::string * to_be_signed)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 
StringEqualToSECItem(const std::string & value1,const SECItem & value2)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.
CertIDMatches(const CertID & cert_id,const std::string & serial_number,const std::string & issuer_key_sha1_hash,const std::string & issuer_key_sha256_hash)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 
ExtractEmbeddedSCTList(X509Certificate::OSCertHandle cert,std::string * sct_list)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 
GetPrecertLogEntry(X509Certificate::OSCertHandle leaf,X509Certificate::OSCertHandle issuer,LogEntry * result)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 
GetX509LogEntry(X509Certificate::OSCertHandle leaf,LogEntry * result)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 
ExtractSCTListFromOCSPResponse(X509Certificate::OSCertHandle issuer,const std::string & cert_serial_number,const std::string & ocsp_response,std::string * sct_list)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