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

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

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