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

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

Issue 108113006: Revert of Extract Certificate Transparency SCTs from stapled OCSP responses (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@extract_scts
Patch Set: Created 7 years 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_objects_extractor.h ('k') | net/cert/ct_objects_extractor_openssl.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2013 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "net/cert/ct_objects_extractor.h" 5 #include "net/cert/ct_objects_extractor.h"
6 6
7 #include <cert.h> 7 #include <cert.h>
8 #include <secasn1.h> 8 #include <secasn1.h>
9 #include <secitem.h> 9 #include <secitem.h>
10 #include <secoid.h> 10 #include <secoid.h>
11 11
12 #include "base/lazy_instance.h" 12 #include "base/lazy_instance.h"
13 #include "base/sha1.h"
14 #include "crypto/scoped_nss_types.h" 13 #include "crypto/scoped_nss_types.h"
15 #include "crypto/sha2.h" 14 #include "crypto/sha2.h"
16 #include "net/cert/asn1_util.h" 15 #include "net/cert/asn1_util.h"
17 #include "net/cert/scoped_nss_types.h" 16 #include "net/cert/scoped_nss_types.h"
18 #include "net/cert/signed_certificate_timestamp.h" 17 #include "net/cert/signed_certificate_timestamp.h"
19 18
20 namespace net { 19 namespace net {
21 20
22 namespace ct { 21 namespace ct {
23 22
24 namespace { 23 namespace {
25 24
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 25 // Wrapper class to convert a X509Certificate::OSCertHandle directly
33 // into a CERTCertificate* usable with other NSS functions. This is used for 26 // into a CERTCertificate* usable with other NSS functions. This is used for
34 // platforms where X509Certificate::OSCertHandle refers to a different type 27 // platforms where X509Certificate::OSCertHandle refers to a different type
35 // than a CERTCertificate*. 28 // than a CERTCertificate*.
36 struct NSSCertWrapper { 29 struct NSSCertWrapper {
37 explicit NSSCertWrapper(X509Certificate::OSCertHandle cert_handle); 30 explicit NSSCertWrapper(X509Certificate::OSCertHandle cert_handle);
38 ~NSSCertWrapper() {} 31 ~NSSCertWrapper() {}
39 32
40 ScopedCERTCertificate cert; 33 ScopedCERTCertificate cert;
41 }; 34 };
(...skipping 20 matching lines...) Expand all
62 } 55 }
63 56
64 // The wire form of the OID 1.3.6.1.4.1.11129.2.4.2. See Section 3.3 of 57 // The wire form of the OID 1.3.6.1.4.1.11129.2.4.2. See Section 3.3 of
65 // RFC6962. 58 // RFC6962.
66 const unsigned char kEmbeddedSCTOid[] = {0x2B, 0x06, 0x01, 0x04, 0x01, 59 const unsigned char kEmbeddedSCTOid[] = {0x2B, 0x06, 0x01, 0x04, 0x01,
67 0xD6, 0x79, 0x02, 0x04, 0x02}; 60 0xD6, 0x79, 0x02, 0x04, 0x02};
68 const char kEmbeddedSCTDescription[] = 61 const char kEmbeddedSCTDescription[] =
69 "X.509v3 Certificate Transparency Embedded Signed Certificate Timestamp " 62 "X.509v3 Certificate Transparency Embedded Signed Certificate Timestamp "
70 "List"; 63 "List";
71 64
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 65 // Initializes the necessary NSS internals for use with Certificate
94 // Transparency. 66 // Transparency.
95 class CTInitSingleton { 67 class CTInitSingleton {
96 public: 68 public:
97 SECOidTag embedded_oid() const { return embedded_oid_; } 69 SECOidTag embedded_oid() const { return embedded_oid_; }
98 70
99 private: 71 private:
100 friend struct base::DefaultLazyInstanceTraits<CTInitSingleton>; 72 friend struct base::DefaultLazyInstanceTraits<CTInitSingleton>;
101 73
102 CTInitSingleton() : embedded_oid_(SEC_OID_UNKNOWN) { 74 CTInitSingleton() : embedded_oid_(SEC_OID_UNKNOWN) {
(...skipping 26 matching lines...) Expand all
129 101
130 SECOidTag embedded_oid_; 102 SECOidTag embedded_oid_;
131 103
132 DISALLOW_COPY_AND_ASSIGN(CTInitSingleton); 104 DISALLOW_COPY_AND_ASSIGN(CTInitSingleton);
133 }; 105 };
134 106
135 base::LazyInstance<CTInitSingleton>::Leaky g_ct_singleton = 107 base::LazyInstance<CTInitSingleton>::Leaky g_ct_singleton =
136 LAZY_INSTANCE_INITIALIZER; 108 LAZY_INSTANCE_INITIALIZER;
137 109
138 // Obtains the data for an X.509v3 certificate extension identified by |oid| 110 // 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 111 // and encoded as an OCTET STRING. Returns true if the extension was found,
140 // the certificate, updating |ext_data| to be the extension data after removing 112 // updating |ext_data| to be the extension data after removing the DER
141 // the DER encoding of OCTET STRING. 113 // encoding of OCTET STRING.
142 bool GetCertOctetStringExtension(CERTCertificate* cert, 114 bool GetOctetStringExtension(CERTCertificate* cert,
143 SECOidTag oid, 115 SECOidTag oid,
144 std::string* extension_data) { 116 std::string* extension_data) {
145 SECItem extension; 117 SECItem extension;
146 SECStatus rv = CERT_FindCertExtension(cert, oid, &extension); 118 SECStatus rv = CERT_FindCertExtension(cert, oid, &extension);
147 if (rv != SECSuccess) 119 if (rv != SECSuccess)
148 return false; 120 return false;
149 121
150 base::StringPiece raw_data(reinterpret_cast<char*>(extension.data), 122 base::StringPiece raw_data(reinterpret_cast<char*>(extension.data),
151 extension.len); 123 extension.len);
152 base::StringPiece parsed_data; 124 base::StringPiece parsed_data;
153 if (!asn1::GetElement(&raw_data, asn1::kOCTETSTRING, &parsed_data) || 125 if (!asn1::GetElement(&raw_data, asn1::kOCTETSTRING, &parsed_data) ||
154 raw_data.size() > 0) { // Decoding failure or raw data left 126 raw_data.size() > 0) { // Decoding failure or raw data left
155 rv = SECFailure; 127 rv = SECFailure;
156 } else { 128 } else {
157 parsed_data.CopyToString(extension_data); 129 parsed_data.CopyToString(extension_data);
158 } 130 }
159 131
160 SECITEM_FreeItem(&extension, PR_FALSE); 132 SECITEM_FreeItem(&extension, PR_FALSE);
161 return rv == SECSuccess; 133 return rv == SECSuccess;
162 } 134 }
163 135
164 // NSS offers CERT_FindCertExtension for certificates, but that only accepts
165 // CERTCertificate* inputs, so the method below extracts the SCT extension
166 // directly from the CERTCertExtension** of an OCSP response.
167 //
168 // Obtains the data for an OCSP extension identified by kOCSPExtensionOidItem
169 // and encoded as an OCTET STRING. Returns true if the extension was found in
170 // |extensions|, updating |extension_data| to be the extension data after
171 // removing the DER encoding of OCTET STRING.
172 bool GetSCTListFromOCSPExtension(PLArenaPool* arena,
173 const CERTCertExtension* const* extensions,
174 std::string* extension_data) {
175 if (!extensions)
176 return false;
177
178 const CERTCertExtension* match = NULL;
179
180 for (const CERTCertExtension* const* exts = extensions; *exts; ++exts) {
181 const CERTCertExtension* ext = *exts;
182 if (SECITEM_ItemsAreEqual(&kOCSPExtensionOidItem, &ext->id)) {
183 match = ext;
184 break;
185 }
186 }
187
188 if (!match)
189 return false;
190
191 SECItem contents;
192 // SEC_QuickDERDecodeItem sets |contents| to point to |match|, so it is not
193 // necessary to free the contents of |contents|.
194 SECStatus rv = SEC_QuickDERDecodeItem(arena, &contents,
195 SEC_ASN1_GET(SEC_OctetStringTemplate),
196 &match->value);
197 if (rv != SECSuccess)
198 return false;
199
200 base::StringPiece parsed_data(reinterpret_cast<char*>(contents.data),
201 contents.len);
202 parsed_data.CopyToString(extension_data);
203 return true;
204 }
205
206 // Given a |cert|, extract the TBSCertificate from this certificate, also 136 // 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, 137 // removing the X.509 extension with OID 1.3.6.1.4.1.11129.2.4.2 (that is,
208 // the embedded SCT) 138 // the embedded SCT)
209 bool ExtractTBSCertWithoutSCTs(CERTCertificate* cert, 139 bool ExtractTBSCertWithoutSCTs(CERTCertificate* cert,
210 std::string* to_be_signed) { 140 std::string* to_be_signed) {
211 SECOidData* oid = SECOID_FindOIDByTag(g_ct_singleton.Get().embedded_oid()); 141 SECOidData* oid = SECOID_FindOIDByTag(g_ct_singleton.Get().embedded_oid());
212 if (!oid) 142 if (!oid)
213 return false; 143 return false;
214 144
215 // This is a giant hack, due to the fact that NSS does not expose a good API 145 // This is a giant hack, due to the fact that NSS does not expose a good API
(...skipping 27 matching lines...) Expand all
243 &tbs_data, 173 &tbs_data,
244 &temp_cert, 174 &temp_cert,
245 SEC_ASN1_GET(CERT_CertificateTemplate)); 175 SEC_ASN1_GET(CERT_CertificateTemplate));
246 if (!result) 176 if (!result)
247 return false; 177 return false;
248 178
249 to_be_signed->assign(reinterpret_cast<char*>(tbs_data.data), tbs_data.len); 179 to_be_signed->assign(reinterpret_cast<char*>(tbs_data.data), tbs_data.len);
250 return true; 180 return true;
251 } 181 }
252 182
253 // The following code is adapted from the NSS OCSP module, in order to expose
254 // the internal structure of an OCSP response.
255
256 // ResponseBytes ::= SEQUENCE {
257 // responseType OBJECT IDENTIFIER,
258 // response OCTET STRING }
259 struct ResponseBytes {
260 SECItem response_type;
261 SECItem der_response;
262 };
263
264 const SEC_ASN1Template kResponseBytesTemplate[] = {
265 { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(ResponseBytes) },
266 { SEC_ASN1_OBJECT_ID, offsetof(ResponseBytes, response_type) },
267 { SEC_ASN1_OCTET_STRING, offsetof(ResponseBytes, der_response) },
268 { 0 }
269 };
270
271 // OCSPResponse ::= SEQUENCE {
272 // responseStatus OCSPResponseStatus,
273 // responseBytes [0] EXPLICIT ResponseBytes OPTIONAL }
274 struct OCSPResponse {
275 SECItem response_status;
276 // This indirection is needed because |response_bytes| is an optional
277 // component and we need a way to determine if it is missing.
278 ResponseBytes* response_bytes;
279 };
280
281 const SEC_ASN1Template kPointerToResponseBytesTemplate[] = {
282 { SEC_ASN1_POINTER, 0, kResponseBytesTemplate }
283 };
284
285 const SEC_ASN1Template kOCSPResponseTemplate[] = {
286 { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(OCSPResponse) },
287 { SEC_ASN1_ENUMERATED, offsetof(OCSPResponse, response_status) },
288 { SEC_ASN1_OPTIONAL | SEC_ASN1_EXPLICIT | SEC_ASN1_CONSTRUCTED |
289 SEC_ASN1_CONTEXT_SPECIFIC | 0, offsetof(OCSPResponse, response_bytes),
290 kPointerToResponseBytesTemplate },
291 { 0 }
292 };
293
294 // CertID ::= SEQUENCE {
295 // hashAlgorithm AlgorithmIdentifier,
296 // issuerNameHash OCTET STRING, -- Hash of Issuer's DN
297 // issuerKeyHash OCTET STRING, -- Hash of Issuers public key
298 // serialNumber CertificateSerialNumber }
299 struct CertID {
300 SECAlgorithmID hash_algorithm;
301 SECItem issuer_name_hash;
302 SECItem issuer_key_hash;
303 SECItem serial_number;
304 };
305
306 const SEC_ASN1Template kCertIDTemplate[] = {
307 { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(CertID) },
308 { SEC_ASN1_INLINE | SEC_ASN1_XTRN, offsetof(CertID, hash_algorithm),
309 SEC_ASN1_SUB(SECOID_AlgorithmIDTemplate) },
310 { SEC_ASN1_OCTET_STRING, offsetof(CertID, issuer_name_hash) },
311 { SEC_ASN1_OCTET_STRING, offsetof(CertID, issuer_key_hash) },
312 { SEC_ASN1_INTEGER, offsetof(CertID, serial_number) },
313 { 0 }
314 };
315
316 // SingleResponse ::= SEQUENCE {
317 // certID CertID,
318 // certStatus CertStatus,
319 // thisUpdate GeneralizedTime,
320 // nextUpdate [0] EXPLICIT GeneralizedTime OPTIONAL,
321 // singleExtensions [1] EXPLICIT Extensions OPTIONAL }
322 struct SingleResponse {
323 CertID cert_id;
324 // The following three fields are not used.
325 SECItem der_cert_status;
326 SECItem this_update;
327 SECItem next_update;
328 CERTCertExtension** single_extensions;
329 };
330
331 const SEC_ASN1Template kSingleResponseTemplate[] = {
332 { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(SingleResponse) },
333 { SEC_ASN1_INLINE, offsetof(SingleResponse, cert_id), kCertIDTemplate },
334 // Really a CHOICE but we make it an ANY because we don't care about the
335 // contents of this field.
336 // TODO(ekasper): use SEC_ASN1_CHOICE.
337 { SEC_ASN1_ANY, offsetof(SingleResponse, der_cert_status) },
338 { SEC_ASN1_GENERALIZED_TIME, offsetof(SingleResponse, this_update) },
339 { SEC_ASN1_OPTIONAL | SEC_ASN1_EXPLICIT |
340 SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_XTRN | 0,
341 offsetof(SingleResponse, next_update),
342 SEC_ASN1_SUB(SEC_GeneralizedTimeTemplate) },
343 { SEC_ASN1_OPTIONAL | SEC_ASN1_EXPLICIT | SEC_ASN1_CONSTRUCTED |
344 SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_XTRN | 1,
345 offsetof(SingleResponse, single_extensions),
346 SEC_ASN1_SUB(CERT_SequenceOfCertExtensionTemplate) },
347 { 0 }
348 };
349
350 // ResponseData ::= SEQUENCE {
351 // version [0] EXPLICIT Version DEFAULT v1,
352 // responderID ResponderID,
353 // producedAt GeneralizedTime,
354 // responses SEQUENCE OF SingleResponse,
355 // responseExtensions [1] EXPLICIT Extensions OPTIONAL }
356 struct ResponseData {
357 // The first three fields are not used.
358 SECItem version;
359 SECItem der_responder_id;
360 SECItem produced_at;
361 SingleResponse** single_responses;
362 // Skip extensions.
363 };
364
365 const SEC_ASN1Template kResponseDataTemplate[] = {
366 { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(ResponseData) },
367 { SEC_ASN1_OPTIONAL | SEC_ASN1_EXPLICIT | SEC_ASN1_CONSTRUCTED |
368 SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_XTRN | 0,
369 offsetof(ResponseData, version), SEC_ASN1_SUB(SEC_IntegerTemplate) },
370 // Really a CHOICE but we make it an ANY because we don't care about the
371 // contents of this field.
372 // TODO(ekasper): use SEC_ASN1_CHOICE.
373 { SEC_ASN1_ANY, offsetof(ResponseData, der_responder_id) },
374 { SEC_ASN1_GENERALIZED_TIME, offsetof(ResponseData, produced_at) },
375 { SEC_ASN1_SEQUENCE_OF, offsetof(ResponseData, single_responses),
376 kSingleResponseTemplate },
377 { SEC_ASN1_SKIP_REST },
378 { 0 }
379 };
380
381 // BasicOCSPResponse ::= SEQUENCE {
382 // tbsResponseData ResponseData,
383 // signatureAlgorithm AlgorithmIdentifier,
384 // signature BIT STRING,
385 // certs [0] EXPLICIT SEQUENCE OF Certificate OPTIONAL }
386 struct BasicOCSPResponse {
387 ResponseData tbs_response_data;
388 // We do not care about the rest.
389 };
390
391 const SEC_ASN1Template kBasicOCSPResponseTemplate[] = {
392 { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(BasicOCSPResponse) },
393 { SEC_ASN1_INLINE, offsetof(BasicOCSPResponse, tbs_response_data),
394 kResponseDataTemplate },
395 { SEC_ASN1_SKIP_REST },
396 { 0 }
397 };
398
399 bool StringEqualToSECItem(const std::string& value1, const SECItem& value2) {
400 if (value1.size() != value2.len)
401 return false;
402 return memcmp(value1.data(), value2.data, value2.len) == 0;
403 }
404
405 // TODO(ekasper): also use the issuer name hash in matching.
406 bool CertIDMatches(const CertID& cert_id,
407 const std::string& serial_number,
408 const std::string& issuer_key_sha1_hash,
409 const std::string& issuer_key_sha256_hash) {
410 if (!StringEqualToSECItem(serial_number, cert_id.serial_number))
411 return false;
412
413 SECOidTag hash_alg = SECOID_FindOIDTag(&cert_id.hash_algorithm.algorithm);
414 switch (hash_alg) {
415 case SEC_OID_SHA1:
416 return StringEqualToSECItem(issuer_key_sha1_hash,
417 cert_id.issuer_key_hash);
418 case SEC_OID_SHA256:
419 return StringEqualToSECItem(issuer_key_sha256_hash,
420 cert_id.issuer_key_hash);
421 default:
422 return false;
423 }
424 }
425
426 } // namespace 183 } // namespace
427 184
428 bool ExtractEmbeddedSCTList(X509Certificate::OSCertHandle cert, 185 bool ExtractEmbeddedSCTList(X509Certificate::OSCertHandle cert,
429 std::string* sct_list) { 186 std::string* sct_list) {
430 DCHECK(cert); 187 DCHECK(cert);
431 188
432 NSSCertWrapper leaf_cert(cert); 189 NSSCertWrapper leaf_cert(cert);
433 if (!leaf_cert.cert) 190 if (!leaf_cert.cert)
434 return false; 191 return false;
435 192
436 return GetCertOctetStringExtension(leaf_cert.cert.get(), 193 return GetOctetStringExtension(
437 g_ct_singleton.Get().embedded_oid(), 194 leaf_cert.cert.get(), g_ct_singleton.Get().embedded_oid(), sct_list);
438 sct_list);
439 } 195 }
440 196
441 bool GetPrecertLogEntry(X509Certificate::OSCertHandle leaf, 197 bool GetPrecertLogEntry(X509Certificate::OSCertHandle leaf,
442 X509Certificate::OSCertHandle issuer, 198 X509Certificate::OSCertHandle issuer,
443 LogEntry* result) { 199 LogEntry* result) {
444 DCHECK(leaf); 200 DCHECK(leaf);
445 DCHECK(issuer); 201 DCHECK(issuer);
446 202
447 NSSCertWrapper leaf_cert(leaf); 203 NSSCertWrapper leaf_cert(leaf);
448 NSSCertWrapper issuer_cert(issuer); 204 NSSCertWrapper issuer_cert(issuer);
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after
506 std::string encoded; 262 std::string encoded;
507 if (!X509Certificate::GetDEREncoded(leaf, &encoded)) 263 if (!X509Certificate::GetDEREncoded(leaf, &encoded))
508 return false; 264 return false;
509 265
510 result->Reset(); 266 result->Reset();
511 result->type = ct::LogEntry::LOG_ENTRY_TYPE_X509; 267 result->type = ct::LogEntry::LOG_ENTRY_TYPE_X509;
512 result->leaf_certificate.swap(encoded); 268 result->leaf_certificate.swap(encoded);
513 return true; 269 return true;
514 } 270 }
515 271
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 crypto::ScopedPLArenaPool arena(PORT_NewArena(DER_DEFAULT_CHUNKSIZE));
522
523 OCSPResponse response;
524 memset(&response, 0, sizeof(response));
525
526 SECItem src = { siBuffer,
527 reinterpret_cast<unsigned char*>(const_cast<char*>(
528 ocsp_response.data())), ocsp_response.size() };
529
530 // |response| will point directly into |src|, so it's not necessary to
531 // free the |response| contents, but they may only be used while |src|
532 // is valid (i.e., in this method).
533 SECStatus rv = SEC_QuickDERDecodeItem(arena.get(), &response,
534 kOCSPResponseTemplate, &src);
535 if (rv != SECSuccess)
536 return false;
537
538 if (!response.response_bytes)
539 return false;
540
541 if (!SECITEM_ItemsAreEqual(&kBasicOCSPResponseOidItem,
542 &response.response_bytes->response_type)) {
543 return false;
544 }
545
546 BasicOCSPResponse basic_response;
547 memset(&basic_response, 0, sizeof(basic_response));
548
549 rv = SEC_QuickDERDecodeItem(arena.get(), &basic_response,
550 kBasicOCSPResponseTemplate,
551 &response.response_bytes->der_response);
552 if (rv != SECSuccess)
553 return false;
554
555 SingleResponse** responses =
556 basic_response.tbs_response_data.single_responses;
557 if (!responses)
558 return false;
559
560 std::string issuer_der;
561 if (!X509Certificate::GetDEREncoded(issuer, &issuer_der))
562 return false;
563
564 base::StringPiece issuer_spki;
565 if (!asn1::ExtractSPKIFromDERCert(issuer_der, &issuer_spki))
566 return false;
567
568 // In OCSP, only the key itself is under hash.
569 base::StringPiece issuer_spk;
570 if (!asn1::ExtractSubjectPublicKeyFromSPKI(issuer_spki, &issuer_spk))
571 return false;
572
573 // ExtractSubjectPublicKey... does not remove the initial octet encoding the
574 // number of unused bits in the ASN.1 BIT STRING so we do it here. For public
575 // keys, the bitstring is in practice always byte-aligned.
576 if (issuer_spk.empty() || issuer_spk[0] != 0)
577 return false;
578 issuer_spk.remove_prefix(1);
579
580 // NSS OCSP lib recognizes SHA1, MD5 and MD2; MD5 and MD2 are dead but
581 // https://bugzilla.mozilla.org/show_bug.cgi?id=663315 will add SHA-256
582 // and SHA-384.
583 // TODO(ekasper): add SHA-384 to crypto/sha2.h and here if it proves
584 // necessary.
585 // TODO(ekasper): only compute the hashes on demand.
586 std::string issuer_key_sha256_hash = crypto::SHA256HashString(issuer_spk);
587 std::string issuer_key_sha1_hash = base::SHA1HashString(
588 issuer_spk.as_string());
589
590 const SingleResponse* match = NULL;
591 for (const SingleResponse* const* resps = responses; *resps; ++resps) {
592 const SingleResponse* resp = *resps;
593 if (CertIDMatches(resp->cert_id, cert_serial_number,
594 issuer_key_sha1_hash, issuer_key_sha256_hash)) {
595 match = resp;
596 break;
597 }
598 }
599
600 if (!match)
601 return false;
602
603 return GetSCTListFromOCSPExtension(arena.get(), match->single_extensions,
604 sct_list);
605 }
606
607 } // namespace ct 272 } // namespace ct
608 273
609 } // namespace net 274 } // namespace net
OLDNEW
« no previous file with comments | « net/cert/ct_objects_extractor.h ('k') | net/cert/ct_objects_extractor_openssl.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698