1 // Copyright 2013 The Chromium Authors
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 <string.h>
8
9 #include "base/hash/sha1.h"
10 #include "base/logging.h"
11 #include "base/strings/string_piece.h"
12 #include "base/strings/string_util.h"
13 #include "crypto/sha2.h"
14 #include "net/cert/asn1_util.h"
15 #include "net/cert/signed_certificate_timestamp.h"
16 #include "net/cert/x509_util.h"
17 #include "third_party/boringssl/src/include/openssl/bytestring.h"
18 #include "third_party/boringssl/src/include/openssl/mem.h"
19
20 namespace net::ct {
21
22 namespace {
23
24 // The wire form of the OID 1.3.6.1.4.1.11129.2.4.2. See Section 3.3 of
25 // RFC6962.
26 const uint8_t kEmbeddedSCTOid[] = {0x2B, 0x06, 0x01, 0x04, 0x01,
27 0xD6, 0x79, 0x02, 0x04, 0x02};
28
29 // The wire form of the OID 1.3.6.1.4.1.11129.2.4.5 - OCSP SingleExtension for
30 // X.509v3 Certificate Transparency Signed Certificate Timestamp List, see
31 // Section 3.3 of RFC6962.
32 const uint8_t kOCSPExtensionOid[] = {0x2B, 0x06, 0x01, 0x04, 0x01,
33 0xD6, 0x79, 0x02, 0x04, 0x05};
34
35 // The wire form of the OID 1.3.6.1.5.5.7.48.1.1. See RFC 6960.
36 const uint8_t kOCSPBasicResponseOid[] = {0x2b, 0x06, 0x01, 0x05, 0x05,
37 0x07, 0x30, 0x01, 0x01};
38
39 // The wire form of the OID 1.3.14.3.2.26.
40 const uint8_t kSHA1Oid[] = {0x2b, 0x0e, 0x03, 0x02, 0x1a};
41
42 // The wire form of the OID 2.16.840.1.101.3.4.2.1.
43 const uint8_t kSHA256Oid[] = {0x60, 0x86, 0x48, 0x01, 0x65,
44 0x03, 0x04, 0x02, 0x01};
45
StringEqualToCBS(const std::string & value1,const CBS * value2)46 bool StringEqualToCBS(const std::string& value1, const CBS* value2) {
47 if (CBS_len(value2) != value1.size())
48 return false;
49 return memcmp(value1.data(), CBS_data(value2), CBS_len(value2)) == 0;
50 }
51
SkipElements(CBS * cbs,int count)52 bool SkipElements(CBS* cbs, int count) {
53 for (int i = 0; i < count; i++) {
54 if (!CBS_get_any_asn1_element(cbs, nullptr, nullptr, nullptr))
55 return false;
56 }
57 return true;
58 }
59
SkipOptionalElement(CBS * cbs,unsigned tag)60 bool SkipOptionalElement(CBS* cbs, unsigned tag) {
61 CBS unused;
62 return !CBS_peek_asn1_tag(cbs, tag) || CBS_get_asn1(cbs, &unused, tag);
63 }
64
65 // Copies all the bytes in |outer| which are before |inner| to |out|. |inner|
66 // must be a subset of |outer|.
CopyBefore(const CBS & outer,const CBS & inner,CBB * out)67 bool CopyBefore(const CBS& outer, const CBS& inner, CBB* out) {
68 CHECK_LE(CBS_data(&outer), CBS_data(&inner));
69 CHECK_LE(CBS_data(&inner) + CBS_len(&inner),
70 CBS_data(&outer) + CBS_len(&outer));
71
72 return !!CBB_add_bytes(out, CBS_data(&outer),
73 CBS_data(&inner) - CBS_data(&outer));
74 }
75
76 // Copies all the bytes in |outer| which are after |inner| to |out|. |inner|
77 // must be a subset of |outer|.
CopyAfter(const CBS & outer,const CBS & inner,CBB * out)78 bool CopyAfter(const CBS& outer, const CBS& inner, CBB* out) {
79 CHECK_LE(CBS_data(&outer), CBS_data(&inner));
80 CHECK_LE(CBS_data(&inner) + CBS_len(&inner),
81 CBS_data(&outer) + CBS_len(&outer));
82
83 return !!CBB_add_bytes(
84 out, CBS_data(&inner) + CBS_len(&inner),
85 CBS_data(&outer) + CBS_len(&outer) - CBS_data(&inner) - CBS_len(&inner));
86 }
87
88 // Skips |tbs_cert|, which must be a TBSCertificate body, to just before the
89 // extensions element.
SkipTBSCertificateToExtensions(CBS * tbs_cert)90 bool SkipTBSCertificateToExtensions(CBS* tbs_cert) {
91 constexpr unsigned kVersionTag =
92 CBS_ASN1_CONTEXT_SPECIFIC | CBS_ASN1_CONSTRUCTED | 0;
93 constexpr unsigned kIssuerUniqueIDTag = CBS_ASN1_CONTEXT_SPECIFIC | 1;
94 constexpr unsigned kSubjectUniqueIDTag = CBS_ASN1_CONTEXT_SPECIFIC | 2;
95 return SkipOptionalElement(tbs_cert, kVersionTag) &&
96 SkipElements(tbs_cert,
97 6 /* serialNumber through subjectPublicKeyInfo */) &&
98 SkipOptionalElement(tbs_cert, kIssuerUniqueIDTag) &&
99 SkipOptionalElement(tbs_cert, kSubjectUniqueIDTag);
100 }
101
102 // Looks for the extension with the specified OID in |extensions|, which must
103 // contain the contents of a SEQUENCE of X.509 extension structures. If found,
104 // returns true and sets |*out| to the full extension element.
FindExtensionElement(const CBS & extensions,const uint8_t * oid,size_t oid_len,CBS * out)105 bool FindExtensionElement(const CBS& extensions,
106 const uint8_t* oid,
107 size_t oid_len,
108 CBS* out) {
109 CBS extensions_copy = extensions;
110 CBS result;
111 CBS_init(&result, nullptr, 0);
112 bool found = false;
113 while (CBS_len(&extensions_copy) > 0) {
114 CBS extension_element;
115 if (!CBS_get_asn1_element(&extensions_copy, &extension_element,
116 CBS_ASN1_SEQUENCE)) {
117 return false;
118 }
119
120 CBS copy = extension_element;
121 CBS extension, extension_oid;
122 if (!CBS_get_asn1(©, &extension, CBS_ASN1_SEQUENCE) ||
123 !CBS_get_asn1(&extension, &extension_oid, CBS_ASN1_OBJECT)) {
124 return false;
125 }
126
127 if (CBS_mem_equal(&extension_oid, oid, oid_len)) {
128 if (found)
129 return false;
130 found = true;
131 result = extension_element;
132 }
133 }
134 if (!found)
135 return false;
136
137 *out = result;
138 return true;
139 }
140
141 // Finds the SignedCertificateTimestampList in an extension with OID |oid| in
142 // |x509_exts|. If found, returns true and sets |*out_sct_list| to the encoded
143 // SCT list.
ParseSCTListFromExtensions(const CBS & extensions,const uint8_t * oid,size_t oid_len,std::string * out_sct_list)144 bool ParseSCTListFromExtensions(const CBS& extensions,
145 const uint8_t* oid,
146 size_t oid_len,
147 std::string* out_sct_list) {
148 CBS extension_element, extension, extension_oid, value, sct_list;
149 if (!FindExtensionElement(extensions, oid, oid_len, &extension_element) ||
150 !CBS_get_asn1(&extension_element, &extension, CBS_ASN1_SEQUENCE) ||
151 !CBS_get_asn1(&extension, &extension_oid, CBS_ASN1_OBJECT) ||
152 // Skip the optional critical element.
153 !SkipOptionalElement(&extension, CBS_ASN1_BOOLEAN) ||
154 // The extension value is stored in an OCTET STRING.
155 !CBS_get_asn1(&extension, &value, CBS_ASN1_OCTETSTRING) ||
156 CBS_len(&extension) != 0 ||
157 // The extension value itself is an OCTET STRING containing the
158 // serialized SCT list.
159 !CBS_get_asn1(&value, &sct_list, CBS_ASN1_OCTETSTRING) ||
160 CBS_len(&value) != 0) {
161 return false;
162 }
163
164 DCHECK(CBS_mem_equal(&extension_oid, oid, oid_len));
165 *out_sct_list = std::string(
166 reinterpret_cast<const char*>(CBS_data(&sct_list)), CBS_len(&sct_list));
167 return true;
168 }
169
170 // Finds the SingleResponse in |responses| which matches |issuer| and
171 // |cert_serial_number|. On success, returns true and sets
172 // |*out_single_response| to the body of the SingleResponse starting at the
173 // |certStatus| field.
FindMatchingSingleResponse(CBS * responses,const CRYPTO_BUFFER * issuer,const std::string & cert_serial_number,CBS * out_single_response)174 bool FindMatchingSingleResponse(CBS* responses,
175 const CRYPTO_BUFFER* issuer,
176 const std::string& cert_serial_number,
177 CBS* out_single_response) {
178 base::StringPiece issuer_spki;
179 if (!asn1::ExtractSPKIFromDERCert(
180 x509_util::CryptoBufferAsStringPiece(issuer), &issuer_spki))
181 return false;
182
183 // In OCSP, only the key itself is under hash.
184 base::StringPiece issuer_spk;
185 if (!asn1::ExtractSubjectPublicKeyFromSPKI(issuer_spki, &issuer_spk))
186 return false;
187
188 // ExtractSubjectPublicKeyFromSPKI does not remove the initial octet encoding
189 // the number of unused bits in the ASN.1 BIT STRING so we do it here. For
190 // public keys, the bitstring is in practice always byte-aligned.
191 if (issuer_spk.empty() || issuer_spk[0] != 0)
192 return false;
193 issuer_spk.remove_prefix(1);
194
195 // TODO(ekasper): add SHA-384 to crypto/sha2.h and here if it proves
196 // necessary.
197 // TODO(ekasper): only compute the hashes on demand.
198 std::string issuer_key_sha256_hash = crypto::SHA256HashString(issuer_spk);
199 std::string issuer_key_sha1_hash =
200 base::SHA1HashString(std::string(issuer_spk));
201
202 while (CBS_len(responses) > 0) {
203 CBS single_response, cert_id;
204 if (!CBS_get_asn1(responses, &single_response, CBS_ASN1_SEQUENCE) ||
205 !CBS_get_asn1(&single_response, &cert_id, CBS_ASN1_SEQUENCE)) {
206 return false;
207 }
208
209 CBS hash_algorithm, hash, serial_number, issuer_name_hash, issuer_key_hash;
210 if (!CBS_get_asn1(&cert_id, &hash_algorithm, CBS_ASN1_SEQUENCE) ||
211 !CBS_get_asn1(&hash_algorithm, &hash, CBS_ASN1_OBJECT) ||
212 !CBS_get_asn1(&cert_id, &issuer_name_hash, CBS_ASN1_OCTETSTRING) ||
213 !CBS_get_asn1(&cert_id, &issuer_key_hash, CBS_ASN1_OCTETSTRING) ||
214 !CBS_get_asn1(&cert_id, &serial_number, CBS_ASN1_INTEGER) ||
215 CBS_len(&cert_id) != 0) {
216 return false;
217 }
218
219 // Check the serial number matches.
220 if (!StringEqualToCBS(cert_serial_number, &serial_number))
221 continue;
222
223 // Check if the issuer_key_hash matches.
224 // TODO(ekasper): also use the issuer name hash in matching.
225 if (CBS_mem_equal(&hash, kSHA1Oid, sizeof(kSHA1Oid))) {
226 if (StringEqualToCBS(issuer_key_sha1_hash, &issuer_key_hash)) {
227 *out_single_response = single_response;
228 return true;
229 }
230 } else if (CBS_mem_equal(&hash, kSHA256Oid, sizeof(kSHA256Oid))) {
231 if (StringEqualToCBS(issuer_key_sha256_hash, &issuer_key_hash)) {
232 *out_single_response = single_response;
233 return true;
234 }
235 }
236 }
237
238 return false;
239 }
240
241 } // namespace
242
ExtractEmbeddedSCTList(const CRYPTO_BUFFER * cert,std::string * sct_list)243 bool ExtractEmbeddedSCTList(const CRYPTO_BUFFER* cert, std::string* sct_list) {
244 CBS cert_cbs;
245 CBS_init(&cert_cbs, CRYPTO_BUFFER_data(cert), CRYPTO_BUFFER_len(cert));
246 CBS cert_body, tbs_cert, extensions_wrap, extensions;
247 if (!CBS_get_asn1(&cert_cbs, &cert_body, CBS_ASN1_SEQUENCE) ||
248 CBS_len(&cert_cbs) != 0 ||
249 !CBS_get_asn1(&cert_body, &tbs_cert, CBS_ASN1_SEQUENCE) ||
250 !SkipTBSCertificateToExtensions(&tbs_cert) ||
251 // Extract the extensions list.
252 !CBS_get_asn1(&tbs_cert, &extensions_wrap,
253 CBS_ASN1_CONTEXT_SPECIFIC | CBS_ASN1_CONSTRUCTED | 3) ||
254 !CBS_get_asn1(&extensions_wrap, &extensions, CBS_ASN1_SEQUENCE) ||
255 CBS_len(&extensions_wrap) != 0 || CBS_len(&tbs_cert) != 0) {
256 return false;
257 }
258
259 return ParseSCTListFromExtensions(extensions, kEmbeddedSCTOid,
260 sizeof(kEmbeddedSCTOid), sct_list);
261 }
262
GetPrecertSignedEntry(const CRYPTO_BUFFER * leaf,const CRYPTO_BUFFER * issuer,SignedEntryData * result)263 bool GetPrecertSignedEntry(const CRYPTO_BUFFER* leaf,
264 const CRYPTO_BUFFER* issuer,
265 SignedEntryData* result) {
266 result->Reset();
267
268 // Parse the TBSCertificate.
269 CBS cert_cbs;
270 CBS_init(&cert_cbs, CRYPTO_BUFFER_data(leaf), CRYPTO_BUFFER_len(leaf));
271 CBS cert_body, tbs_cert;
272 if (!CBS_get_asn1(&cert_cbs, &cert_body, CBS_ASN1_SEQUENCE) ||
273 CBS_len(&cert_cbs) != 0 ||
274 !CBS_get_asn1(&cert_body, &tbs_cert, CBS_ASN1_SEQUENCE)) {
275 return false;
276 }
277
278 CBS tbs_cert_copy = tbs_cert;
279 if (!SkipTBSCertificateToExtensions(&tbs_cert))
280 return false;
281
282 // Start filling in a new TBSCertificate. Copy everything parsed or skipped
283 // so far to the |new_tbs_cert|.
284 bssl::ScopedCBB cbb;
285 CBB new_tbs_cert;
286 if (!CBB_init(cbb.get(), CBS_len(&tbs_cert_copy)) ||
287 !CBB_add_asn1(cbb.get(), &new_tbs_cert, CBS_ASN1_SEQUENCE) ||
288 !CopyBefore(tbs_cert_copy, tbs_cert, &new_tbs_cert)) {
289 return false;
290 }
291
292 // Parse the extensions list and find the SCT extension.
293 //
294 // XXX(rsleevi): We could generate precerts for certs without the extension
295 // by leaving the TBSCertificate as-is. The reference implementation does not
296 // do this.
297 constexpr unsigned kExtensionsTag =
298 CBS_ASN1_CONTEXT_SPECIFIC | CBS_ASN1_CONSTRUCTED | 3;
299 CBS extensions_wrap, extensions, sct_extension;
300 if (!CBS_get_asn1(&tbs_cert, &extensions_wrap, kExtensionsTag) ||
301 !CBS_get_asn1(&extensions_wrap, &extensions, CBS_ASN1_SEQUENCE) ||
302 CBS_len(&extensions_wrap) != 0 || CBS_len(&tbs_cert) != 0 ||
303 !FindExtensionElement(extensions, kEmbeddedSCTOid,
304 sizeof(kEmbeddedSCTOid), &sct_extension)) {
305 return false;
306 }
307
308 // Add extensions to the TBSCertificate. Copy all extensions except the
309 // embedded SCT extension.
310 CBB new_extensions_wrap, new_extensions;
311 if (!CBB_add_asn1(&new_tbs_cert, &new_extensions_wrap, kExtensionsTag) ||
312 !CBB_add_asn1(&new_extensions_wrap, &new_extensions, CBS_ASN1_SEQUENCE) ||
313 !CopyBefore(extensions, sct_extension, &new_extensions) ||
314 !CopyAfter(extensions, sct_extension, &new_extensions)) {
315 return false;
316 }
317
318 uint8_t* new_tbs_cert_der;
319 size_t new_tbs_cert_len;
320 if (!CBB_finish(cbb.get(), &new_tbs_cert_der, &new_tbs_cert_len))
321 return false;
322 bssl::UniquePtr<uint8_t> scoped_new_tbs_cert_der(new_tbs_cert_der);
323
324 // Extract the issuer's public key.
325 base::StringPiece issuer_key;
326 if (!asn1::ExtractSPKIFromDERCert(
327 x509_util::CryptoBufferAsStringPiece(issuer), &issuer_key)) {
328 return false;
329 }
330
331 // Fill in the SignedEntryData.
332 result->type = ct::SignedEntryData::LOG_ENTRY_TYPE_PRECERT;
333 result->tbs_certificate.assign(
334 reinterpret_cast<const char*>(new_tbs_cert_der), new_tbs_cert_len);
335 crypto::SHA256HashString(issuer_key, result->issuer_key_hash.data,
336 sizeof(result->issuer_key_hash.data));
337
338 return true;
339 }
340
GetX509SignedEntry(const CRYPTO_BUFFER * leaf,SignedEntryData * result)341 bool GetX509SignedEntry(const CRYPTO_BUFFER* leaf, SignedEntryData* result) {
342 DCHECK(leaf);
343
344 result->Reset();
345 result->type = ct::SignedEntryData::LOG_ENTRY_TYPE_X509;
346 result->leaf_certificate =
347 std::string(x509_util::CryptoBufferAsStringPiece(leaf));
348 return true;
349 }
350
ExtractSCTListFromOCSPResponse(const CRYPTO_BUFFER * issuer,const std::string & cert_serial_number,base::StringPiece ocsp_response,std::string * sct_list)351 bool ExtractSCTListFromOCSPResponse(const CRYPTO_BUFFER* issuer,
352 const std::string& cert_serial_number,
353 base::StringPiece ocsp_response,
354 std::string* sct_list) {
355 // The input is an OCSPResponse. See RFC2560, section 4.2.1. The SCT list is
356 // in the extensions field of the SingleResponse which matches the input
357 // certificate.
358 CBS cbs;
359 CBS_init(&cbs, reinterpret_cast<const uint8_t*>(ocsp_response.data()),
360 ocsp_response.size());
361
362 // Parse down to the ResponseBytes. The ResponseBytes is optional, but if it's
363 // missing, this can't include an SCT list.
364 CBS sequence, tagged_response_bytes, response_bytes, response_type, response;
365 if (!CBS_get_asn1(&cbs, &sequence, CBS_ASN1_SEQUENCE) || CBS_len(&cbs) != 0 ||
366 !SkipElements(&sequence, 1 /* responseStatus */) ||
367 !CBS_get_asn1(&sequence, &tagged_response_bytes,
368 CBS_ASN1_CONTEXT_SPECIFIC | CBS_ASN1_CONSTRUCTED | 0) ||
369 CBS_len(&sequence) != 0 ||
370 !CBS_get_asn1(&tagged_response_bytes, &response_bytes,
371 CBS_ASN1_SEQUENCE) ||
372 CBS_len(&tagged_response_bytes) != 0 ||
373 !CBS_get_asn1(&response_bytes, &response_type, CBS_ASN1_OBJECT) ||
374 !CBS_get_asn1(&response_bytes, &response, CBS_ASN1_OCTETSTRING) ||
375 CBS_len(&response_bytes) != 0) {
376 return false;
377 }
378
379 // The only relevant ResponseType is id-pkix-ocsp-basic.
380 if (!CBS_mem_equal(&response_type, kOCSPBasicResponseOid,
381 sizeof(kOCSPBasicResponseOid))) {
382 return false;
383 }
384
385 // Parse the ResponseData out of the BasicOCSPResponse. Ignore the rest.
386 constexpr unsigned kVersionTag =
387 CBS_ASN1_CONTEXT_SPECIFIC | CBS_ASN1_CONSTRUCTED | 0;
388 CBS basic_response, response_data, responses;
389 if (!CBS_get_asn1(&response, &basic_response, CBS_ASN1_SEQUENCE) ||
390 CBS_len(&response) != 0 ||
391 !CBS_get_asn1(&basic_response, &response_data, CBS_ASN1_SEQUENCE)) {
392 return false;
393 }
394
395 // Extract the list of SingleResponses from the ResponseData.
396 if (!SkipOptionalElement(&response_data, kVersionTag) ||
397 !SkipElements(&response_data, 2 /* responderID, producedAt */) ||
398 !CBS_get_asn1(&response_data, &responses, CBS_ASN1_SEQUENCE)) {
399 return false;
400 }
401
402 CBS single_response;
403 if (!FindMatchingSingleResponse(&responses, issuer, cert_serial_number,
404 &single_response)) {
405 return false;
406 }
407
408 // Parse the extensions out of the SingleResponse.
409 constexpr unsigned kNextUpdateTag =
410 CBS_ASN1_CONTEXT_SPECIFIC | CBS_ASN1_CONSTRUCTED | 0;
411 constexpr unsigned kSingleExtensionsTag =
412 CBS_ASN1_CONTEXT_SPECIFIC | CBS_ASN1_CONSTRUCTED | 1;
413 CBS extensions_wrap, extensions;
414 if (!SkipElements(&single_response, 2 /* certStatus, thisUpdate */) ||
415 !SkipOptionalElement(&single_response, kNextUpdateTag) ||
416 !CBS_get_asn1(&single_response, &extensions_wrap, kSingleExtensionsTag) ||
417 !CBS_get_asn1(&extensions_wrap, &extensions, CBS_ASN1_SEQUENCE) ||
418 CBS_len(&extensions_wrap) != 0) {
419 return false;
420 }
421
422 return ParseSCTListFromExtensions(extensions, kOCSPExtensionOid,
423 sizeof(kOCSPExtensionOid), sct_list);
424 }
425
426 } // namespace net::ct
427