We started redesigning GpuMemoryBuffer interface to handle multiple buffers [0].
[chromium-blink-merge.git] / net / cert / ct_objects_extractor_openssl.cc
blob80fed58d3de04d7e6b112dbcfc1d99465749932d
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"
7 #include <string.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"
20 #include "net/ssl/scoped_openssl_types.h"
22 namespace net {
24 namespace ct {
26 namespace {
28 void FreeX509_EXTENSIONS(X509_EXTENSIONS* ptr) {
29 sk_X509_EXTENSION_pop_free(ptr, X509_EXTENSION_free);
32 using ScopedX509_EXTENSIONS =
33 crypto::ScopedOpenSSL<X509_EXTENSIONS, FreeX509_EXTENSIONS>;
35 // The wire form of the OID 1.3.6.1.4.1.11129.2.4.2. See Section 3.3 of
36 // RFC6962.
37 const uint8_t kEmbeddedSCTOid[] = {0x2B, 0x06, 0x01, 0x04, 0x01, 0xD6, 0x79,
38 0x02, 0x04, 0x02};
40 // The wire form of the OID 1.3.6.1.4.1.11129.2.4.5 - OCSP SingleExtension for
41 // X.509v3 Certificate Transparency Signed Certificate Timestamp List, see
42 // Section 3.3 of RFC6962.
43 const uint8_t kOCSPExtensionOid[] = {0x2B, 0x06, 0x01, 0x04, 0x01, 0xD6, 0x79,
44 0x02, 0x04, 0x05};
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;
52 ScopedX509 OSCertHandleToOpenSSL(X509Certificate::OSCertHandle os_handle) {
53 #if defined(USE_OPENSSL_CERTS)
54 return ScopedX509(X509Certificate::DupOSCertHandle(os_handle));
55 #else
56 std::string der_encoded;
57 if (!X509Certificate::GetDEREncoded(os_handle, &der_encoded))
58 return ScopedX509();
59 const uint8_t* bytes = reinterpret_cast<const uint8_t*>(der_encoded.data());
60 return ScopedX509(d2i_X509(NULL, &bytes, der_encoded.size()));
61 #endif
64 // Finds the SignedCertificateTimestampList in an extension with OID |oid| in
65 // |x509_exts|. If found, returns true and sets |*out_sct_list| to the encoded
66 // SCT list. |out_sct_list| may be NULL.
67 bool GetSCTListFromX509_EXTENSIONS(const X509_EXTENSIONS* x509_exts,
68 const uint8_t* oid,
69 size_t oid_len,
70 std::string* out_sct_list) {
71 for (size_t i = 0; i < sk_X509_EXTENSION_num(x509_exts); i++) {
72 X509_EXTENSION* x509_ext = sk_X509_EXTENSION_value(x509_exts, i);
73 if (static_cast<size_t>(x509_ext->object->length) == oid_len &&
74 memcmp(x509_ext->object->data, oid, oid_len) == 0) {
75 // The SCT list is an OCTET STRING inside the extension.
76 CBS ext_value, sct_list;
77 CBS_init(&ext_value, x509_ext->value->data, x509_ext->value->length);
78 if (!CBS_get_asn1(&ext_value, &sct_list, CBS_ASN1_OCTETSTRING) ||
79 CBS_len(&ext_value) != 0) {
80 return false;
82 if (out_sct_list) {
83 *out_sct_list = std::string(
84 reinterpret_cast<const char*>(CBS_data(&sct_list)),
85 CBS_len(&sct_list));
87 return true;
90 return false;
93 // Finds the SingleResponse in |responses| which matches |issuer| and
94 // |cert_serial_number|. On success, returns true and sets
95 // |*out_single_response| to the body of the SingleResponse starting at the
96 // |certStatus| field.
97 bool FindMatchingSingleResponse(CBS* responses,
98 X509Certificate::OSCertHandle issuer,
99 const std::string& cert_serial_number,
100 CBS* out_single_response) {
101 std::string issuer_der;
102 if (!X509Certificate::GetDEREncoded(issuer, &issuer_der))
103 return false;
105 base::StringPiece issuer_spki;
106 if (!asn1::ExtractSPKIFromDERCert(issuer_der, &issuer_spki))
107 return false;
109 // In OCSP, only the key itself is under hash.
110 base::StringPiece issuer_spk;
111 if (!asn1::ExtractSubjectPublicKeyFromSPKI(issuer_spki, &issuer_spk))
112 return false;
114 // ExtractSubjectPublicKey... does not remove the initial octet encoding the
115 // number of unused bits in the ASN.1 BIT STRING so we do it here. For public
116 // keys, the bitstring is in practice always byte-aligned.
117 if (issuer_spk.empty() || issuer_spk[0] != 0)
118 return false;
119 issuer_spk.remove_prefix(1);
121 // TODO(ekasper): add SHA-384 to crypto/sha2.h and here if it proves
122 // necessary.
123 // TODO(ekasper): only compute the hashes on demand.
124 std::string issuer_key_sha256_hash = crypto::SHA256HashString(issuer_spk);
125 std::string issuer_key_sha1_hash = base::SHA1HashString(
126 issuer_spk.as_string());
128 while (CBS_len(responses) > 0) {
129 CBS single_response, cert_id;
130 if (!CBS_get_asn1(responses, &single_response, CBS_ASN1_SEQUENCE) ||
131 !CBS_get_asn1(&single_response, &cert_id, CBS_ASN1_SEQUENCE)) {
132 return false;
135 CBS hash_algorithm, hash, serial_number, issuer_name_hash, issuer_key_hash;
136 if (!CBS_get_asn1(&cert_id, &hash_algorithm, CBS_ASN1_SEQUENCE) ||
137 !CBS_get_asn1(&hash_algorithm, &hash, CBS_ASN1_OBJECT) ||
138 !CBS_get_asn1(&cert_id, &issuer_name_hash, CBS_ASN1_OCTETSTRING) ||
139 !CBS_get_asn1(&cert_id, &issuer_key_hash, CBS_ASN1_OCTETSTRING) ||
140 !CBS_get_asn1(&cert_id, &serial_number, CBS_ASN1_INTEGER) ||
141 CBS_len(&cert_id) != 0) {
142 return false;
145 // Check the serial number matches.
146 if (!StringEqualToCBS(cert_serial_number, &serial_number))
147 continue;
149 // Check if the issuer_key_hash matches.
150 // TODO(ekasper): also use the issuer name hash in matching.
151 switch (OBJ_cbs2nid(&hash)) {
152 case NID_sha1:
153 if (StringEqualToCBS(issuer_key_sha1_hash, &issuer_key_hash)) {
154 *out_single_response = single_response;
155 return true;
157 break;
158 case NID_sha256:
159 if (StringEqualToCBS(issuer_key_sha256_hash, &issuer_key_hash)) {
160 *out_single_response = single_response;
161 return true;
163 break;
167 return false;
170 } // namespace
172 bool ExtractEmbeddedSCTList(X509Certificate::OSCertHandle cert,
173 std::string* sct_list) {
174 ScopedX509 x509(OSCertHandleToOpenSSL(cert));
175 if (!x509)
176 return false;
177 X509_EXTENSIONS* x509_exts = x509->cert_info->extensions;
178 if (!x509_exts)
179 return false;
180 return GetSCTListFromX509_EXTENSIONS(
181 x509->cert_info->extensions, kEmbeddedSCTOid, sizeof(kEmbeddedSCTOid),
182 sct_list);
185 bool GetPrecertLogEntry(X509Certificate::OSCertHandle leaf,
186 X509Certificate::OSCertHandle issuer,
187 LogEntry* result) {
188 result->Reset();
190 ScopedX509 leaf_x509(OSCertHandleToOpenSSL(leaf));
191 if (!leaf_x509)
192 return false;
194 // XXX(rsleevi): This check may be overkill, since we should be able to
195 // generate precerts for certs without the extension. For now, just a sanity
196 // check to match the reference implementation.
197 if (!leaf_x509->cert_info->extensions ||
198 !GetSCTListFromX509_EXTENSIONS(leaf_x509->cert_info->extensions,
199 kEmbeddedSCTOid, sizeof(kEmbeddedSCTOid),
200 NULL)) {
201 return false;
204 // The Precertificate log entry is the final certificate's TBSCertificate
205 // without the SCT extension (RFC6962, section 3.2).
206 ScopedX509 leaf_copy(X509_dup(leaf_x509.get()));
207 if (!leaf_copy || !leaf_copy->cert_info->extensions) {
208 NOTREACHED();
209 return false;
211 X509_EXTENSIONS* leaf_copy_exts = leaf_copy->cert_info->extensions;
212 for (size_t i = 0; i < sk_X509_EXTENSION_num(leaf_copy_exts); i++) {
213 X509_EXTENSION* ext = sk_X509_EXTENSION_value(leaf_copy_exts, i);
214 if (static_cast<size_t>(ext->object->length) == sizeof(kEmbeddedSCTOid) &&
215 memcmp(ext->object->data,
216 kEmbeddedSCTOid, sizeof(kEmbeddedSCTOid)) == 0) {
217 X509_EXTENSION_free(sk_X509_EXTENSION_delete(leaf_copy_exts, i));
218 X509_CINF_set_modified(leaf_copy->cert_info);
219 break;
223 std::string to_be_signed;
224 int len = i2d_X509_CINF(leaf_copy->cert_info, NULL);
225 if (len < 0)
226 return false;
227 uint8_t* ptr = reinterpret_cast<uint8_t*>(WriteInto(&to_be_signed, len + 1));
228 if (i2d_X509_CINF(leaf_copy->cert_info, &ptr) < 0)
229 return false;
231 // Extract the issuer's public key.
232 std::string issuer_der;
233 if (!X509Certificate::GetDEREncoded(issuer, &issuer_der))
234 return ScopedX509();
235 base::StringPiece issuer_key;
236 if (!asn1::ExtractSPKIFromDERCert(issuer_der, &issuer_key))
237 return false;
239 // Fill in the LogEntry.
240 result->type = ct::LogEntry::LOG_ENTRY_TYPE_PRECERT;
241 result->tbs_certificate.swap(to_be_signed);
242 crypto::SHA256HashString(issuer_key,
243 result->issuer_key_hash.data,
244 sizeof(result->issuer_key_hash.data));
246 return true;
249 bool GetX509LogEntry(X509Certificate::OSCertHandle leaf, LogEntry* result) {
250 DCHECK(leaf);
252 std::string encoded;
253 if (!X509Certificate::GetDEREncoded(leaf, &encoded))
254 return false;
256 result->Reset();
257 result->type = ct::LogEntry::LOG_ENTRY_TYPE_X509;
258 result->leaf_certificate.swap(encoded);
259 return true;
262 bool ExtractSCTListFromOCSPResponse(X509Certificate::OSCertHandle issuer,
263 const std::string& cert_serial_number,
264 const std::string& ocsp_response,
265 std::string* sct_list) {
266 // The input is an OCSPResponse. See RFC2560, section 4.2.1. The SCT list is
267 // in the extensions field of the SingleResponse which matches the input
268 // certificate.
269 CBS cbs;
270 CBS_init(&cbs,
271 reinterpret_cast<const uint8_t*>(ocsp_response.data()),
272 ocsp_response.size());
274 // Parse down to the ResponseBytes. The ResponseBytes is optional, but if it's
275 // missing, this can't include an SCT list.
276 CBS sequence, response_status, tagged_response_bytes, response_bytes;
277 CBS response_type, response;
278 if (!CBS_get_asn1(&cbs, &sequence, CBS_ASN1_SEQUENCE) ||
279 CBS_len(&cbs) != 0 ||
280 !CBS_get_asn1(&sequence, &response_status, CBS_ASN1_ENUMERATED) ||
281 !CBS_get_asn1(&sequence, &tagged_response_bytes,
282 CBS_ASN1_CONTEXT_SPECIFIC | CBS_ASN1_CONSTRUCTED | 0) ||
283 CBS_len(&sequence) != 0 ||
284 !CBS_get_asn1(&tagged_response_bytes, &response_bytes,
285 CBS_ASN1_SEQUENCE) ||
286 CBS_len(&tagged_response_bytes) != 0 ||
287 !CBS_get_asn1(&response_bytes, &response_type, CBS_ASN1_OBJECT) ||
288 !CBS_get_asn1(&response_bytes, &response, CBS_ASN1_OCTETSTRING) ||
289 CBS_len(&response_bytes) != 0) {
290 return false;
293 // The only relevant ResponseType is id-pkix-ocsp-basic.
294 if (OBJ_cbs2nid(&response_type) != NID_id_pkix_OCSP_basic)
295 return false;
297 // Parse the ResponseData out of the BasicOCSPResponse. Ignore the rest.
298 CBS basic_response, response_data, responses;
299 if (!CBS_get_asn1(&response, &basic_response, CBS_ASN1_SEQUENCE) ||
300 CBS_len(&response) != 0 ||
301 !CBS_get_asn1(&basic_response, &response_data, CBS_ASN1_SEQUENCE)) {
304 // Skip the optional version.
305 const int kVersionTag =
306 CBS_ASN1_CONTEXT_SPECIFIC | CBS_ASN1_CONSTRUCTED | 0;
307 if (CBS_len(&response_data) > 0 &&
308 CBS_data(&response_data)[0] == kVersionTag &&
309 !CBS_get_asn1(&response_data, NULL /* version */, kVersionTag)) {
310 return false;
313 // Extract the list of SingleResponses.
314 if (!CBS_get_any_asn1_element(&response_data,
315 NULL /* responderID */, NULL, NULL) ||
316 !CBS_get_any_asn1_element(&response_data,
317 NULL /* producedAt */, NULL, NULL) ||
318 !CBS_get_asn1(&response_data, &responses, CBS_ASN1_SEQUENCE)) {
319 return false;
322 CBS single_response;
323 if (!FindMatchingSingleResponse(&responses, issuer, cert_serial_number,
324 &single_response)) {
325 return false;
328 // Skip the certStatus and thisUpdate fields.
329 if (!CBS_get_any_asn1_element(&single_response,
330 NULL /* certStatus */, NULL, NULL) ||
331 !CBS_get_any_asn1_element(&single_response,
332 NULL /* thisUpdate */, NULL, NULL)) {
333 return false;
336 const int kNextUpdateTag =
337 CBS_ASN1_CONTEXT_SPECIFIC | CBS_ASN1_CONSTRUCTED | 0;
338 const int kSingleExtensionsTag =
339 CBS_ASN1_CONTEXT_SPECIFIC | CBS_ASN1_CONSTRUCTED | 1;
341 // Skip the optional nextUpdate field.
342 if (CBS_len(&single_response) > 0 &&
343 CBS_data(&single_response)[0] == kNextUpdateTag &&
344 !CBS_get_asn1(&single_response, NULL /* nextUpdate */, kNextUpdateTag)) {
345 return false;
348 CBS extensions;
349 if (!CBS_get_asn1(&single_response, &extensions, kSingleExtensionsTag))
350 return false;
351 const uint8_t* ptr = CBS_data(&extensions);
352 ScopedX509_EXTENSIONS x509_exts(
353 d2i_X509_EXTENSIONS(NULL, &ptr, CBS_len(&extensions)));
354 if (!x509_exts || ptr != CBS_data(&extensions) + CBS_len(&extensions))
355 return false;
357 return GetSCTListFromX509_EXTENSIONS(
358 x509_exts.get(), kOCSPExtensionOid, sizeof(kOCSPExtensionOid), sct_list);
361 } // namespace ct
363 } // namespace net