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
20namespace net {
21
22namespace ct {
23
24namespace {
25
26// NSS black magic to get the address of externally defined template at runtime.
27SEC_ASN1_MKSUB(SEC_IntegerTemplate)
28SEC_ASN1_MKSUB(SECOID_AlgorithmIDTemplate)
29SEC_ASN1_MKSUB(SEC_GeneralizedTimeTemplate)
30SEC_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*.
36struct NSSCertWrapper {
37  explicit NSSCertWrapper(X509Certificate::OSCertHandle cert_handle);
38  ~NSSCertWrapper() {}
39
40  ScopedCERTCertificate cert;
41};
42
43NSSCertWrapper::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.
66const unsigned char kEmbeddedSCTOid[] = {0x2B, 0x06, 0x01, 0x04, 0x01,
67                                         0xD6, 0x79, 0x02, 0x04, 0x02};
68const 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.
75const unsigned char kOCSPExtensionOid[] = {0x2B, 0x06, 0x01, 0x04, 0x01,
76                                           0xD6, 0x79, 0x02, 0x04, 0x05};
77
78const 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
84const unsigned char kBasicOCSPResponseOid[] = {0x2B, 0x06, 0x01, 0x05, 0x05,
85                                               0x07, 0x30, 0x01, 0x01};
86
87const 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.
95class 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
135base::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.
142bool 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.
172bool 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)
209bool 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 }
259struct ResponseBytes {
260  SECItem response_type;
261  SECItem der_response;
262};
263
264const 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 }
274struct 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
281const SEC_ASN1Template kPointerToResponseBytesTemplate[] = {
282  { SEC_ASN1_POINTER, 0, kResponseBytesTemplate }
283};
284
285const 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 }
299struct CertID {
300  SECAlgorithmID hash_algorithm;
301  SECItem issuer_name_hash;
302  SECItem issuer_key_hash;
303  SECItem serial_number;
304};
305
306const 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 }
322struct 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
331const 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 }
356struct 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
365const 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 }
386struct BasicOCSPResponse {
387  ResponseData tbs_response_data;
388  // We do not care about the rest.
389};
390
391const 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
399bool 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.
406bool 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
428bool 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
441bool 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
503bool 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
516bool 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