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 "crypto/scoped_openssl_types.h"
17 #include "net/cert/x509_cert_types.h"
18 #include "net/cert/x509_util.h"
24 typedef crypto::ScopedOpenSSL
<ASN1_INTEGER
, ASN1_INTEGER_free
>::Type
26 typedef crypto::ScopedOpenSSL
<ASN1_OCTET_STRING
, ASN1_OCTET_STRING_free
>::Type
27 ScopedASN1_OCTET_STRING
;
28 typedef crypto::ScopedOpenSSL
<ASN1_STRING
, ASN1_STRING_free
>::Type
30 typedef crypto::ScopedOpenSSL
<ASN1_TIME
, ASN1_TIME_free
>::Type ScopedASN1_TIME
;
31 typedef crypto::ScopedOpenSSL
<X509
, X509_free
>::Type ScopedX509
;
32 typedef crypto::ScopedOpenSSL
<X509_EXTENSION
, X509_EXTENSION_free
>::Type
34 typedef crypto::ScopedOpenSSL
<X509_NAME
, X509_NAME_free
>::Type ScopedX509_NAME
;
36 const EVP_MD
* ToEVP(x509_util::DigestAlgorithm alg
) {
38 case x509_util::DIGEST_SHA1
:
40 case x509_util::DIGEST_SHA256
:
52 X509
* CreateCertificate(EVP_PKEY
* key
,
54 const std::string
& common_name
,
55 uint32_t serial_number
,
56 base::Time not_valid_before
,
57 base::Time not_valid_after
) {
58 // Put the serial number into an OpenSSL-friendly object.
59 ScopedASN1_INTEGER
asn1_serial(ASN1_INTEGER_new());
60 if (!asn1_serial
.get() ||
61 !ASN1_INTEGER_set(asn1_serial
.get(), static_cast<long>(serial_number
))) {
62 LOG(ERROR
) << "Invalid serial number " << serial_number
;
66 // Do the same for the time stamps.
67 ScopedASN1_TIME
asn1_not_before_time(
68 ASN1_TIME_set(NULL
, not_valid_before
.ToTimeT()));
69 if (!asn1_not_before_time
.get()) {
70 LOG(ERROR
) << "Invalid not_valid_before time: "
71 << not_valid_before
.ToTimeT();
75 ScopedASN1_TIME
asn1_not_after_time(
76 ASN1_TIME_set(NULL
, not_valid_after
.ToTimeT()));
77 if (!asn1_not_after_time
.get()) {
78 LOG(ERROR
) << "Invalid not_valid_after time: " << not_valid_after
.ToTimeT();
82 // Because |common_name| only contains a common name and starts with 'CN=',
83 // there is no need for a full RFC 2253 parser here. Do some sanity checks
85 static const char kCommonNamePrefix
[] = "CN=";
86 const size_t kCommonNamePrefixLen
= sizeof(kCommonNamePrefix
) - 1;
87 if (common_name
.size() < kCommonNamePrefixLen
||
88 strncmp(common_name
.c_str(), kCommonNamePrefix
, kCommonNamePrefixLen
)) {
89 LOG(ERROR
) << "Common name must begin with " << kCommonNamePrefix
;
92 if (common_name
.size() > INT_MAX
) {
93 LOG(ERROR
) << "Common name too long";
96 unsigned char* common_name_str
=
97 reinterpret_cast<unsigned char*>(const_cast<char*>(common_name
.data())) +
100 static_cast<int>(common_name
.size() - kCommonNamePrefixLen
);
102 ScopedX509_NAME
name(X509_NAME_new());
103 if (!name
.get() || !X509_NAME_add_entry_by_NID(name
.get(),
110 LOG(ERROR
) << "Can't parse common name: " << common_name
.c_str();
114 // Now create certificate and populate it.
115 ScopedX509
cert(X509_new());
116 if (!cert
.get() || !X509_set_version(cert
.get(), 2L) /* i.e. version 3 */ ||
117 !X509_set_pubkey(cert
.get(), key
) ||
118 !X509_set_serialNumber(cert
.get(), asn1_serial
.get()) ||
119 !X509_set_notBefore(cert
.get(), asn1_not_before_time
.get()) ||
120 !X509_set_notAfter(cert
.get(), asn1_not_after_time
.get()) ||
121 !X509_set_subject_name(cert
.get(), name
.get()) ||
122 !X509_set_issuer_name(cert
.get(), name
.get())) {
123 LOG(ERROR
) << "Could not create certificate";
127 return cert
.release();
130 bool SignAndDerEncodeCert(X509
* cert
,
133 std::string
* der_encoded
) {
134 // Get the message digest algorithm
135 const EVP_MD
* md
= ToEVP(alg
);
137 LOG(ERROR
) << "Unrecognized hash algorithm.";
141 // Sign it with the private key.
142 if (!X509_sign(cert
, key
, md
)) {
143 LOG(ERROR
) << "Could not sign certificate with key.";
147 // Convert it into a DER-encoded string copied to |der_encoded|.
148 int der_data_length
= i2d_X509(cert
, NULL
);
149 if (der_data_length
< 0)
152 der_encoded
->resize(der_data_length
);
153 unsigned char* der_data
=
154 reinterpret_cast<unsigned char*>(&(*der_encoded
)[0]);
155 if (i2d_X509(cert
, &der_data
) < 0)
161 // There is no OpenSSL NID for the 'originBoundCertificate' extension OID yet,
162 // so create a global ASN1_OBJECT lazily with the right parameters.
163 class DomainBoundOid
{
165 DomainBoundOid() : obj_(OBJ_txt2obj(kDomainBoundOidText
, 1)) { CHECK(obj_
); }
169 ASN1_OBJECT_free(obj_
);
172 ASN1_OBJECT
* obj() const { return obj_
; }
175 static const char kDomainBoundOidText
[];
180 // 1.3.6.1.4.1.11129.2.1.6
181 // (iso.org.dod.internet.private.enterprises.google.googleSecurity.
182 // certificateExtensions.originBoundCertificate)
183 const char DomainBoundOid::kDomainBoundOidText
[] = "1.3.6.1.4.1.11129.2.1.6";
185 ASN1_OBJECT
* GetDomainBoundOid() {
186 static base::LazyInstance
<DomainBoundOid
>::Leaky s_lazy
=
187 LAZY_INSTANCE_INITIALIZER
;
188 return s_lazy
.Get().obj();
193 bool IsSupportedValidityRange(base::Time not_valid_before
,
194 base::Time not_valid_after
) {
195 if (not_valid_before
> not_valid_after
)
198 // The validity field of a certificate can only encode years 1-9999.
200 // Compute the base::Time values corresponding to Jan 1st,0001 and
201 // Jan 1st, 10000 respectively. Done by using the pre-computed numbers
202 // of days between these dates and the Unix epoch, i.e. Jan 1st, 1970,
203 // using the following Python script:
205 // from datetime import date as D
206 // print (D(1970,1,1)-D(1,1,1)) # -> 719162 days
207 // print (D(9999,12,31)-D(1970,1,1)) # -> 2932896 days
209 // Note: This ignores leap seconds, but should be enough in practice.
211 const int64 kDaysFromYear0001ToUnixEpoch
= 719162;
212 const int64 kDaysFromUnixEpochToYear10000
= 2932896 + 1;
213 const base::Time kEpoch
= base::Time::UnixEpoch();
214 const base::Time kYear0001
= kEpoch
-
215 base::TimeDelta::FromDays(kDaysFromYear0001ToUnixEpoch
);
216 const base::Time kYear10000
= kEpoch
+
217 base::TimeDelta::FromDays(kDaysFromUnixEpochToYear10000
);
219 if (not_valid_before
< kYear0001
|| not_valid_before
>= kYear10000
||
220 not_valid_after
< kYear0001
|| not_valid_after
>= kYear10000
)
226 bool CreateChannelIDEC(
227 crypto::ECPrivateKey
* key
,
229 const std::string
& domain
,
230 uint32 serial_number
,
231 base::Time not_valid_before
,
232 base::Time not_valid_after
,
233 std::string
* der_cert
) {
234 crypto::OpenSSLErrStackTracer
err_tracer(FROM_HERE
);
235 // Create certificate.
236 ScopedX509
cert(CreateCertificate(key
->key(),
238 "CN=anonymous.invalid",
245 // Add TLS-Channel-ID extension to the certificate before signing it.
246 // The value must be stored DER-encoded, as a ASN.1 IA5String.
247 ScopedASN1_STRING
domain_ia5(ASN1_IA5STRING_new());
248 if (!domain_ia5
.get() ||
249 !ASN1_STRING_set(domain_ia5
.get(), domain
.data(), domain
.size()))
252 std::string domain_der
;
253 int domain_der_len
= i2d_ASN1_IA5STRING(domain_ia5
.get(), NULL
);
254 if (domain_der_len
< 0)
257 domain_der
.resize(domain_der_len
);
258 unsigned char* domain_der_data
=
259 reinterpret_cast<unsigned char*>(&domain_der
[0]);
260 if (i2d_ASN1_IA5STRING(domain_ia5
.get(), &domain_der_data
) < 0)
263 ScopedASN1_OCTET_STRING
domain_str(ASN1_OCTET_STRING_new());
264 if (!domain_str
.get() ||
265 !ASN1_STRING_set(domain_str
.get(), domain_der
.data(), domain_der
.size()))
268 ScopedX509_EXTENSION
ext(X509_EXTENSION_create_by_OBJ(
269 NULL
, GetDomainBoundOid(), 1 /* critical */, domain_str
.get()));
270 if (!ext
.get() || !X509_add_ext(cert
.get(), ext
.get(), -1)) {
274 // Sign and encode it.
275 return SignAndDerEncodeCert(cert
.get(), key
->key(), alg
, der_cert
);
278 bool CreateSelfSignedCert(crypto::RSAPrivateKey
* key
,
280 const std::string
& common_name
,
281 uint32 serial_number
,
282 base::Time not_valid_before
,
283 base::Time not_valid_after
,
284 std::string
* der_encoded
) {
285 crypto::OpenSSLErrStackTracer
err_tracer(FROM_HERE
);
286 ScopedX509
cert(CreateCertificate(key
->key(),
295 return SignAndDerEncodeCert(cert
.get(), key
->key(), alg
, der_encoded
);
298 bool ParsePrincipalKeyAndValue(X509_NAME_ENTRY
* entry
,
300 std::string
* value
) {
302 ASN1_OBJECT
* object
= X509_NAME_ENTRY_get_object(entry
);
303 key
->assign(OBJ_nid2sn(OBJ_obj2nid(object
)));
306 ASN1_STRING
* data
= X509_NAME_ENTRY_get_data(entry
);
310 unsigned char* buf
= NULL
;
311 int len
= ASN1_STRING_to_UTF8(&buf
, data
);
315 value
->assign(reinterpret_cast<const char*>(buf
), len
);
320 bool ParsePrincipalKeyAndValueByIndex(X509_NAME
* name
,
323 std::string
* value
) {
324 X509_NAME_ENTRY
* entry
= X509_NAME_get_entry(name
, index
);
328 return ParsePrincipalKeyAndValue(entry
, key
, value
);
331 bool ParsePrincipalValueByIndex(X509_NAME
* name
,
333 std::string
* value
) {
334 return ParsePrincipalKeyAndValueByIndex(name
, index
, NULL
, value
);
337 bool ParsePrincipalValueByNID(X509_NAME
* name
, int nid
, std::string
* value
) {
338 int index
= X509_NAME_get_index_by_NID(name
, nid
, -1);
342 return ParsePrincipalValueByIndex(name
, index
, value
);
345 bool ParseDate(ASN1_TIME
* x509_time
, base::Time
* time
) {
347 (x509_time
->type
!= V_ASN1_UTCTIME
&&
348 x509_time
->type
!= V_ASN1_GENERALIZEDTIME
))
351 base::StringPiece
str_date(reinterpret_cast<const char*>(x509_time
->data
),
354 CertDateFormat format
= x509_time
->type
== V_ASN1_UTCTIME
?
355 CERT_DATE_FORMAT_UTC_TIME
: CERT_DATE_FORMAT_GENERALIZED_TIME
;
356 return ParseCertificateDate(str_date
, format
, time
);
359 } // namespace x509_util