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