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