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

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

Issue 92443002: Extract Certificate Transparency SCTs from stapled OCSP responses (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@extract_scts
Patch Set: clean up subs 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
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 <certt.h>
8 #include <secasn1.h> 9 #include <secasn1.h>
10 #include <secasn1t.h>
11 #include <secdert.h>
wtc 2013/12/08 04:52:45 The xxxt.h headers define types. The corresponding
ekasper 2013/12/09 14:17:05 Done. secdert.h is also no longer needed in the la
9 #include <secitem.h> 12 #include <secitem.h>
10 #include <secoid.h> 13 #include <secoid.h>
11 14
12 #include "base/lazy_instance.h" 15 #include "base/lazy_instance.h"
16 #include "base/sha1.h"
13 #include "crypto/scoped_nss_types.h" 17 #include "crypto/scoped_nss_types.h"
14 #include "crypto/sha2.h" 18 #include "crypto/sha2.h"
15 #include "net/cert/asn1_util.h" 19 #include "net/cert/asn1_util.h"
16 #include "net/cert/scoped_nss_types.h" 20 #include "net/cert/scoped_nss_types.h"
17 #include "net/cert/signed_certificate_timestamp.h" 21 #include "net/cert/signed_certificate_timestamp.h"
18 22
19 namespace net { 23 namespace net {
20 24
21 namespace ct { 25 namespace ct {
22 26
23 namespace { 27 namespace {
24 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
25 // Wrapper class to convert a X509Certificate::OSCertHandle directly 35 // Wrapper class to convert a X509Certificate::OSCertHandle directly
26 // into a CERTCertificate* usable with other NSS functions. This is used for 36 // into a CERTCertificate* usable with other NSS functions. This is used for
27 // platforms where X509Certificate::OSCertHandle refers to a different type 37 // platforms where X509Certificate::OSCertHandle refers to a different type
28 // than a CERTCertificate*. 38 // than a CERTCertificate*.
29 struct NSSCertWrapper { 39 struct NSSCertWrapper {
30 explicit NSSCertWrapper(X509Certificate::OSCertHandle cert_handle); 40 explicit NSSCertWrapper(X509Certificate::OSCertHandle cert_handle);
31 ~NSSCertWrapper() {} 41 ~NSSCertWrapper() {}
32 42
33 ScopedCERTCertificate cert; 43 ScopedCERTCertificate cert;
34 }; 44 };
(...skipping 20 matching lines...) Expand all
55 } 65 }
56 66
57 // The wire form of the OID 1.3.6.1.4.1.11129.2.4.2. See Section 3.3 of 67 // The wire form of the OID 1.3.6.1.4.1.11129.2.4.2. See Section 3.3 of
58 // RFC6962. 68 // RFC6962.
59 const unsigned char kEmbeddedSCTOid[] = {0x2B, 0x06, 0x01, 0x04, 0x01, 69 const unsigned char kEmbeddedSCTOid[] = {0x2B, 0x06, 0x01, 0x04, 0x01,
60 0xD6, 0x79, 0x02, 0x04, 0x02}; 70 0xD6, 0x79, 0x02, 0x04, 0x02};
61 const char kEmbeddedSCTDescription[] = 71 const char kEmbeddedSCTDescription[] =
62 "X.509v3 Certificate Transparency Embedded Signed Certificate Timestamp " 72 "X.509v3 Certificate Transparency Embedded Signed Certificate Timestamp "
63 "List"; 73 "List";
64 74
75 // The wire form of the OID 1.3.6.1.4.1.11129.2.4.2. See Section 3.3 of
wtc 2013/12/08 04:52:45 Typo: the OCSP extension OID should be 1.3.6.1.4.1
ekasper 2013/12/09 14:17:05 Done.
76 // RFC6962.
77 const unsigned char kOCSPExtensionOid[] = {0x2B, 0x06, 0x01, 0x04, 0x01, 0xD6,
78 0x79, 0x02, 0x04, 0x05};
wtc 2013/12/08 04:52:45 Nit: it would be nice to fold the previous line be
ekasper 2013/12/09 14:17:05 Done.
79
80 const char kOCSPExtensionDescription[] =
81 "OCSP SingleExtension for X.509v3 Certificate Transparency Signed "
82 "Certificate Timestamp List ";
83
65 // Initializes the necessary NSS internals for use with Certificate 84 // Initializes the necessary NSS internals for use with Certificate
66 // Transparency. 85 // Transparency.
67 class CTInitSingleton { 86 class CTInitSingleton {
68 public: 87 public:
69 SECOidTag embedded_oid() const { return embedded_oid_; } 88 SECOidTag embedded_oid() const { return embedded_oid_; }
89 SECOidTag ocsp_extension_oid() const { return ocsp_extension_oid_; }
70 90
71 private: 91 private:
72 friend struct base::DefaultLazyInstanceTraits<CTInitSingleton>; 92 friend struct base::DefaultLazyInstanceTraits<CTInitSingleton>;
73 93
74 CTInitSingleton() : embedded_oid_(SEC_OID_UNKNOWN) { 94 CTInitSingleton() : embedded_oid_(SEC_OID_UNKNOWN),
95 ocsp_extension_oid_(SEC_OID_UNKNOWN) {
75 embedded_oid_ = RegisterOid( 96 embedded_oid_ = RegisterOid(
76 kEmbeddedSCTOid, sizeof(kEmbeddedSCTOid), kEmbeddedSCTDescription); 97 kEmbeddedSCTOid, sizeof(kEmbeddedSCTOid), kEmbeddedSCTDescription);
98 ocsp_extension_oid_ = RegisterOid(
99 kOCSPExtensionOid, sizeof(kOCSPExtensionOid),
100 kOCSPExtensionDescription);
77 } 101 }
78 102
79 ~CTInitSingleton() {} 103 ~CTInitSingleton() {}
80 104
81 SECOidTag RegisterOid(const unsigned char* oid, 105 SECOidTag RegisterOid(const unsigned char* oid,
82 unsigned int oid_len, 106 unsigned int oid_len,
83 const char* description) { 107 const char* description) {
84 SECOidData oid_data; 108 SECOidData oid_data;
85 oid_data.oid.len = oid_len; 109 oid_data.oid.len = oid_len;
86 oid_data.oid.data = const_cast<unsigned char*>(oid); 110 oid_data.oid.data = const_cast<unsigned char*>(oid);
87 oid_data.offset = SEC_OID_UNKNOWN; 111 oid_data.offset = SEC_OID_UNKNOWN;
88 oid_data.desc = description; 112 oid_data.desc = description;
89 oid_data.mechanism = CKM_INVALID_MECHANISM; 113 oid_data.mechanism = CKM_INVALID_MECHANISM;
90 // Setting this to SUPPORTED_CERT_EXTENSION ensures that if a certificate 114 // Setting this to SUPPORTED_CERT_EXTENSION ensures that if a certificate
91 // contains this extension with the critical bit set, NSS will not reject 115 // contains this extension with the critical bit set, NSS will not reject
92 // it. However, because verification of this extension happens after NSS, 116 // it. However, because verification of this extension happens after NSS,
93 // it is currently left as INVALID_CERT_EXTENSION. 117 // it is currently left as INVALID_CERT_EXTENSION.
wtc 2013/12/08 04:52:45 Nit: this comment doesn't really apply to the OCSP
94 oid_data.supportedExtension = INVALID_CERT_EXTENSION; 118 oid_data.supportedExtension = INVALID_CERT_EXTENSION;
95 119
96 SECOidTag result = SECOID_AddEntry(&oid_data); 120 SECOidTag result = SECOID_AddEntry(&oid_data);
97 CHECK_NE(SEC_OID_UNKNOWN, result); 121 CHECK_NE(SEC_OID_UNKNOWN, result);
98 122
99 return result; 123 return result;
100 } 124 }
101 125
102 SECOidTag embedded_oid_; 126 SECOidTag embedded_oid_;
127 SECOidTag ocsp_extension_oid_;
103 128
104 DISALLOW_COPY_AND_ASSIGN(CTInitSingleton); 129 DISALLOW_COPY_AND_ASSIGN(CTInitSingleton);
105 }; 130 };
106 131
107 base::LazyInstance<CTInitSingleton>::Leaky g_ct_singleton = 132 base::LazyInstance<CTInitSingleton>::Leaky g_ct_singleton =
108 LAZY_INSTANCE_INITIALIZER; 133 LAZY_INSTANCE_INITIALIZER;
109 134
110 // Obtains the data for an X.509v3 certificate extension identified by |oid| 135 // 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, 136 // 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 137 // the certificate, updating |ext_data| to be the extension data after removing
113 // encoding of OCTET STRING. 138 // the DER encoding of OCTET STRING.
114 bool GetOctetStringExtension(CERTCertificate* cert, 139 bool GetCertOctetStringExtension(CERTCertificate* cert,
115 SECOidTag oid, 140 SECOidTag oid,
116 std::string* extension_data) { 141 std::string* extension_data) {
117 SECItem extension; 142 SECItem extension;
118 SECStatus rv = CERT_FindCertExtension(cert, oid, &extension); 143 SECStatus rv = CERT_FindCertExtension(cert, oid, &extension);
119 if (rv != SECSuccess) 144 if (rv != SECSuccess)
120 return false; 145 return false;
121 146
122 base::StringPiece raw_data(reinterpret_cast<char*>(extension.data), 147 base::StringPiece raw_data(reinterpret_cast<char*>(extension.data),
123 extension.len); 148 extension.len);
124 base::StringPiece parsed_data; 149 base::StringPiece parsed_data;
125 if (!asn1::GetElement(&raw_data, asn1::kOCTETSTRING, &parsed_data) || 150 if (!asn1::GetElement(&raw_data, asn1::kOCTETSTRING, &parsed_data) ||
126 raw_data.size() > 0) { // Decoding failure or raw data left 151 raw_data.size() > 0) { // Decoding failure or raw data left
127 rv = SECFailure; 152 rv = SECFailure;
128 } else { 153 } else {
129 parsed_data.CopyToString(extension_data); 154 parsed_data.CopyToString(extension_data);
130 } 155 }
131 156
132 SECITEM_FreeItem(&extension, PR_FALSE); 157 SECITEM_FreeItem(&extension, PR_FALSE);
133 return rv == SECSuccess; 158 return rv == SECSuccess;
134 } 159 }
135 160
161 // NSS offers CERT_FindCertExtension for certificates, but we also need to
162 // to extract extensions from OCSP responses, so we inspect the extensions
163 // manually.
164 //
165 // Obtains the data for an X.509v3 certificate extension identified by |oid|
wtc 2013/12/08 04:52:45 Typo: |oid| => |tag|
ekasper 2013/12/09 14:17:05 This has gone away.
166 // and encoded as an OCTET STRING. Returns true if the extension was found in
167 // |extensions|, updating |ext_data| to be the extension data after removing
wtc 2013/12/08 04:52:45 Typo: |ext_data| => |extension_data|
ekasper 2013/12/09 14:17:05 Done. Sorry for all the typos!
168 // the DER encoding of OCTET STRING.
169 bool GetOctetStringExtension(PLArenaPool* arena,
wtc 2013/12/08 04:52:45 OCTET STRING is trivial to decode. If this functio
ekasper 2013/12/09 14:17:05 I am not supposed to use asn1_util for these input
170 CERTCertExtension** extensions,
wtc 2013/12/08 04:52:45 Nit: this can be const: const CERTCertExtension*
ekasper 2013/12/09 14:17:05 Hm, that's not allowed, but it can be a const CERT
171 SECOidTag tag, std::string* extension_data) {
172 if (!extensions)
173 return false;
174
175 SECOidData* oid = SECOID_FindOIDByTag(tag);
wtc 2013/12/08 04:52:45 If we directly pass the SECItem of oid bytes to th
ekasper 2013/12/09 14:17:05 I've done this for my case (see comment above).
176 if (!oid)
177 return false;
178
179 CERTCertExtension *match = NULL;
wtc 2013/12/08 04:52:45 Nit: search for " *" in this file and move the '*'
ekasper 2013/12/09 14:17:05 Done.
180
181 for (CERTCertExtension** exts = extensions; *exts; ++exts) {
182 CERTCertExtension* ext = *exts;
183 SECComparison result = SECITEM_CompareItem(&oid->oid, &ext->id);
184 if (result == SECEqual) {
wtc 2013/12/08 04:52:45 You can say if (SECITEM_ItemsAreEqual(&oid->oi
ekasper 2013/12/09 14:17:05 Done.
185 match = ext;
186 break;
187 }
188 }
189
190 if (!match)
191 return false;
192
193 SECItem contents;
194 // QuickDER will point to |match|, so we don't have to free |contents|.
195 SECStatus rv = SEC_QuickDERDecodeItem(arena, &contents,
196 SEC_ASN1_GET(SEC_OctetStringTemplate),
197 &match->value);
198 if (rv != SECSuccess)
199 return false;
200
201 base::StringPiece parsed_data(reinterpret_cast<char*>(contents.data),
202 contents.len);
203 parsed_data.CopyToString(extension_data);
204 return true;
205 }
206
207
wtc 2013/12/08 04:52:45 Nit: delete one blank line.
ekasper 2013/12/09 14:17:05 Done.
136 // Given a |cert|, extract the TBSCertificate from this certificate, also 208 // 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, 209 // removing the X.509 extension with OID 1.3.6.1.4.1.11129.2.4.2 (that is,
138 // the embedded SCT) 210 // the embedded SCT)
139 bool ExtractTBSCertWithoutSCTs(CERTCertificate* cert, 211 bool ExtractTBSCertWithoutSCTs(CERTCertificate* cert,
140 std::string* to_be_signed) { 212 std::string* to_be_signed) {
141 SECOidData* oid = SECOID_FindOIDByTag(g_ct_singleton.Get().embedded_oid()); 213 SECOidData* oid = SECOID_FindOIDByTag(g_ct_singleton.Get().embedded_oid());
142 if (!oid) 214 if (!oid)
143 return false; 215 return false;
144 216
145 // This is a giant hack, due to the fact that NSS does not expose a good API 217 // 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, 245 &tbs_data,
174 &temp_cert, 246 &temp_cert,
175 SEC_ASN1_GET(CERT_CertificateTemplate)); 247 SEC_ASN1_GET(CERT_CertificateTemplate));
176 if (!result) 248 if (!result)
177 return false; 249 return false;
178 250
179 to_be_signed->assign(reinterpret_cast<char*>(tbs_data.data), tbs_data.len); 251 to_be_signed->assign(reinterpret_cast<char*>(tbs_data.data), tbs_data.len);
180 return true; 252 return true;
181 } 253 }
182 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 SECItem der_cert_status;
327 SECItem this_update;
328 SECItem next_update;
329 CERTCertExtension **single_extensions;
330 };
331
332 const SEC_ASN1Template kSingleResponseTemplate[] = {
333 { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(SingleResponse) },
334 { SEC_ASN1_INLINE, offsetof(SingleResponse, cert_id), kCertIDTemplate },
335 // ANY because (a) NSS ASN.1 doesn't support automatic CHOICE and
336 // (b) we don't care about the contents of this field anyway.
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 | 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 SECItem version;
358 SECItem der_responder_id;
359 SECItem produced_at;
360 SingleResponse **single_responses;
361 // Skip extensions.
362 };
363
364 const SEC_ASN1Template kResponseDataTemplate[] = {
365 { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(ResponseData) },
366 { SEC_ASN1_OPTIONAL | SEC_ASN1_EXPLICIT | SEC_ASN1_CONSTRUCTED |
367 SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_XTRN | 0,
368 offsetof(ResponseData, version), SEC_ASN1_SUB(SEC_IntegerTemplate) },
369 // ANY because (a) NSS ASN.1 doesn't support automatic CHOICE and
370 // (b) we don't care about the contents of this field anyway.
371 { SEC_ASN1_ANY, offsetof(ResponseData, der_responder_id) },
372 { SEC_ASN1_GENERALIZED_TIME, offsetof(ResponseData, produced_at) },
373 { SEC_ASN1_SEQUENCE_OF, offsetof(ResponseData, single_responses),
374 kSingleResponseTemplate },
375 { SEC_ASN1_SKIP_REST },
376 { 0 }
377 };
378
379 // BasicOCSPResponse ::= SEQUENCE {
380 // tbsResponseData ResponseData,
381 // signatureAlgorithm AlgorithmIdentifier,
382 // signature BIT STRING,
383 // certs [0] EXPLICIT SEQUENCE OF Certificate OPTIONAL }
384 struct BasicOCSPResponse {
385 ResponseData tbs_response_data;
386 // We do not care about the rest.
387 };
388
389 const SEC_ASN1Template kBasicOCSPResponseTemplate[] = {
390 { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(BasicOCSPResponse) },
391 { SEC_ASN1_INLINE, offsetof(BasicOCSPResponse, tbs_response_data),
392 kResponseDataTemplate },
393 { SEC_ASN1_SKIP_REST },
394 { 0 }
395 };
396
397 bool StringEqualToSECItem(const std::string& value1, const SECItem& value2) {
398 if (value1.size() != value2.len)
399 return false;
400 return memcmp(value1.data(), value2.data, value2.len) == 0;
401 }
402
403 bool CertIDsMatch(const std::string& serial_number,
404 const std::string& issuer_key_sha1_hash,
405 const std::string& issuer_key_sha256_hash,
406 const CertID& cert_id) {
407 if (!StringEqualToSECItem(serial_number, cert_id.serial_number))
408 return false;
409
410 SECOidTag hash_alg = SECOID_FindOIDTag(&cert_id.hash_algorithm.algorithm);
411 switch (hash_alg) {
412 case SEC_OID_SHA1:
413 return StringEqualToSECItem(issuer_key_sha1_hash,
414 cert_id.issuer_key_hash);
415 case SEC_OID_SHA256:
416 return StringEqualToSECItem(issuer_key_sha256_hash,
417 cert_id.issuer_key_hash);
418 default:
419 return false;
420 }
421 }
422
183 } // namespace 423 } // namespace
184 424
185 bool ExtractEmbeddedSCTList(X509Certificate::OSCertHandle cert, 425 bool ExtractEmbeddedSCTList(X509Certificate::OSCertHandle cert,
186 std::string* sct_list) { 426 std::string* sct_list) {
187 DCHECK(cert); 427 DCHECK(cert);
188 428
189 NSSCertWrapper leaf_cert(cert); 429 NSSCertWrapper leaf_cert(cert);
190 if (!leaf_cert.cert) 430 if (!leaf_cert.cert)
191 return false; 431 return false;
192 432
193 return GetOctetStringExtension( 433 return GetCertOctetStringExtension(leaf_cert.cert.get(),
194 leaf_cert.cert.get(), g_ct_singleton.Get().embedded_oid(), sct_list); 434 g_ct_singleton.Get().embedded_oid(),
435 sct_list);
195 } 436 }
196 437
197 bool GetPrecertLogEntry(X509Certificate::OSCertHandle leaf, 438 bool GetPrecertLogEntry(X509Certificate::OSCertHandle leaf,
198 X509Certificate::OSCertHandle issuer, 439 X509Certificate::OSCertHandle issuer,
199 LogEntry* result) { 440 LogEntry* result) {
200 DCHECK(leaf); 441 DCHECK(leaf);
201 DCHECK(issuer); 442 DCHECK(issuer);
202 443
203 NSSCertWrapper leaf_cert(leaf); 444 NSSCertWrapper leaf_cert(leaf);
204 NSSCertWrapper issuer_cert(issuer); 445 NSSCertWrapper issuer_cert(issuer);
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after
262 std::string encoded; 503 std::string encoded;
263 if (!X509Certificate::GetDEREncoded(leaf, &encoded)) 504 if (!X509Certificate::GetDEREncoded(leaf, &encoded))
264 return false; 505 return false;
265 506
266 result->Reset(); 507 result->Reset();
267 result->type = ct::LogEntry::LOG_ENTRY_TYPE_X509; 508 result->type = ct::LogEntry::LOG_ENTRY_TYPE_X509;
268 result->leaf_certificate.swap(encoded); 509 result->leaf_certificate.swap(encoded);
269 return true; 510 return true;
270 } 511 }
271 512
513 bool ExtractSCTListFromOCSPResponse(const std::string& cert_serial_number,
514 X509Certificate::OSCertHandle issuer,
515 const std::string& ocsp_response,
516 std::string* sct_list) {
517 DCHECK(issuer);
518 crypto::ScopedPLArenaPool arena(PORT_NewArena(DER_DEFAULT_CHUNKSIZE));
519
520 // QuickDERDecodeItem returns data that points into |src|. This is
521 // ok for us as the decoded items never leave the method scope.
522 SECItem src = { siBuffer,
523 reinterpret_cast<unsigned char*>(const_cast<char*>(
524 ocsp_response.data())), ocsp_response.size() };
525
526 OCSPResponse response;
527 memset(&response, 0, sizeof(response));
528
529 SECStatus rv = SEC_QuickDERDecodeItem(arena.get(), &response,
530 kOCSPResponseTemplate, &src);
531 if (rv != SECSuccess)
532 return false;
533
534 // id-ad-ocsp: 1.3.6.1.5.5.7.48.1.1
535 static const uint8 kBasicOCSPResponseOID[] = { 0x2b, 0x06, 0x01, 0x05, 0x05,
536 0x07, 0x30, 0x01, 0x01 };
537
538 if (!response.response_bytes)
539 return false;
540
541 if (response.response_bytes->response_type.len !=
542 sizeof(kBasicOCSPResponseOID) ||
543 memcmp(response.response_bytes->response_type.data, kBasicOCSPResponseOID,
544 sizeof(kBasicOCSPResponseOID)) != 0) {
545 return false;
546 }
547
548 BasicOCSPResponse basic_response;
549 memset(&basic_response, 0, sizeof(basic_response));
550
551 rv = SEC_QuickDERDecodeItem(arena.get(), &basic_response,
552 kBasicOCSPResponseTemplate,
553 &response.response_bytes->der_response);
554 if (rv != SECSuccess)
555 return false;
556
557 SingleResponse** responses =
558 basic_response.tbs_response_data.single_responses;
559 if (!responses)
560 return false;
561
562 std::string issuer_der;
563 if (!X509Certificate::GetDEREncoded(issuer, &issuer_der))
564 return false;
565
566 base::StringPiece issuer_spki;
567 if (!asn1::ExtractSPKIFromDERCert(issuer_der, &issuer_spki))
568 return false;
569
570 // In OCSP, only the key itself is under hash.
571 base::StringPiece issuer_spk;
572 if (!asn1::ExtractSubjectPublicKeyFromSPKI(issuer_spki, &issuer_spk))
573 return false;
574
575 // ExtractSubjectPublicKey... does not remove the leading pad byte from the
576 // BitString so we do it here. For public keys, the pad byte is in practice
577 // always 0.
578 if (issuer_spk.empty() || issuer_spk[0] != 0)
579 return false;
580 issuer_spk.remove_prefix(1);
581
582 // NSS OCSP lib recognizes SHA1, MD5 and MD2; MD5 and MD2 are dead but
583 // https://bugzilla.mozilla.org/show_bug.cgi?id=663315 will add SHA-256
584 // and SHA-384.
585 // TODO(ekasper): add SHA-384 to crypto/sha2.h and here if it proves
586 // necessary.
587 std::string issuer_key_sha256_hash = crypto::SHA256HashString(issuer_spk);
588 std::string issuer_key_sha1_hash = base::SHA1HashString(
589 issuer_spk.as_string());
590
591 SingleResponse* match = NULL;
592 for (int i = 0; responses[i] != NULL; ++i) {
593 if (CertIDsMatch(cert_serial_number, issuer_key_sha1_hash,
wtc 2013/12/08 04:52:45 With more work, we can compute the issuer key hash
ekasper 2013/12/09 14:17:05 Added a TODO.
594 issuer_key_sha256_hash, responses[i]->cert_id)) {
595 match = responses[i];
596 break;
597 }
598 }
599
600 if (!match)
601 return false;
602
603 return GetOctetStringExtension(arena.get(), match->single_extensions,
604 g_ct_singleton.Get().ocsp_extension_oid(),
605 sct_list);
606 }
607
272 } // namespace ct 608 } // namespace ct
273 609
274 } // namespace net 610 } // namespace net
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698