15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved. 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file. 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "net/cert/x509_util_openssl.h" 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <algorithm> 88bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)#include <openssl/asn1.h> 95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 108bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)#include "base/lazy_instance.h" 115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/logging.h" 12c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "base/strings/string_piece.h" 138bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)#include "crypto/ec_private_key.h" 148bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)#include "crypto/openssl_util.h" 158bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)#include "crypto/rsa_private_key.h" 16c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "net/cert/x509_cert_types.h" 178bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)#include "net/cert/x509_util.h" 185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace net { 205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 210f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)namespace { 220f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) 230f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)const EVP_MD* ToEVP(x509_util::DigestAlgorithm alg) { 240f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) switch (alg) { 250f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) case x509_util::DIGEST_SHA1: 260f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) return EVP_sha1(); 270f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) case x509_util::DIGEST_SHA256: 280f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) return EVP_sha256(); 290f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) } 300f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) return NULL; 310f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)} 320f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) 330f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)} // namespace 340f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) 355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace x509_util { 365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 378bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)namespace { 388bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) 398bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)X509* CreateCertificate(EVP_PKEY* key, 400f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) DigestAlgorithm alg, 418bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) const std::string& common_name, 428bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) uint32_t serial_number, 438bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) base::Time not_valid_before, 448bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) base::Time not_valid_after) { 458bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) // Put the serial number into an OpenSSL-friendly object. 468bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) crypto::ScopedOpenSSL<ASN1_INTEGER, ASN1_INTEGER_free> asn1_serial( 478bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) ASN1_INTEGER_new()); 488bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) if (!asn1_serial.get() || 498bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) !ASN1_INTEGER_set(asn1_serial.get(), static_cast<long>(serial_number))) { 508bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) LOG(ERROR) << "Invalid serial number " << serial_number; 518bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) return NULL; 528bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) } 538bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) 548bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) // Do the same for the time stamps. 558bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) crypto::ScopedOpenSSL<ASN1_TIME, ASN1_TIME_free> asn1_not_before_time( 568bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) ASN1_TIME_set(NULL, not_valid_before.ToTimeT())); 578bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) if (!asn1_not_before_time.get()) { 588bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) LOG(ERROR) << "Invalid not_valid_before time: " 598bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) << not_valid_before.ToTimeT(); 608bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) return NULL; 618bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) } 628bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) 638bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) crypto::ScopedOpenSSL<ASN1_TIME, ASN1_TIME_free> asn1_not_after_time( 648bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) ASN1_TIME_set(NULL, not_valid_after.ToTimeT())); 658bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) if (!asn1_not_after_time.get()) { 668bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) LOG(ERROR) << "Invalid not_valid_after time: " << not_valid_after.ToTimeT(); 678bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) return NULL; 688bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) } 698bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) 708bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) // Because |common_name| only contains a common name and starts with 'CN=', 718bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) // there is no need for a full RFC 2253 parser here. Do some sanity checks 728bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) // though. 738bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) static const char kCommonNamePrefix[] = "CN="; 748bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) const size_t kCommonNamePrefixLen = sizeof(kCommonNamePrefix) - 1; 758bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) if (common_name.size() < kCommonNamePrefixLen || 768bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) strncmp(common_name.c_str(), kCommonNamePrefix, kCommonNamePrefixLen)) { 778bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) LOG(ERROR) << "Common name must begin with " << kCommonNamePrefix; 788bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) return NULL; 798bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) } 808bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) if (common_name.size() > INT_MAX) { 818bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) LOG(ERROR) << "Common name too long"; 828bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) return NULL; 838bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) } 848bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) unsigned char* common_name_str = 858bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) reinterpret_cast<unsigned char*>(const_cast<char*>(common_name.data())) + 868bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) kCommonNamePrefixLen; 878bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) int common_name_len = 888bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) static_cast<int>(common_name.size() - kCommonNamePrefixLen); 898bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) 908bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) crypto::ScopedOpenSSL<X509_NAME, X509_NAME_free> name(X509_NAME_new()); 918bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) if (!name.get() || !X509_NAME_add_entry_by_NID(name.get(), 928bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) NID_commonName, 938bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) MBSTRING_ASC, 948bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) common_name_str, 958bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) common_name_len, 968bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) -1, 978bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) 0)) { 988bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) LOG(ERROR) << "Can't parse common name: " << common_name.c_str(); 998bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) return NULL; 1008bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) } 1018bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) 1028bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) // Now create certificate and populate it. 1038bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) crypto::ScopedOpenSSL<X509, X509_free> cert(X509_new()); 1048bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) if (!cert.get() || !X509_set_version(cert.get(), 2L) /* i.e. version 3 */ || 1058bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) !X509_set_pubkey(cert.get(), key) || 1068bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) !X509_set_serialNumber(cert.get(), asn1_serial.get()) || 1078bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) !X509_set_notBefore(cert.get(), asn1_not_before_time.get()) || 1088bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) !X509_set_notAfter(cert.get(), asn1_not_after_time.get()) || 1098bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) !X509_set_subject_name(cert.get(), name.get()) || 1108bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) !X509_set_issuer_name(cert.get(), name.get())) { 1118bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) LOG(ERROR) << "Could not create certificate"; 1128bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) return NULL; 1138bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) } 1148bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) 1158bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) return cert.release(); 1168bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)} 1178bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) 1180f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)bool SignAndDerEncodeCert(X509* cert, 1190f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) EVP_PKEY* key, 1200f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) DigestAlgorithm alg, 1210f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) std::string* der_encoded) { 1220f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) // Get the message digest algorithm 1230f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) const EVP_MD* md = ToEVP(alg); 1240f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) if (!md) { 1250f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) LOG(ERROR) << "Unrecognized hash algorithm."; 1260f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) return false; 1270f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) } 1280f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) 1298bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) // Sign it with the private key. 1300f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) if (!X509_sign(cert, key, md)) { 1318bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) LOG(ERROR) << "Could not sign certificate with key."; 1328bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) return false; 1338bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) } 1348bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) 1358bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) // Convert it into a DER-encoded string copied to |der_encoded|. 1368bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) int der_data_length = i2d_X509(cert, NULL); 1378bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) if (der_data_length < 0) 1388bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) return false; 1398bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) 1408bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) der_encoded->resize(der_data_length); 1418bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) unsigned char* der_data = 1428bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) reinterpret_cast<unsigned char*>(&(*der_encoded)[0]); 1438bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) if (i2d_X509(cert, &der_data) < 0) 1448bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) return false; 1458bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) 1468bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) return true; 1478bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)} 1488bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) 1498bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)// There is no OpenSSL NID for the 'originBoundCertificate' extension OID yet, 1508bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)// so create a global ASN1_OBJECT lazily with the right parameters. 1518bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)class DomainBoundOid { 1528bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) public: 1538bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) DomainBoundOid() : obj_(OBJ_txt2obj(kDomainBoundOidText, 1)) { CHECK(obj_); } 1548bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) 1558bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) ~DomainBoundOid() { 1568bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) if (obj_) 1578bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) ASN1_OBJECT_free(obj_); 1588bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) } 1598bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) 1608bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) ASN1_OBJECT* obj() const { return obj_; } 1618bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) 1628bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) private: 1638bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) static const char kDomainBoundOidText[]; 1648bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) 1658bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) ASN1_OBJECT* obj_; 1668bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)}; 1678bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) 1688bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)// 1.3.6.1.4.1.11129.2.1.6 1698bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)// (iso.org.dod.internet.private.enterprises.google.googleSecurity. 1708bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)// certificateExtensions.originBoundCertificate) 1718bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)const char DomainBoundOid::kDomainBoundOidText[] = "1.3.6.1.4.1.11129.2.1.6"; 1728bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) 1738bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)ASN1_OBJECT* GetDomainBoundOid() { 1748bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) static base::LazyInstance<DomainBoundOid>::Leaky s_lazy = 1758bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) LAZY_INSTANCE_INITIALIZER; 1768bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) return s_lazy.Get().obj(); 1778bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)} 1788bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) 1798bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)} // namespace 1808bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) 1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool IsSupportedValidityRange(base::Time not_valid_before, 1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::Time not_valid_after) { 1832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (not_valid_before > not_valid_after) 1842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return false; 1852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // The validity field of a certificate can only encode years 1-9999. 1872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Compute the base::Time values corresponding to Jan 1st,0001 and 1892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Jan 1st, 10000 respectively. Done by using the pre-computed numbers 1902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // of days between these dates and the Unix epoch, i.e. Jan 1st, 1970, 1912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // using the following Python script: 1922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // 1932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // from datetime import date as D 1942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // print (D(1970,1,1)-D(1,1,1)) # -> 719162 days 1952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // print (D(9999,12,31)-D(1970,1,1)) # -> 2932896 days 1962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // 1972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Note: This ignores leap seconds, but should be enough in practice. 1982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // 1992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const int64 kDaysFromYear0001ToUnixEpoch = 719162; 2002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const int64 kDaysFromUnixEpochToYear10000 = 2932896 + 1; 2012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const base::Time kEpoch = base::Time::UnixEpoch(); 2022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const base::Time kYear0001 = kEpoch - 2032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::TimeDelta::FromDays(kDaysFromYear0001ToUnixEpoch); 2042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const base::Time kYear10000 = kEpoch + 2052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::TimeDelta::FromDays(kDaysFromUnixEpochToYear10000); 2062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (not_valid_before < kYear0001 || not_valid_before >= kYear10000 || 2082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) not_valid_after < kYear0001 || not_valid_after >= kYear10000) 2092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return false; 2102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool CreateDomainBoundCertEC( 2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) crypto::ECPrivateKey* key, 2160f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) DigestAlgorithm alg, 2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const std::string& domain, 2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) uint32 serial_number, 2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::Time not_valid_before, 2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::Time not_valid_after, 2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string* der_cert) { 2228bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) crypto::OpenSSLErrStackTracer err_tracer(FROM_HERE); 2238bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) // Create certificate. 2248bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) crypto::ScopedOpenSSL<X509, X509_free> cert( 2258bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) CreateCertificate(key->key(), 2260f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) alg, 2278bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) "CN=anonymous.invalid", 2288bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) serial_number, 2298bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) not_valid_before, 2308bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) not_valid_after)); 2318bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) if (!cert.get()) 2328bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) return false; 2338bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) 2348bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) // Add TLS-Channel-ID extension to the certificate before signing it. 2358bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) // The value must be stored DER-encoded, as a ASN.1 IA5String. 2368bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) crypto::ScopedOpenSSL<ASN1_STRING, ASN1_STRING_free> domain_ia5( 2378bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) ASN1_IA5STRING_new()); 2388bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) if (!domain_ia5.get() || 2398bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) !ASN1_STRING_set(domain_ia5.get(), domain.data(), domain.size())) 2408bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) return false; 2418bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) 2428bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) std::string domain_der; 2438bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) int domain_der_len = i2d_ASN1_IA5STRING(domain_ia5.get(), NULL); 2448bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) if (domain_der_len < 0) 2458bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) return false; 2468bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) 2478bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) domain_der.resize(domain_der_len); 2488bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) unsigned char* domain_der_data = 2498bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) reinterpret_cast<unsigned char*>(&domain_der[0]); 2508bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) if (i2d_ASN1_IA5STRING(domain_ia5.get(), &domain_der_data) < 0) 2518bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) return false; 2528bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) 2538bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) crypto::ScopedOpenSSL<ASN1_OCTET_STRING, ASN1_OCTET_STRING_free> domain_str( 2548bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) ASN1_OCTET_STRING_new()); 2558bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) if (!domain_str.get() || 2568bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) !ASN1_STRING_set(domain_str.get(), domain_der.data(), domain_der.size())) 2578bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) return false; 2588bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) 2598bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) crypto::ScopedOpenSSL<X509_EXTENSION, X509_EXTENSION_free> ext( 2608bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) X509_EXTENSION_create_by_OBJ( 2618bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) NULL, GetDomainBoundOid(), 1 /* critical */, domain_str.get())); 2628bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) if (!ext.get() || !X509_add_ext(cert.get(), ext.get(), -1)) { 2638bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) return false; 2648bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) } 2658bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) 2668bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) // Sign and encode it. 2670f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) return SignAndDerEncodeCert(cert.get(), key->key(), alg, der_cert); 2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 270eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochbool CreateSelfSignedCert(crypto::RSAPrivateKey* key, 2710f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) DigestAlgorithm alg, 272eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch const std::string& common_name, 273eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch uint32 serial_number, 274eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch base::Time not_valid_before, 275eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch base::Time not_valid_after, 276eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch std::string* der_encoded) { 2778bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) crypto::OpenSSLErrStackTracer err_tracer(FROM_HERE); 2788bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) crypto::ScopedOpenSSL<X509, X509_free> cert( 2798bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) CreateCertificate(key->key(), 2800f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) alg, 2818bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) common_name, 2828bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) serial_number, 2838bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) not_valid_before, 2848bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) not_valid_after)); 2858bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) if (!cert.get()) 2868bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) return false; 2878bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) 2880f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) return SignAndDerEncodeCert(cert.get(), key->key(), alg, der_encoded); 289eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch} 290eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool ParsePrincipalKeyAndValueByIndex(X509_NAME* name, 2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int index, 2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string* key, 2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string* value) { 2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) X509_NAME_ENTRY* entry = X509_NAME_get_entry(name, index); 2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!entry) 2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (key) { 3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ASN1_OBJECT* object = X509_NAME_ENTRY_get_object(entry); 3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) key->assign(OBJ_nid2sn(OBJ_obj2nid(object))); 3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ASN1_STRING* data = X509_NAME_ENTRY_get_data(entry); 3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!data) 3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) unsigned char* buf = NULL; 3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int len = ASN1_STRING_to_UTF8(&buf, data); 3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (len <= 0) 3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) value->assign(reinterpret_cast<const char*>(buf), len); 3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) OPENSSL_free(buf); 3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool ParsePrincipalValueByIndex(X509_NAME* name, 3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int index, 3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string* value) { 3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return ParsePrincipalKeyAndValueByIndex(name, index, NULL, value); 3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool ParsePrincipalValueByNID(X509_NAME* name, int nid, std::string* value) { 3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int index = X509_NAME_get_index_by_NID(name, nid, -1); 3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (index < 0) 3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return ParsePrincipalValueByIndex(name, index, value); 3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool ParseDate(ASN1_TIME* x509_time, base::Time* time) { 3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!x509_time || 3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (x509_time->type != V_ASN1_UTCTIME && 3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) x509_time->type != V_ASN1_GENERALIZEDTIME)) 3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::StringPiece str_date(reinterpret_cast<const char*>(x509_time->data), 3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) x509_time->length); 3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CertDateFormat format = x509_time->type == V_ASN1_UTCTIME ? 3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CERT_DATE_FORMAT_UTC_TIME : CERT_DATE_FORMAT_GENERALIZED_TIME; 3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return ParseCertificateDate(str_date, format, time); 3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace x509_util 3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace net 349