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 "crypto/ec_private_key.h"
14 #include "crypto/openssl_util.h"
15 #include "crypto/rsa_private_key.h"
16 #include "net/cert/x509_cert_types.h"
17 #include "net/cert/x509_util.h"
23 const EVP_MD
* ToEVP(x509_util::DigestAlgorithm alg
) {
25 case x509_util::DIGEST_SHA1
:
27 case x509_util::DIGEST_SHA256
:
39 X509
* CreateCertificate(EVP_PKEY
* key
,
41 const std::string
& common_name
,
42 uint32_t serial_number
,
43 base::Time not_valid_before
,
44 base::Time not_valid_after
) {
45 // Put the serial number into an OpenSSL-friendly object.
46 crypto::ScopedOpenSSL
<ASN1_INTEGER
, ASN1_INTEGER_free
> asn1_serial(
48 if (!asn1_serial
.get() ||
49 !ASN1_INTEGER_set(asn1_serial
.get(), static_cast<long>(serial_number
))) {
50 LOG(ERROR
) << "Invalid serial number " << serial_number
;
54 // Do the same for the time stamps.
55 crypto::ScopedOpenSSL
<ASN1_TIME
, ASN1_TIME_free
> asn1_not_before_time(
56 ASN1_TIME_set(NULL
, not_valid_before
.ToTimeT()));
57 if (!asn1_not_before_time
.get()) {
58 LOG(ERROR
) << "Invalid not_valid_before time: "
59 << not_valid_before
.ToTimeT();
63 crypto::ScopedOpenSSL
<ASN1_TIME
, ASN1_TIME_free
> asn1_not_after_time(
64 ASN1_TIME_set(NULL
, not_valid_after
.ToTimeT()));
65 if (!asn1_not_after_time
.get()) {
66 LOG(ERROR
) << "Invalid not_valid_after time: " << not_valid_after
.ToTimeT();
70 // Because |common_name| only contains a common name and starts with 'CN=',
71 // there is no need for a full RFC 2253 parser here. Do some sanity checks
73 static const char kCommonNamePrefix
[] = "CN=";
74 const size_t kCommonNamePrefixLen
= sizeof(kCommonNamePrefix
) - 1;
75 if (common_name
.size() < kCommonNamePrefixLen
||
76 strncmp(common_name
.c_str(), kCommonNamePrefix
, kCommonNamePrefixLen
)) {
77 LOG(ERROR
) << "Common name must begin with " << kCommonNamePrefix
;
80 if (common_name
.size() > INT_MAX
) {
81 LOG(ERROR
) << "Common name too long";
84 unsigned char* common_name_str
=
85 reinterpret_cast<unsigned char*>(const_cast<char*>(common_name
.data())) +
88 static_cast<int>(common_name
.size() - kCommonNamePrefixLen
);
90 crypto::ScopedOpenSSL
<X509_NAME
, X509_NAME_free
> name(X509_NAME_new());
91 if (!name
.get() || !X509_NAME_add_entry_by_NID(name
.get(),
98 LOG(ERROR
) << "Can't parse common name: " << common_name
.c_str();
102 // Now create certificate and populate it.
103 crypto::ScopedOpenSSL
<X509
, X509_free
> cert(X509_new());
104 if (!cert
.get() || !X509_set_version(cert
.get(), 2L) /* i.e. version 3 */ ||
105 !X509_set_pubkey(cert
.get(), key
) ||
106 !X509_set_serialNumber(cert
.get(), asn1_serial
.get()) ||
107 !X509_set_notBefore(cert
.get(), asn1_not_before_time
.get()) ||
108 !X509_set_notAfter(cert
.get(), asn1_not_after_time
.get()) ||
109 !X509_set_subject_name(cert
.get(), name
.get()) ||
110 !X509_set_issuer_name(cert
.get(), name
.get())) {
111 LOG(ERROR
) << "Could not create certificate";
115 return cert
.release();
118 bool SignAndDerEncodeCert(X509
* cert
,
121 std::string
* der_encoded
) {
122 // Get the message digest algorithm
123 const EVP_MD
* md
= ToEVP(alg
);
125 LOG(ERROR
) << "Unrecognized hash algorithm.";
129 // Sign it with the private key.
130 if (!X509_sign(cert
, key
, md
)) {
131 LOG(ERROR
) << "Could not sign certificate with key.";
135 // Convert it into a DER-encoded string copied to |der_encoded|.
136 int der_data_length
= i2d_X509(cert
, NULL
);
137 if (der_data_length
< 0)
140 der_encoded
->resize(der_data_length
);
141 unsigned char* der_data
=
142 reinterpret_cast<unsigned char*>(&(*der_encoded
)[0]);
143 if (i2d_X509(cert
, &der_data
) < 0)
149 // There is no OpenSSL NID for the 'originBoundCertificate' extension OID yet,
150 // so create a global ASN1_OBJECT lazily with the right parameters.
151 class DomainBoundOid
{
153 DomainBoundOid() : obj_(OBJ_txt2obj(kDomainBoundOidText
, 1)) { CHECK(obj_
); }
157 ASN1_OBJECT_free(obj_
);
160 ASN1_OBJECT
* obj() const { return obj_
; }
163 static const char kDomainBoundOidText
[];
168 // 1.3.6.1.4.1.11129.2.1.6
169 // (iso.org.dod.internet.private.enterprises.google.googleSecurity.
170 // certificateExtensions.originBoundCertificate)
171 const char DomainBoundOid::kDomainBoundOidText
[] = "1.3.6.1.4.1.11129.2.1.6";
173 ASN1_OBJECT
* GetDomainBoundOid() {
174 static base::LazyInstance
<DomainBoundOid
>::Leaky s_lazy
=
175 LAZY_INSTANCE_INITIALIZER
;
176 return s_lazy
.Get().obj();
181 bool IsSupportedValidityRange(base::Time not_valid_before
,
182 base::Time not_valid_after
) {
183 if (not_valid_before
> not_valid_after
)
186 // The validity field of a certificate can only encode years 1-9999.
188 // Compute the base::Time values corresponding to Jan 1st,0001 and
189 // Jan 1st, 10000 respectively. Done by using the pre-computed numbers
190 // of days between these dates and the Unix epoch, i.e. Jan 1st, 1970,
191 // using the following Python script:
193 // from datetime import date as D
194 // print (D(1970,1,1)-D(1,1,1)) # -> 719162 days
195 // print (D(9999,12,31)-D(1970,1,1)) # -> 2932896 days
197 // Note: This ignores leap seconds, but should be enough in practice.
199 const int64 kDaysFromYear0001ToUnixEpoch
= 719162;
200 const int64 kDaysFromUnixEpochToYear10000
= 2932896 + 1;
201 const base::Time kEpoch
= base::Time::UnixEpoch();
202 const base::Time kYear0001
= kEpoch
-
203 base::TimeDelta::FromDays(kDaysFromYear0001ToUnixEpoch
);
204 const base::Time kYear10000
= kEpoch
+
205 base::TimeDelta::FromDays(kDaysFromUnixEpochToYear10000
);
207 if (not_valid_before
< kYear0001
|| not_valid_before
>= kYear10000
||
208 not_valid_after
< kYear0001
|| not_valid_after
>= kYear10000
)
214 bool CreateDomainBoundCertEC(
215 crypto::ECPrivateKey
* key
,
217 const std::string
& domain
,
218 uint32 serial_number
,
219 base::Time not_valid_before
,
220 base::Time not_valid_after
,
221 std::string
* der_cert
) {
222 crypto::OpenSSLErrStackTracer
err_tracer(FROM_HERE
);
223 // Create certificate.
224 crypto::ScopedOpenSSL
<X509
, X509_free
> cert(
225 CreateCertificate(key
->key(),
227 "CN=anonymous.invalid",
234 // Add TLS-Channel-ID extension to the certificate before signing it.
235 // The value must be stored DER-encoded, as a ASN.1 IA5String.
236 crypto::ScopedOpenSSL
<ASN1_STRING
, ASN1_STRING_free
> domain_ia5(
237 ASN1_IA5STRING_new());
238 if (!domain_ia5
.get() ||
239 !ASN1_STRING_set(domain_ia5
.get(), domain
.data(), domain
.size()))
242 std::string domain_der
;
243 int domain_der_len
= i2d_ASN1_IA5STRING(domain_ia5
.get(), NULL
);
244 if (domain_der_len
< 0)
247 domain_der
.resize(domain_der_len
);
248 unsigned char* domain_der_data
=
249 reinterpret_cast<unsigned char*>(&domain_der
[0]);
250 if (i2d_ASN1_IA5STRING(domain_ia5
.get(), &domain_der_data
) < 0)
253 crypto::ScopedOpenSSL
<ASN1_OCTET_STRING
, ASN1_OCTET_STRING_free
> domain_str(
254 ASN1_OCTET_STRING_new());
255 if (!domain_str
.get() ||
256 !ASN1_STRING_set(domain_str
.get(), domain_der
.data(), domain_der
.size()))
259 crypto::ScopedOpenSSL
<X509_EXTENSION
, X509_EXTENSION_free
> ext(
260 X509_EXTENSION_create_by_OBJ(
261 NULL
, GetDomainBoundOid(), 1 /* critical */, domain_str
.get()));
262 if (!ext
.get() || !X509_add_ext(cert
.get(), ext
.get(), -1)) {
266 // Sign and encode it.
267 return SignAndDerEncodeCert(cert
.get(), key
->key(), alg
, der_cert
);
270 bool CreateSelfSignedCert(crypto::RSAPrivateKey
* key
,
272 const std::string
& common_name
,
273 uint32 serial_number
,
274 base::Time not_valid_before
,
275 base::Time not_valid_after
,
276 std::string
* der_encoded
) {
277 crypto::OpenSSLErrStackTracer
err_tracer(FROM_HERE
);
278 crypto::ScopedOpenSSL
<X509
, X509_free
> cert(
279 CreateCertificate(key
->key(),
288 return SignAndDerEncodeCert(cert
.get(), key
->key(), alg
, der_encoded
);
291 bool ParsePrincipalKeyAndValueByIndex(X509_NAME
* name
,
294 std::string
* value
) {
295 X509_NAME_ENTRY
* entry
= X509_NAME_get_entry(name
, index
);
300 ASN1_OBJECT
* object
= X509_NAME_ENTRY_get_object(entry
);
301 key
->assign(OBJ_nid2sn(OBJ_obj2nid(object
)));
304 ASN1_STRING
* data
= X509_NAME_ENTRY_get_data(entry
);
308 unsigned char* buf
= NULL
;
309 int len
= ASN1_STRING_to_UTF8(&buf
, data
);
313 value
->assign(reinterpret_cast<const char*>(buf
), len
);
318 bool ParsePrincipalValueByIndex(X509_NAME
* name
,
320 std::string
* value
) {
321 return ParsePrincipalKeyAndValueByIndex(name
, index
, NULL
, value
);
324 bool ParsePrincipalValueByNID(X509_NAME
* name
, int nid
, std::string
* value
) {
325 int index
= X509_NAME_get_index_by_NID(name
, nid
, -1);
329 return ParsePrincipalValueByIndex(name
, index
, value
);
332 bool ParseDate(ASN1_TIME
* x509_time
, base::Time
* time
) {
334 (x509_time
->type
!= V_ASN1_UTCTIME
&&
335 x509_time
->type
!= V_ASN1_GENERALIZEDTIME
))
338 base::StringPiece
str_date(reinterpret_cast<const char*>(x509_time
->data
),
341 CertDateFormat format
= x509_time
->type
== V_ASN1_UTCTIME
?
342 CERT_DATE_FORMAT_UTC_TIME
: CERT_DATE_FORMAT_GENERALIZED_TIME
;
343 return ParseCertificateDate(str_date
, format
, time
);
346 } // namespace x509_util