• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2019 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.
4 
5 #include "util/crypto/certificate_utils.h"
6 
7 #include <openssl/asn1.h>
8 #include <openssl/bio.h>
9 #include <openssl/bn.h>
10 #include <openssl/crypto.h>
11 #include <openssl/evp.h>
12 #include <openssl/rsa.h>
13 #include <openssl/ssl.h>
14 #include <openssl/x509v3.h>
15 #include <time.h>
16 
17 #include <string>
18 
19 #include "util/crypto/openssl_util.h"
20 #include "util/crypto/sha2.h"
21 #include "util/osp_logging.h"
22 
23 namespace openscreen {
24 
25 namespace {
26 
27 // These values are bit positions from RFC 5280 4.2.1.3 and will be passed to
28 // ASN1_BIT_STRING_set_bit.
29 enum KeyUsageBits {
30   kDigitalSignature = 0,
31   kKeyCertSign = 5,
32 };
33 
34 // Returns whether or not the certificate field successfully was added.
AddCertificateField(X509_NAME * certificate_name,absl::string_view field,absl::string_view value)35 bool AddCertificateField(X509_NAME* certificate_name,
36                          absl::string_view field,
37                          absl::string_view value) {
38   return X509_NAME_add_entry_by_txt(
39              certificate_name, std::string(field).c_str(), MBSTRING_ASC,
40              reinterpret_cast<const unsigned char*>(value.data()),
41              value.length(), -1, 0) == 1;
42 }
43 
ToAsn1Time(std::chrono::seconds time_since_epoch)44 bssl::UniquePtr<ASN1_TIME> ToAsn1Time(std::chrono::seconds time_since_epoch) {
45   return bssl::UniquePtr<ASN1_TIME>(
46       ASN1_TIME_set(nullptr, time_since_epoch.count()));
47 }
48 
CreateCertificateInternal(absl::string_view name,std::chrono::seconds certificate_duration,EVP_PKEY key_pair,std::chrono::seconds time_since_unix_epoch,bool make_ca,X509 * issuer,EVP_PKEY * issuer_key)49 bssl::UniquePtr<X509> CreateCertificateInternal(
50     absl::string_view name,
51     std::chrono::seconds certificate_duration,
52     EVP_PKEY key_pair,
53     std::chrono::seconds time_since_unix_epoch,
54     bool make_ca,
55     X509* issuer,
56     EVP_PKEY* issuer_key) {
57   OSP_DCHECK((!!issuer) == (!!issuer_key));
58   bssl::UniquePtr<X509> certificate(X509_new());
59   if (!issuer) {
60     issuer = certificate.get();
61   }
62   if (!issuer_key) {
63     issuer_key = &key_pair;
64   }
65 
66   // Certificate versions are zero indexed, so V1 = 0.
67   const int kCertificateVersion3 = 2;
68   if (X509_set_version(certificate.get(), kCertificateVersion3) != 1) {
69     OSP_DVLOG << "Failed to set certificate version";
70     return nullptr;
71   }
72 
73   // Serial numbers must be unique for this session. As a pretend CA, we should
74   // not issue certificates with the same serial number in the same session.
75   static int serial_number(1);
76   if (ASN1_INTEGER_set(X509_get_serialNumber(certificate.get()),
77                        serial_number++) != 1) {
78     OSP_DVLOG << "Failed to set serial number.";
79     return nullptr;
80   }
81 
82   const bssl::UniquePtr<ASN1_TIME> now(ToAsn1Time(time_since_unix_epoch));
83   const bssl::UniquePtr<ASN1_TIME> expiration_time(
84       ToAsn1Time(time_since_unix_epoch + certificate_duration));
85 
86   if ((X509_set_notBefore(certificate.get(), now.get()) != 1) ||
87       (X509_set_notAfter(certificate.get(), expiration_time.get()) != 1)) {
88     OSP_DVLOG << "Failed to set before and after ranges.";
89     return nullptr;
90   }
91 
92   X509_NAME* certificate_name = X509_get_subject_name(certificate.get());
93   if (!AddCertificateField(certificate_name, "CN", name)) {
94     OSP_DVLOG << "Failed to set subject name";
95     return nullptr;
96   }
97 
98   bssl::UniquePtr<ASN1_BIT_STRING> x(ASN1_BIT_STRING_new());
99   ASN1_BIT_STRING_set_bit(x.get(), KeyUsageBits::kDigitalSignature, 1);
100   if (make_ca) {
101     ASN1_BIT_STRING_set_bit(x.get(), KeyUsageBits::kKeyCertSign, 1);
102   }
103   if (X509_add1_ext_i2d(certificate.get(), NID_key_usage, x.get(), 0, 0) != 1) {
104     OSP_DVLOG << "Failed to set key usage extension";
105     return nullptr;
106   }
107   if (make_ca) {
108     X509V3_CTX ctx;
109     X509V3_set_ctx_nodb(&ctx);
110     X509V3_set_ctx(&ctx, issuer, certificate.get(), nullptr, nullptr, 0);
111     bssl::UniquePtr<X509_EXTENSION> ex(
112         X509V3_EXT_nconf_nid(nullptr, &ctx, NID_basic_constraints,
113                              const_cast<char*>("critical,CA:TRUE")));
114     if (!ex) {
115       OSP_DVLOG << "Failed to set constraints extension";
116       return nullptr;
117     }
118     void* thing = X509V3_EXT_d2i(ex.get());
119     X509_add1_ext_i2d(certificate.get(), NID_basic_constraints, thing, 1, 0);
120     X509V3_EXT_free(NID_basic_constraints, thing);
121   }
122 
123   X509_NAME* issuer_name = X509_get_subject_name(issuer);
124   if ((X509_set_issuer_name(certificate.get(), issuer_name) != 1) ||
125       (X509_set_pubkey(certificate.get(), &key_pair) != 1) ||
126       // Unlike all of the other BoringSSL methods here, X509_sign returns
127       // the size of the signature in bytes.
128       (X509_sign(certificate.get(), issuer_key, EVP_sha256()) <= 0) ||
129       (X509_verify(certificate.get(), issuer_key) != 1)) {
130     OSP_DVLOG << "Failed to set pubkey, set issuer, sign, or verify";
131     return nullptr;
132   }
133 
134   return certificate;
135 }
136 
137 }  // namespace
138 
GenerateRsaKeyPair(int key_bits)139 bssl::UniquePtr<EVP_PKEY> GenerateRsaKeyPair(int key_bits) {
140   bssl::UniquePtr<BIGNUM> prime(BN_new());
141   if (BN_set_word(prime.get(), RSA_F4) == 0) {
142     return nullptr;
143   }
144 
145   bssl::UniquePtr<RSA> rsa(RSA_new());
146   if (RSA_generate_key_ex(rsa.get(), key_bits, prime.get(), nullptr) == 0) {
147     return nullptr;
148   }
149 
150   bssl::UniquePtr<EVP_PKEY> pkey(EVP_PKEY_new());
151   if (EVP_PKEY_set1_RSA(pkey.get(), rsa.get()) == 0) {
152     return nullptr;
153   }
154 
155   return pkey;
156 }
157 
CreateSelfSignedX509Certificate(absl::string_view name,std::chrono::seconds duration,const EVP_PKEY & key_pair,std::chrono::seconds time_since_unix_epoch,bool make_ca,X509 * issuer,EVP_PKEY * issuer_key)158 ErrorOr<bssl::UniquePtr<X509>> CreateSelfSignedX509Certificate(
159     absl::string_view name,
160     std::chrono::seconds duration,
161     const EVP_PKEY& key_pair,
162     std::chrono::seconds time_since_unix_epoch,
163     bool make_ca,
164     X509* issuer,
165     EVP_PKEY* issuer_key) {
166   bssl::UniquePtr<X509> certificate =
167       CreateCertificateInternal(name, duration, key_pair, time_since_unix_epoch,
168                                 make_ca, issuer, issuer_key);
169   if (!certificate) {
170     return Error::Code::kCertificateCreationError;
171   }
172   return certificate;
173 }
174 
ExportX509CertificateToDer(const X509 & certificate)175 ErrorOr<std::vector<uint8_t>> ExportX509CertificateToDer(
176     const X509& certificate) {
177   unsigned char* buffer = nullptr;
178   // Casting-away the const because the legacy i2d_X509() function is not
179   // const-correct.
180   X509* const certificate_ptr = const_cast<X509*>(&certificate);
181   const int len = i2d_X509(certificate_ptr, &buffer);
182   if (len <= 0) {
183     return Error::Code::kCertificateValidationError;
184   }
185   std::vector<uint8_t> raw_der_certificate(buffer, buffer + len);
186   // BoringSSL doesn't free the temporary buffer.
187   OPENSSL_free(buffer);
188   return raw_der_certificate;
189 }
190 
ImportCertificate(const uint8_t * der_x509_cert,int der_x509_cert_length)191 ErrorOr<bssl::UniquePtr<X509>> ImportCertificate(const uint8_t* der_x509_cert,
192                                                  int der_x509_cert_length) {
193   if (!der_x509_cert) {
194     return Error::Code::kErrCertsMissing;
195   }
196   bssl::UniquePtr<X509> certificate(
197       d2i_X509(nullptr, &der_x509_cert, der_x509_cert_length));
198   if (!certificate) {
199     return Error::Code::kCertificateValidationError;
200   }
201   return certificate;
202 }
203 
ImportRSAPrivateKey(const uint8_t * der_rsa_private_key,int key_length)204 ErrorOr<bssl::UniquePtr<EVP_PKEY>> ImportRSAPrivateKey(
205     const uint8_t* der_rsa_private_key,
206     int key_length) {
207   if (!der_rsa_private_key || key_length == 0) {
208     return Error::Code::kParameterInvalid;
209   }
210 
211   RSA* rsa = RSA_private_key_from_bytes(der_rsa_private_key, key_length);
212   if (!rsa) {
213     return Error::Code::kRSAKeyParseError;
214   }
215   bssl::UniquePtr<EVP_PKEY> pkey(EVP_PKEY_new());
216   EVP_PKEY_assign_RSA(pkey.get(), rsa);
217   return pkey;
218 }
219 
GetSpkiTlv(X509 * cert)220 std::string GetSpkiTlv(X509* cert) {
221   X509_PUBKEY* key = X509_get_X509_PUBKEY(cert);
222   int len = i2d_X509_PUBKEY(key, nullptr);
223   if (len <= 0) {
224     return {};
225   }
226   std::string x(len, 0);
227   uint8_t* data = reinterpret_cast<uint8_t*>(&x[0]);
228   if (!i2d_X509_PUBKEY(key, &data)) {
229     return {};
230   }
231   return x;
232 }
233 
ParseDerUint64(const ASN1_INTEGER * asn1int)234 ErrorOr<uint64_t> ParseDerUint64(const ASN1_INTEGER* asn1int) {
235   const uint8_t* data = ASN1_STRING_get0_data(asn1int);
236   int length = ASN1_STRING_length(asn1int);
237   if (length > 8 || length <= 0) {
238     return Error::Code::kParameterInvalid;
239   }
240   uint64_t result = 0;
241   for (int i = 0; i < length; ++i) {
242     result = (result << 8) | data[i];
243   }
244   return result;
245 }
246 
247 }  // namespace openscreen
248