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
3 // found in the LICENSE file.
5 #include "net/cert/ct_objects_extractor.h"
9 #include <openssl/bytestring.h>
10 #include <openssl/obj.h>
11 #include <openssl/x509.h>
13 #include "base/logging.h"
14 #include "base/sha1.h"
15 #include "base/strings/string_util.h"
16 #include "crypto/scoped_openssl_types.h"
17 #include "crypto/sha2.h"
18 #include "net/cert/asn1_util.h"
19 #include "net/cert/signed_certificate_timestamp.h"
27 typedef crypto::ScopedOpenSSL
<X509
, X509_free
>::Type ScopedX509
;
29 void FreeX509_EXTENSIONS(X509_EXTENSIONS
* ptr
) {
30 sk_X509_EXTENSION_pop_free(ptr
, X509_EXTENSION_free
);
33 typedef crypto::ScopedOpenSSL
<X509_EXTENSIONS
, FreeX509_EXTENSIONS
>::Type
34 ScopedX509_EXTENSIONS
;
36 // The wire form of the OID 1.3.6.1.4.1.11129.2.4.2. See Section 3.3 of
38 const uint8_t kEmbeddedSCTOid
[] = {0x2B, 0x06, 0x01, 0x04, 0x01, 0xD6, 0x79,
41 // The wire form of the OID 1.3.6.1.4.1.11129.2.4.5 - OCSP SingleExtension for
42 // X.509v3 Certificate Transparency Signed Certificate Timestamp List, see
43 // Section 3.3 of RFC6962.
44 const uint8_t kOCSPExtensionOid
[] = {0x2B, 0x06, 0x01, 0x04, 0x01, 0xD6, 0x79,
47 bool StringEqualToCBS(const std::string
& value1
, const CBS
* value2
) {
48 if (CBS_len(value2
) != value1
.size())
50 return memcmp(value1
.data(), CBS_data(value2
), CBS_len(value2
)) == 0;
53 ScopedX509
OSCertHandleToOpenSSL(X509Certificate::OSCertHandle os_handle
) {
54 #if defined(USE_OPENSSL_CERTS)
55 return ScopedX509(X509Certificate::DupOSCertHandle(os_handle
));
57 std::string der_encoded
;
58 if (!X509Certificate::GetDEREncoded(os_handle
, &der_encoded
))
60 const uint8_t* bytes
= reinterpret_cast<const uint8_t*>(der_encoded
.data());
61 return ScopedX509(d2i_X509(NULL
, &bytes
, der_encoded
.size()));
65 // Finds the SignedCertificateTimestampList in an extension with OID |oid| in
66 // |x509_exts|. If found, returns true and sets |*out_sct_list| to the encoded
67 // SCT list. |out_sct_list| may be NULL.
68 bool GetSCTListFromX509_EXTENSIONS(const X509_EXTENSIONS
* x509_exts
,
71 std::string
* out_sct_list
) {
72 for (size_t i
= 0; i
< sk_X509_EXTENSION_num(x509_exts
); i
++) {
73 X509_EXTENSION
* x509_ext
= sk_X509_EXTENSION_value(x509_exts
, i
);
74 if (static_cast<size_t>(x509_ext
->object
->length
) == oid_len
&&
75 memcmp(x509_ext
->object
->data
, oid
, oid_len
) == 0) {
76 // The SCT list is an OCTET STRING inside the extension.
77 CBS ext_value
, sct_list
;
78 CBS_init(&ext_value
, x509_ext
->value
->data
, x509_ext
->value
->length
);
79 if (!CBS_get_asn1(&ext_value
, &sct_list
, CBS_ASN1_OCTETSTRING
) ||
80 CBS_len(&ext_value
) != 0) {
84 *out_sct_list
= std::string(
85 reinterpret_cast<const char*>(CBS_data(&sct_list
)),
94 // Finds the SingleResponse in |responses| which matches |issuer| and
95 // |cert_serial_number|. On success, returns true and sets
96 // |*out_single_response| to the body of the SingleResponse starting at the
97 // |certStatus| field.
98 bool FindMatchingSingleResponse(CBS
* responses
,
99 X509Certificate::OSCertHandle issuer
,
100 const std::string
& cert_serial_number
,
101 CBS
* out_single_response
) {
102 std::string issuer_der
;
103 if (!X509Certificate::GetDEREncoded(issuer
, &issuer_der
))
106 base::StringPiece issuer_spki
;
107 if (!asn1::ExtractSPKIFromDERCert(issuer_der
, &issuer_spki
))
110 // In OCSP, only the key itself is under hash.
111 base::StringPiece issuer_spk
;
112 if (!asn1::ExtractSubjectPublicKeyFromSPKI(issuer_spki
, &issuer_spk
))
115 // ExtractSubjectPublicKey... does not remove the initial octet encoding the
116 // number of unused bits in the ASN.1 BIT STRING so we do it here. For public
117 // keys, the bitstring is in practice always byte-aligned.
118 if (issuer_spk
.empty() || issuer_spk
[0] != 0)
120 issuer_spk
.remove_prefix(1);
122 // TODO(ekasper): add SHA-384 to crypto/sha2.h and here if it proves
124 // TODO(ekasper): only compute the hashes on demand.
125 std::string issuer_key_sha256_hash
= crypto::SHA256HashString(issuer_spk
);
126 std::string issuer_key_sha1_hash
= base::SHA1HashString(
127 issuer_spk
.as_string());
129 while (CBS_len(responses
) > 0) {
130 CBS single_response
, cert_id
;
131 if (!CBS_get_asn1(responses
, &single_response
, CBS_ASN1_SEQUENCE
) ||
132 !CBS_get_asn1(&single_response
, &cert_id
, CBS_ASN1_SEQUENCE
)) {
136 CBS hash_algorithm
, hash
, serial_number
, issuer_name_hash
, issuer_key_hash
;
137 if (!CBS_get_asn1(&cert_id
, &hash_algorithm
, CBS_ASN1_SEQUENCE
) ||
138 !CBS_get_asn1(&hash_algorithm
, &hash
, CBS_ASN1_OBJECT
) ||
139 !CBS_get_asn1(&cert_id
, &issuer_name_hash
, CBS_ASN1_OCTETSTRING
) ||
140 !CBS_get_asn1(&cert_id
, &issuer_key_hash
, CBS_ASN1_OCTETSTRING
) ||
141 !CBS_get_asn1(&cert_id
, &serial_number
, CBS_ASN1_INTEGER
) ||
142 CBS_len(&cert_id
) != 0) {
146 // Check the serial number matches.
147 if (!StringEqualToCBS(cert_serial_number
, &serial_number
))
150 // Check if the issuer_key_hash matches.
151 // TODO(ekasper): also use the issuer name hash in matching.
152 switch (OBJ_cbs2nid(&hash
)) {
154 if (StringEqualToCBS(issuer_key_sha1_hash
, &issuer_key_hash
)) {
155 *out_single_response
= single_response
;
160 if (StringEqualToCBS(issuer_key_sha256_hash
, &issuer_key_hash
)) {
161 *out_single_response
= single_response
;
173 bool ExtractEmbeddedSCTList(X509Certificate::OSCertHandle cert
,
174 std::string
* sct_list
) {
175 ScopedX509
x509(OSCertHandleToOpenSSL(cert
));
178 X509_EXTENSIONS
* x509_exts
= x509
->cert_info
->extensions
;
181 return GetSCTListFromX509_EXTENSIONS(
182 x509
->cert_info
->extensions
, kEmbeddedSCTOid
, sizeof(kEmbeddedSCTOid
),
186 bool GetPrecertLogEntry(X509Certificate::OSCertHandle leaf
,
187 X509Certificate::OSCertHandle issuer
,
191 ScopedX509
leaf_x509(OSCertHandleToOpenSSL(leaf
));
195 // XXX(rsleevi): This check may be overkill, since we should be able to
196 // generate precerts for certs without the extension. For now, just a sanity
197 // check to match the reference implementation.
198 if (!leaf_x509
->cert_info
->extensions
||
199 !GetSCTListFromX509_EXTENSIONS(leaf_x509
->cert_info
->extensions
,
200 kEmbeddedSCTOid
, sizeof(kEmbeddedSCTOid
),
205 // The Precertificate log entry is the final certificate's TBSCertificate
206 // without the SCT extension (RFC6962, section 3.2).
207 ScopedX509
leaf_copy(X509_dup(leaf_x509
.get()));
208 if (!leaf_copy
|| !leaf_copy
->cert_info
->extensions
) {
212 X509_EXTENSIONS
* leaf_copy_exts
= leaf_copy
->cert_info
->extensions
;
213 for (size_t i
= 0; i
< sk_X509_EXTENSION_num(leaf_copy_exts
); i
++) {
214 X509_EXTENSION
* ext
= sk_X509_EXTENSION_value(leaf_copy_exts
, i
);
215 if (static_cast<size_t>(ext
->object
->length
) == sizeof(kEmbeddedSCTOid
) &&
216 memcmp(ext
->object
->data
,
217 kEmbeddedSCTOid
, sizeof(kEmbeddedSCTOid
)) == 0) {
218 X509_EXTENSION_free(sk_X509_EXTENSION_delete(leaf_copy_exts
, i
));
219 X509_CINF_set_modified(leaf_copy
->cert_info
);
224 std::string to_be_signed
;
225 int len
= i2d_X509_CINF(leaf_copy
->cert_info
, NULL
);
228 uint8_t* ptr
= reinterpret_cast<uint8_t*>(WriteInto(&to_be_signed
, len
+ 1));
229 if (i2d_X509_CINF(leaf_copy
->cert_info
, &ptr
) < 0)
232 // Extract the issuer's public key.
233 std::string issuer_der
;
234 if (!X509Certificate::GetDEREncoded(issuer
, &issuer_der
))
236 base::StringPiece issuer_key
;
237 if (!asn1::ExtractSPKIFromDERCert(issuer_der
, &issuer_key
))
240 // Fill in the LogEntry.
241 result
->type
= ct::LogEntry::LOG_ENTRY_TYPE_PRECERT
;
242 result
->tbs_certificate
.swap(to_be_signed
);
243 crypto::SHA256HashString(issuer_key
,
244 result
->issuer_key_hash
.data
,
245 sizeof(result
->issuer_key_hash
.data
));
250 bool GetX509LogEntry(X509Certificate::OSCertHandle leaf
, LogEntry
* result
) {
254 if (!X509Certificate::GetDEREncoded(leaf
, &encoded
))
258 result
->type
= ct::LogEntry::LOG_ENTRY_TYPE_X509
;
259 result
->leaf_certificate
.swap(encoded
);
263 bool ExtractSCTListFromOCSPResponse(X509Certificate::OSCertHandle issuer
,
264 const std::string
& cert_serial_number
,
265 const std::string
& ocsp_response
,
266 std::string
* sct_list
) {
267 // The input is an OCSPResponse. See RFC2560, section 4.2.1. The SCT list is
268 // in the extensions field of the SingleResponse which matches the input
272 reinterpret_cast<const uint8_t*>(ocsp_response
.data()),
273 ocsp_response
.size());
275 // Parse down to the ResponseBytes. The ResponseBytes is optional, but if it's
276 // missing, this can't include an SCT list.
277 CBS sequence
, response_status
, tagged_response_bytes
, response_bytes
;
278 CBS response_type
, response
;
279 if (!CBS_get_asn1(&cbs
, &sequence
, CBS_ASN1_SEQUENCE
) ||
280 CBS_len(&cbs
) != 0 ||
281 !CBS_get_asn1(&sequence
, &response_status
, CBS_ASN1_ENUMERATED
) ||
282 !CBS_get_asn1(&sequence
, &tagged_response_bytes
,
283 CBS_ASN1_CONTEXT_SPECIFIC
| CBS_ASN1_CONSTRUCTED
| 0) ||
284 CBS_len(&sequence
) != 0 ||
285 !CBS_get_asn1(&tagged_response_bytes
, &response_bytes
,
286 CBS_ASN1_SEQUENCE
) ||
287 CBS_len(&tagged_response_bytes
) != 0 ||
288 !CBS_get_asn1(&response_bytes
, &response_type
, CBS_ASN1_OBJECT
) ||
289 !CBS_get_asn1(&response_bytes
, &response
, CBS_ASN1_OCTETSTRING
) ||
290 CBS_len(&response_bytes
) != 0) {
294 // The only relevant ResponseType is id-pkix-ocsp-basic.
295 if (OBJ_cbs2nid(&response_type
) != NID_id_pkix_OCSP_basic
)
298 // Parse the ResponseData out of the BasicOCSPResponse. Ignore the rest.
299 CBS basic_response
, response_data
, responses
;
300 if (!CBS_get_asn1(&response
, &basic_response
, CBS_ASN1_SEQUENCE
) ||
301 CBS_len(&response
) != 0 ||
302 !CBS_get_asn1(&basic_response
, &response_data
, CBS_ASN1_SEQUENCE
)) {
305 // Skip the optional version.
306 const int kVersionTag
=
307 CBS_ASN1_CONTEXT_SPECIFIC
| CBS_ASN1_CONSTRUCTED
| 0;
308 if (CBS_len(&response_data
) > 0 &&
309 CBS_data(&response_data
)[0] == kVersionTag
&&
310 !CBS_get_asn1(&response_data
, NULL
/* version */, kVersionTag
)) {
314 // Extract the list of SingleResponses.
315 if (!CBS_get_any_asn1_element(&response_data
,
316 NULL
/* responderID */, NULL
, NULL
) ||
317 !CBS_get_any_asn1_element(&response_data
,
318 NULL
/* producedAt */, NULL
, NULL
) ||
319 !CBS_get_asn1(&response_data
, &responses
, CBS_ASN1_SEQUENCE
)) {
324 if (!FindMatchingSingleResponse(&responses
, issuer
, cert_serial_number
,
329 // Skip the certStatus and thisUpdate fields.
330 if (!CBS_get_any_asn1_element(&single_response
,
331 NULL
/* certStatus */, NULL
, NULL
) ||
332 !CBS_get_any_asn1_element(&single_response
,
333 NULL
/* thisUpdate */, NULL
, NULL
)) {
337 const int kNextUpdateTag
=
338 CBS_ASN1_CONTEXT_SPECIFIC
| CBS_ASN1_CONSTRUCTED
| 0;
339 const int kSingleExtensionsTag
=
340 CBS_ASN1_CONTEXT_SPECIFIC
| CBS_ASN1_CONSTRUCTED
| 1;
342 // Skip the optional nextUpdate field.
343 if (CBS_len(&single_response
) > 0 &&
344 CBS_data(&single_response
)[0] == kNextUpdateTag
&&
345 !CBS_get_asn1(&single_response
, NULL
/* nextUpdate */, kNextUpdateTag
)) {
350 if (!CBS_get_asn1(&single_response
, &extensions
, kSingleExtensionsTag
))
352 const uint8_t* ptr
= CBS_data(&extensions
);
353 ScopedX509_EXTENSIONS
x509_exts(
354 d2i_X509_EXTENSIONS(NULL
, &ptr
, CBS_len(&extensions
)));
355 if (!x509_exts
|| ptr
!= CBS_data(&extensions
) + CBS_len(&extensions
))
358 return GetSCTListFromX509_EXTENSIONS(
359 x509_exts
.get(), kOCSPExtensionOid
, sizeof(kOCSPExtensionOid
), sct_list
);