Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(29)

Side by Side Diff: net/cert/ct_objects_extractor_nss.cc

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

Powered by Google App Engine
This is Rietveld 408576698