xref: /aosp_15_r20/external/cronet/net/third_party/quiche/src/quiche/quic/core/crypto/certificate_util.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1 // Copyright 2021 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 "quiche/quic/core/crypto/certificate_util.h"
6 
7 #include "absl/strings/str_format.h"
8 #include "absl/strings/str_split.h"
9 #include "absl/strings/string_view.h"
10 #include "openssl/bn.h"
11 #include "openssl/bytestring.h"
12 #include "openssl/digest.h"
13 #include "openssl/ec_key.h"
14 #include "openssl/mem.h"
15 #include "openssl/pkcs7.h"
16 #include "openssl/pool.h"
17 #include "openssl/rsa.h"
18 #include "openssl/stack.h"
19 #include "quiche/quic/core/crypto/boring_utils.h"
20 #include "quiche/quic/platform/api/quic_logging.h"
21 
22 namespace quic {
23 namespace {
AddEcdsa256SignatureAlgorithm(CBB * cbb)24 bool AddEcdsa256SignatureAlgorithm(CBB* cbb) {
25   // See RFC 5758. This is the encoding of OID 1.2.840.10045.4.3.2.
26   static const uint8_t kEcdsaWithSha256[] = {0x2a, 0x86, 0x48, 0xce,
27                                              0x3d, 0x04, 0x03, 0x02};
28 
29   // An AlgorithmIdentifier is described in RFC 5280, 4.1.1.2.
30   CBB sequence, oid;
31   if (!CBB_add_asn1(cbb, &sequence, CBS_ASN1_SEQUENCE) ||
32       !CBB_add_asn1(&sequence, &oid, CBS_ASN1_OBJECT)) {
33     return false;
34   }
35 
36   if (!CBB_add_bytes(&oid, kEcdsaWithSha256, sizeof(kEcdsaWithSha256))) {
37     return false;
38   }
39 
40   // RFC 5758, section 3.2: ecdsa-with-sha256 MUST omit the parameters field.
41   return CBB_flush(cbb);
42 }
43 
44 // Adds an X.509 Name with the specified distinguished name to |cbb|.
AddName(CBB * cbb,absl::string_view name)45 bool AddName(CBB* cbb, absl::string_view name) {
46   // See RFC 4519.
47   static const uint8_t kCommonName[] = {0x55, 0x04, 0x03};
48   static const uint8_t kCountryName[] = {0x55, 0x04, 0x06};
49   static const uint8_t kOrganizationName[] = {0x55, 0x04, 0x0a};
50   static const uint8_t kOrganizationalUnitName[] = {0x55, 0x04, 0x0b};
51 
52   std::vector<std::string> attributes =
53       absl::StrSplit(name, ',', absl::SkipEmpty());
54 
55   if (attributes.empty()) {
56     QUIC_LOG(ERROR) << "Missing DN or wrong format";
57     return false;
58   }
59 
60   // See RFC 5280, section 4.1.2.4.
61   CBB rdns;
62   if (!CBB_add_asn1(cbb, &rdns, CBS_ASN1_SEQUENCE)) {
63     return false;
64   }
65 
66   for (const std::string& attribute : attributes) {
67     std::vector<std::string> parts =
68         absl::StrSplit(absl::StripAsciiWhitespace(attribute), '=');
69     if (parts.size() != 2) {
70       QUIC_LOG(ERROR) << "Wrong DN format at " + attribute;
71       return false;
72     }
73 
74     const std::string& type_string = parts[0];
75     const std::string& value_string = parts[1];
76     absl::Span<const uint8_t> type_bytes;
77     if (type_string == "CN") {
78       type_bytes = kCommonName;
79     } else if (type_string == "C") {
80       type_bytes = kCountryName;
81     } else if (type_string == "O") {
82       type_bytes = kOrganizationName;
83     } else if (type_string == "OU") {
84       type_bytes = kOrganizationalUnitName;
85     } else {
86       QUIC_LOG(ERROR) << "Unrecognized type " + type_string;
87       return false;
88     }
89 
90     CBB rdn, attr, type, value;
91     if (!CBB_add_asn1(&rdns, &rdn, CBS_ASN1_SET) ||
92         !CBB_add_asn1(&rdn, &attr, CBS_ASN1_SEQUENCE) ||
93         !CBB_add_asn1(&attr, &type, CBS_ASN1_OBJECT) ||
94         !CBB_add_bytes(&type, type_bytes.data(), type_bytes.size()) ||
95         !CBB_add_asn1(&attr, &value,
96                       type_string == "C" ? CBS_ASN1_PRINTABLESTRING
97                                          : CBS_ASN1_UTF8STRING) ||
98         !AddStringToCbb(&value, value_string) || !CBB_flush(&rdns)) {
99       return false;
100     }
101   }
102   if (!CBB_flush(cbb)) {
103     return false;
104   }
105   return true;
106 }
107 
CBBAddTime(CBB * cbb,const CertificateTimestamp & timestamp)108 bool CBBAddTime(CBB* cbb, const CertificateTimestamp& timestamp) {
109   CBB child;
110   std::string formatted_time;
111 
112   // Per RFC 5280, 4.1.2.5, times which fit in UTCTime must be encoded as
113   // UTCTime rather than GeneralizedTime.
114   const bool is_utc_time = (1950 <= timestamp.year && timestamp.year < 2050);
115   if (is_utc_time) {
116     uint16_t year = timestamp.year - 1900;
117     if (year >= 100) {
118       year -= 100;
119     }
120     formatted_time = absl::StrFormat("%02d", year);
121     if (!CBB_add_asn1(cbb, &child, CBS_ASN1_UTCTIME)) {
122       return false;
123     }
124   } else {
125     formatted_time = absl::StrFormat("%04d", timestamp.year);
126     if (!CBB_add_asn1(cbb, &child, CBS_ASN1_GENERALIZEDTIME)) {
127       return false;
128     }
129   }
130 
131   absl::StrAppendFormat(&formatted_time, "%02d%02d%02d%02d%02dZ",
132                         timestamp.month, timestamp.day, timestamp.hour,
133                         timestamp.minute, timestamp.second);
134 
135   static const size_t kGeneralizedTimeLength = 15;
136   static const size_t kUTCTimeLength = 13;
137   QUICHE_DCHECK_EQ(formatted_time.size(),
138                    is_utc_time ? kUTCTimeLength : kGeneralizedTimeLength);
139 
140   return AddStringToCbb(&child, formatted_time) && CBB_flush(cbb);
141 }
142 
CBBAddExtension(CBB * extensions,absl::Span<const uint8_t> oid,bool critical,absl::Span<const uint8_t> contents)143 bool CBBAddExtension(CBB* extensions, absl::Span<const uint8_t> oid,
144                      bool critical, absl::Span<const uint8_t> contents) {
145   CBB extension, cbb_oid, cbb_contents;
146   if (!CBB_add_asn1(extensions, &extension, CBS_ASN1_SEQUENCE) ||
147       !CBB_add_asn1(&extension, &cbb_oid, CBS_ASN1_OBJECT) ||
148       !CBB_add_bytes(&cbb_oid, oid.data(), oid.size()) ||
149       (critical && !CBB_add_asn1_bool(&extension, 1)) ||
150       !CBB_add_asn1(&extension, &cbb_contents, CBS_ASN1_OCTETSTRING) ||
151       !CBB_add_bytes(&cbb_contents, contents.data(), contents.size()) ||
152       !CBB_flush(extensions)) {
153     return false;
154   }
155 
156   return true;
157 }
158 
IsEcdsa256Key(const EVP_PKEY & evp_key)159 bool IsEcdsa256Key(const EVP_PKEY& evp_key) {
160   if (EVP_PKEY_id(&evp_key) != EVP_PKEY_EC) {
161     return false;
162   }
163   const EC_KEY* key = EVP_PKEY_get0_EC_KEY(&evp_key);
164   if (key == nullptr) {
165     return false;
166   }
167   const EC_GROUP* group = EC_KEY_get0_group(key);
168   if (group == nullptr) {
169     return false;
170   }
171   return EC_GROUP_get_curve_name(group) == NID_X9_62_prime256v1;
172 }
173 
174 }  // namespace
175 
MakeKeyPairForSelfSignedCertificate()176 bssl::UniquePtr<EVP_PKEY> MakeKeyPairForSelfSignedCertificate() {
177   bssl::UniquePtr<EVP_PKEY_CTX> context(
178       EVP_PKEY_CTX_new_id(EVP_PKEY_EC, nullptr));
179   if (!context) {
180     return nullptr;
181   }
182   if (EVP_PKEY_keygen_init(context.get()) != 1) {
183     return nullptr;
184   }
185   if (EVP_PKEY_CTX_set_ec_paramgen_curve_nid(context.get(),
186                                              NID_X9_62_prime256v1) != 1) {
187     return nullptr;
188   }
189   EVP_PKEY* raw_key = nullptr;
190   if (EVP_PKEY_keygen(context.get(), &raw_key) != 1) {
191     return nullptr;
192   }
193   return bssl::UniquePtr<EVP_PKEY>(raw_key);
194 }
195 
CreateSelfSignedCertificate(EVP_PKEY & key,const CertificateOptions & options)196 std::string CreateSelfSignedCertificate(EVP_PKEY& key,
197                                         const CertificateOptions& options) {
198   std::string error;
199   if (!IsEcdsa256Key(key)) {
200     QUIC_LOG(ERROR) << "CreateSelfSignedCert only accepts ECDSA P-256 keys";
201     return error;
202   }
203 
204   // See RFC 5280, section 4.1. First, construct the TBSCertificate.
205   bssl::ScopedCBB cbb;
206   CBB tbs_cert, version, validity;
207   uint8_t* tbs_cert_bytes;
208   size_t tbs_cert_len;
209 
210   if (!CBB_init(cbb.get(), 64) ||
211       !CBB_add_asn1(cbb.get(), &tbs_cert, CBS_ASN1_SEQUENCE) ||
212       !CBB_add_asn1(&tbs_cert, &version,
213                     CBS_ASN1_CONTEXT_SPECIFIC | CBS_ASN1_CONSTRUCTED | 0) ||
214       !CBB_add_asn1_uint64(&version, 2) ||  // X.509 version 3
215       !CBB_add_asn1_uint64(&tbs_cert, options.serial_number) ||
216       !AddEcdsa256SignatureAlgorithm(&tbs_cert) ||  // signature algorithm
217       !AddName(&tbs_cert, options.subject) ||       // issuer
218       !CBB_add_asn1(&tbs_cert, &validity, CBS_ASN1_SEQUENCE) ||
219       !CBBAddTime(&validity, options.validity_start) ||
220       !CBBAddTime(&validity, options.validity_end) ||
221       !AddName(&tbs_cert, options.subject) ||      // subject
222       !EVP_marshal_public_key(&tbs_cert, &key)) {  // subjectPublicKeyInfo
223     return error;
224   }
225 
226   CBB outer_extensions, extensions;
227   if (!CBB_add_asn1(&tbs_cert, &outer_extensions,
228                     3 | CBS_ASN1_CONTEXT_SPECIFIC | CBS_ASN1_CONSTRUCTED) ||
229       !CBB_add_asn1(&outer_extensions, &extensions, CBS_ASN1_SEQUENCE)) {
230     return error;
231   }
232 
233   // Key Usage
234   constexpr uint8_t kKeyUsageOid[] = {0x55, 0x1d, 0x0f};
235   constexpr uint8_t kKeyUsageContent[] = {
236       0x3,   // BIT STRING
237       0x2,   // Length
238       0x0,   // Unused bits
239       0x80,  // bit(0): digitalSignature
240   };
241   CBBAddExtension(&extensions, kKeyUsageOid, true, kKeyUsageContent);
242 
243   // TODO(wub): Add more extensions here if needed.
244 
245   if (!CBB_finish(cbb.get(), &tbs_cert_bytes, &tbs_cert_len)) {
246     return error;
247   }
248 
249   bssl::UniquePtr<uint8_t> delete_tbs_cert_bytes(tbs_cert_bytes);
250 
251   // Sign the TBSCertificate and write the entire certificate.
252   CBB cert, signature;
253   bssl::ScopedEVP_MD_CTX ctx;
254   uint8_t* sig_out;
255   size_t sig_len;
256   uint8_t* cert_bytes;
257   size_t cert_len;
258   if (!CBB_init(cbb.get(), tbs_cert_len) ||
259       !CBB_add_asn1(cbb.get(), &cert, CBS_ASN1_SEQUENCE) ||
260       !CBB_add_bytes(&cert, tbs_cert_bytes, tbs_cert_len) ||
261       !AddEcdsa256SignatureAlgorithm(&cert) ||
262       !CBB_add_asn1(&cert, &signature, CBS_ASN1_BITSTRING) ||
263       !CBB_add_u8(&signature, 0 /* no unused bits */) ||
264       !EVP_DigestSignInit(ctx.get(), nullptr, EVP_sha256(), nullptr, &key) ||
265       // Compute the maximum signature length.
266       !EVP_DigestSign(ctx.get(), nullptr, &sig_len, tbs_cert_bytes,
267                       tbs_cert_len) ||
268       !CBB_reserve(&signature, &sig_out, sig_len) ||
269       // Actually sign the TBSCertificate.
270       !EVP_DigestSign(ctx.get(), sig_out, &sig_len, tbs_cert_bytes,
271                       tbs_cert_len) ||
272       !CBB_did_write(&signature, sig_len) ||
273       !CBB_finish(cbb.get(), &cert_bytes, &cert_len)) {
274     return error;
275   }
276   bssl::UniquePtr<uint8_t> delete_cert_bytes(cert_bytes);
277   return std::string(reinterpret_cast<char*>(cert_bytes), cert_len);
278 }
279 
280 }  // namespace quic
281