1 // Copyright (c) 2012 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/x509_util_openssl.h"
8 #include <openssl/asn1.h>
10 #include "base/lazy_instance.h"
11 #include "base/logging.h"
12 #include "base/strings/string_piece.h"
13 #include "base/strings/string_util.h"
14 #include "crypto/ec_private_key.h"
15 #include "crypto/openssl_util.h"
16 #include "crypto/rsa_private_key.h"
17 #include "crypto/scoped_openssl_types.h"
18 #include "net/cert/x509_cert_types.h"
19 #include "net/cert/x509_util.h"
25 typedef crypto::ScopedOpenSSL
<ASN1_INTEGER
, ASN1_INTEGER_free
>::Type
27 typedef crypto::ScopedOpenSSL
<ASN1_OCTET_STRING
, ASN1_OCTET_STRING_free
>::Type
28 ScopedASN1_OCTET_STRING
;
29 typedef crypto::ScopedOpenSSL
<ASN1_STRING
, ASN1_STRING_free
>::Type
31 typedef crypto::ScopedOpenSSL
<ASN1_TIME
, ASN1_TIME_free
>::Type ScopedASN1_TIME
;
32 typedef crypto::ScopedOpenSSL
<X509
, X509_free
>::Type ScopedX509
;
33 typedef crypto::ScopedOpenSSL
<X509_EXTENSION
, X509_EXTENSION_free
>::Type
35 typedef crypto::ScopedOpenSSL
<X509_NAME
, X509_NAME_free
>::Type ScopedX509_NAME
;
37 const EVP_MD
* ToEVP(x509_util::DigestAlgorithm alg
) {
39 case x509_util::DIGEST_SHA1
:
41 case x509_util::DIGEST_SHA256
:
53 X509
* CreateCertificate(EVP_PKEY
* key
,
55 const std::string
& common_name
,
56 uint32_t serial_number
,
57 base::Time not_valid_before
,
58 base::Time not_valid_after
) {
59 // Put the serial number into an OpenSSL-friendly object.
60 ScopedASN1_INTEGER
asn1_serial(ASN1_INTEGER_new());
61 if (!asn1_serial
.get() ||
62 !ASN1_INTEGER_set(asn1_serial
.get(), static_cast<long>(serial_number
))) {
63 LOG(ERROR
) << "Invalid serial number " << serial_number
;
67 // Do the same for the time stamps.
68 ScopedASN1_TIME
asn1_not_before_time(
69 ASN1_TIME_set(NULL
, not_valid_before
.ToTimeT()));
70 if (!asn1_not_before_time
.get()) {
71 LOG(ERROR
) << "Invalid not_valid_before time: "
72 << not_valid_before
.ToTimeT();
76 ScopedASN1_TIME
asn1_not_after_time(
77 ASN1_TIME_set(NULL
, not_valid_after
.ToTimeT()));
78 if (!asn1_not_after_time
.get()) {
79 LOG(ERROR
) << "Invalid not_valid_after time: " << not_valid_after
.ToTimeT();
83 // Because |common_name| only contains a common name and starts with 'CN=',
84 // there is no need for a full RFC 2253 parser here. Do some sanity checks
86 static const char kCommonNamePrefix
[] = "CN=";
87 const size_t kCommonNamePrefixLen
= sizeof(kCommonNamePrefix
) - 1;
88 if (common_name
.size() < kCommonNamePrefixLen
||
89 strncmp(common_name
.c_str(), kCommonNamePrefix
, kCommonNamePrefixLen
)) {
90 LOG(ERROR
) << "Common name must begin with " << kCommonNamePrefix
;
93 if (common_name
.size() > INT_MAX
) {
94 LOG(ERROR
) << "Common name too long";
97 unsigned char* common_name_str
=
98 reinterpret_cast<unsigned char*>(const_cast<char*>(common_name
.data())) +
100 int common_name_len
=
101 static_cast<int>(common_name
.size() - kCommonNamePrefixLen
);
103 ScopedX509_NAME
name(X509_NAME_new());
104 if (!name
.get() || !X509_NAME_add_entry_by_NID(name
.get(),
111 LOG(ERROR
) << "Can't parse common name: " << common_name
.c_str();
115 // Now create certificate and populate it.
116 ScopedX509
cert(X509_new());
117 if (!cert
.get() || !X509_set_version(cert
.get(), 2L) /* i.e. version 3 */ ||
118 !X509_set_pubkey(cert
.get(), key
) ||
119 !X509_set_serialNumber(cert
.get(), asn1_serial
.get()) ||
120 !X509_set_notBefore(cert
.get(), asn1_not_before_time
.get()) ||
121 !X509_set_notAfter(cert
.get(), asn1_not_after_time
.get()) ||
122 !X509_set_subject_name(cert
.get(), name
.get()) ||
123 !X509_set_issuer_name(cert
.get(), name
.get())) {
124 LOG(ERROR
) << "Could not create certificate";
128 return cert
.release();
131 // DER-encodes |x509|. On success, returns true and writes the
132 // encoding to |*out_der|.
133 bool DerEncodeCert(X509
* x509
, std::string
* out_der
) {
134 int len
= i2d_X509(x509
, NULL
);
138 uint8_t* ptr
= reinterpret_cast<uint8_t*>(WriteInto(out_der
, len
+ 1));
139 if (i2d_X509(x509
, &ptr
) < 0) {
147 bool SignAndDerEncodeCert(X509
* cert
,
150 std::string
* der_encoded
) {
151 // Get the message digest algorithm
152 const EVP_MD
* md
= ToEVP(alg
);
154 LOG(ERROR
) << "Unrecognized hash algorithm.";
158 // Sign it with the private key.
159 if (!X509_sign(cert
, key
, md
)) {
160 LOG(ERROR
) << "Could not sign certificate with key.";
164 // Convert it into a DER-encoded string copied to |der_encoded|.
165 return DerEncodeCert(cert
, der_encoded
);
168 // There is no OpenSSL NID for the 'originBoundCertificate' extension OID yet,
169 // so create a global ASN1_OBJECT lazily with the right parameters.
170 class DomainBoundOid
{
172 DomainBoundOid() : obj_(OBJ_txt2obj(kDomainBoundOidText
, 1)) { CHECK(obj_
); }
176 ASN1_OBJECT_free(obj_
);
179 ASN1_OBJECT
* obj() const { return obj_
; }
182 static const char kDomainBoundOidText
[];
187 // 1.3.6.1.4.1.11129.2.1.6
188 // (iso.org.dod.internet.private.enterprises.google.googleSecurity.
189 // certificateExtensions.originBoundCertificate)
190 const char DomainBoundOid::kDomainBoundOidText
[] = "1.3.6.1.4.1.11129.2.1.6";
192 ASN1_OBJECT
* GetDomainBoundOid() {
193 static base::LazyInstance
<DomainBoundOid
>::Leaky s_lazy
=
194 LAZY_INSTANCE_INITIALIZER
;
195 return s_lazy
.Get().obj();
203 void DERCache_free(void* parent
, void* ptr
, CRYPTO_EX_DATA
* ad
, int idx
,
204 long argl
, void* argp
) {
205 DERCache
* der_cache
= static_cast<DERCache
*>(ptr
);
209 class DERCacheInitSingleton
{
211 DERCacheInitSingleton() {
212 crypto::EnsureOpenSSLInit();
213 der_cache_ex_index_
= X509_get_ex_new_index(0, 0, 0, 0, DERCache_free
);
214 DCHECK_NE(-1, der_cache_ex_index_
);
217 int der_cache_ex_index() const { return der_cache_ex_index_
; }
220 int der_cache_ex_index_
;
222 DISALLOW_COPY_AND_ASSIGN(DERCacheInitSingleton
);
225 base::LazyInstance
<DERCacheInitSingleton
>::Leaky g_der_cache_singleton
=
226 LAZY_INSTANCE_INITIALIZER
;
230 bool IsSupportedValidityRange(base::Time not_valid_before
,
231 base::Time not_valid_after
) {
232 if (not_valid_before
> not_valid_after
)
235 // The validity field of a certificate can only encode years 1-9999.
237 // Compute the base::Time values corresponding to Jan 1st,0001 and
238 // Jan 1st, 10000 respectively. Done by using the pre-computed numbers
239 // of days between these dates and the Unix epoch, i.e. Jan 1st, 1970,
240 // using the following Python script:
242 // from datetime import date as D
243 // print (D(1970,1,1)-D(1,1,1)) # -> 719162 days
244 // print (D(9999,12,31)-D(1970,1,1)) # -> 2932896 days
246 // Note: This ignores leap seconds, but should be enough in practice.
248 const int64 kDaysFromYear0001ToUnixEpoch
= 719162;
249 const int64 kDaysFromUnixEpochToYear10000
= 2932896 + 1;
250 const base::Time kEpoch
= base::Time::UnixEpoch();
251 const base::Time kYear0001
= kEpoch
-
252 base::TimeDelta::FromDays(kDaysFromYear0001ToUnixEpoch
);
253 const base::Time kYear10000
= kEpoch
+
254 base::TimeDelta::FromDays(kDaysFromUnixEpochToYear10000
);
256 if (not_valid_before
< kYear0001
|| not_valid_before
>= kYear10000
||
257 not_valid_after
< kYear0001
|| not_valid_after
>= kYear10000
)
263 bool CreateChannelIDEC(
264 crypto::ECPrivateKey
* key
,
266 const std::string
& domain
,
267 uint32 serial_number
,
268 base::Time not_valid_before
,
269 base::Time not_valid_after
,
270 std::string
* der_cert
) {
271 crypto::OpenSSLErrStackTracer
err_tracer(FROM_HERE
);
272 // Create certificate.
273 ScopedX509
cert(CreateCertificate(key
->key(),
275 "CN=anonymous.invalid",
282 // Add TLS-Channel-ID extension to the certificate before signing it.
283 // The value must be stored DER-encoded, as a ASN.1 IA5String.
284 ScopedASN1_STRING
domain_ia5(ASN1_IA5STRING_new());
285 if (!domain_ia5
.get() ||
286 !ASN1_STRING_set(domain_ia5
.get(), domain
.data(), domain
.size()))
289 std::string domain_der
;
290 int domain_der_len
= i2d_ASN1_IA5STRING(domain_ia5
.get(), NULL
);
291 if (domain_der_len
< 0)
294 domain_der
.resize(domain_der_len
);
295 unsigned char* domain_der_data
=
296 reinterpret_cast<unsigned char*>(&domain_der
[0]);
297 if (i2d_ASN1_IA5STRING(domain_ia5
.get(), &domain_der_data
) < 0)
300 ScopedASN1_OCTET_STRING
domain_str(ASN1_OCTET_STRING_new());
301 if (!domain_str
.get() ||
302 !ASN1_STRING_set(domain_str
.get(), domain_der
.data(), domain_der
.size()))
305 ScopedX509_EXTENSION
ext(X509_EXTENSION_create_by_OBJ(
306 NULL
, GetDomainBoundOid(), 1 /* critical */, domain_str
.get()));
307 if (!ext
.get() || !X509_add_ext(cert
.get(), ext
.get(), -1)) {
311 // Sign and encode it.
312 return SignAndDerEncodeCert(cert
.get(), key
->key(), alg
, der_cert
);
315 bool CreateSelfSignedCert(crypto::RSAPrivateKey
* key
,
317 const std::string
& common_name
,
318 uint32 serial_number
,
319 base::Time not_valid_before
,
320 base::Time not_valid_after
,
321 std::string
* der_encoded
) {
322 crypto::OpenSSLErrStackTracer
err_tracer(FROM_HERE
);
323 ScopedX509
cert(CreateCertificate(key
->key(),
332 return SignAndDerEncodeCert(cert
.get(), key
->key(), alg
, der_encoded
);
335 bool ParsePrincipalKeyAndValue(X509_NAME_ENTRY
* entry
,
337 std::string
* value
) {
339 ASN1_OBJECT
* object
= X509_NAME_ENTRY_get_object(entry
);
340 key
->assign(OBJ_nid2sn(OBJ_obj2nid(object
)));
343 ASN1_STRING
* data
= X509_NAME_ENTRY_get_data(entry
);
347 unsigned char* buf
= NULL
;
348 int len
= ASN1_STRING_to_UTF8(&buf
, data
);
352 value
->assign(reinterpret_cast<const char*>(buf
), len
);
357 bool ParsePrincipalKeyAndValueByIndex(X509_NAME
* name
,
360 std::string
* value
) {
361 X509_NAME_ENTRY
* entry
= X509_NAME_get_entry(name
, index
);
365 return ParsePrincipalKeyAndValue(entry
, key
, value
);
368 bool ParsePrincipalValueByIndex(X509_NAME
* name
,
370 std::string
* value
) {
371 return ParsePrincipalKeyAndValueByIndex(name
, index
, NULL
, value
);
374 bool ParsePrincipalValueByNID(X509_NAME
* name
, int nid
, std::string
* value
) {
375 int index
= X509_NAME_get_index_by_NID(name
, nid
, -1);
379 return ParsePrincipalValueByIndex(name
, index
, value
);
382 bool ParseDate(ASN1_TIME
* x509_time
, base::Time
* time
) {
384 (x509_time
->type
!= V_ASN1_UTCTIME
&&
385 x509_time
->type
!= V_ASN1_GENERALIZEDTIME
))
388 base::StringPiece
str_date(reinterpret_cast<const char*>(x509_time
->data
),
391 CertDateFormat format
= x509_time
->type
== V_ASN1_UTCTIME
?
392 CERT_DATE_FORMAT_UTC_TIME
: CERT_DATE_FORMAT_GENERALIZED_TIME
;
393 return ParseCertificateDate(str_date
, format
, time
);
396 // Returns true if |der_cache| points to valid data, false otherwise.
397 // (note: the DER-encoded data in |der_cache| is owned by |cert|, callers should
399 bool GetDER(X509
* x509
, base::StringPiece
* der_cache
) {
400 int x509_der_cache_index
=
401 g_der_cache_singleton
.Get().der_cache_ex_index();
403 // Re-encoding the DER data via i2d_X509 is an expensive operation,
404 // but it's necessary for comparing two certificates. Re-encode at
405 // most once per certificate and cache the data within the X509 cert
406 // using X509_set_ex_data.
407 DERCache
* internal_cache
= static_cast<DERCache
*>(
408 X509_get_ex_data(x509
, x509_der_cache_index
));
409 if (!internal_cache
) {
410 scoped_ptr
<DERCache
> new_cache(new DERCache
);
411 if (!DerEncodeCert(x509
, &new_cache
->data
))
413 internal_cache
= new_cache
.get();
414 X509_set_ex_data(x509
, x509_der_cache_index
, new_cache
.release());
416 *der_cache
= base::StringPiece(internal_cache
->data
);
420 } // namespace x509_util