OLD | NEW |
---|---|
(Empty) | |
1 // Copyright 2017 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 "net/cert/x509_certificate.h" | |
6 | |
7 #include "base/pickle.h" | |
8 #include "crypto/openssl_util.h" | |
9 #include "net/base/ip_address.h" | |
10 #include "net/cert/internal/cert_errors.h" | |
11 #include "net/cert/internal/name_constraints.h" | |
12 #include "net/cert/internal/parse_name.h" | |
13 #include "net/cert/internal/parsed_certificate.h" | |
14 #include "net/cert/internal/signature_policy.h" | |
15 #include "net/cert/internal/verify_name_match.h" | |
16 #include "net/cert/internal/verify_signed_data.h" | |
17 #include "net/cert/x509_util.h" | |
18 #include "net/cert/x509_util_openssl.h" | |
19 #include "net/der/parser.h" | |
20 #include "third_party/boringssl/src/include/openssl/evp.h" | |
21 #include "third_party/boringssl/src/include/openssl/pool.h" | |
22 #include "third_party/boringssl/src/include/openssl/sha.h" | |
23 | |
24 namespace net { | |
25 | |
26 namespace { | |
27 | |
28 // Converts a GeneralizedTime struct to a base::Time, returning true on success | |
29 // or false if |generalized| was invalid or cannot be represented by | |
30 // base::Time. | |
31 bool GeneralizedTimeToBaseTime(const der::GeneralizedTime& generalized, | |
32 base::Time* result) { | |
33 base::Time::Exploded exploded = {0}; | |
34 exploded.year = generalized.year; | |
35 exploded.month = generalized.month; | |
36 exploded.day_of_month = generalized.day; | |
37 exploded.hour = generalized.hours; | |
38 exploded.minute = generalized.minutes; | |
39 exploded.second = generalized.seconds; | |
40 return base::Time::FromUTCExploded(exploded, result); | |
41 } | |
42 | |
43 // Sets |value| to the Value from a DER Sequence Tag-Length-Value and return | |
44 // true, or return false if the if was not a valid DER Sequence. | |
eroman
2017/03/29 23:06:55
if the if --> if the TLV
mattm
2017/03/30 04:38:10
Done.
| |
45 WARN_UNUSED_RESULT bool GetSequenceValue(const der::Input& tlv, | |
46 der::Input* value) { | |
47 der::Parser parser(tlv); | |
48 return parser.ReadTag(der::kSequence, value) && !parser.HasMore(); | |
49 } | |
50 | |
51 // Returns true if |cert|'s normalized Issuer value matches any of | |
52 // |normalized_issuers| (which must be pre-normalized). Returns false if there | |
53 // was no match or if there was a parsing error. | |
54 bool IsCertIssuerMatch(CRYPTO_BUFFER* cert, | |
55 const std::vector<std::string>& normalized_issuers) { | |
56 der::Input tbs_certificate_tlv; | |
57 der::Input signature_algorithm_tlv; | |
58 der::BitString signature_value; | |
59 if (!ParseCertificate( | |
60 der::Input(CRYPTO_BUFFER_data(cert), CRYPTO_BUFFER_len(cert)), | |
61 &tbs_certificate_tlv, &signature_algorithm_tlv, &signature_value, | |
62 nullptr)) { | |
63 return false; | |
64 } | |
65 ParsedTbsCertificate tbs; | |
66 if (!ParseTbsCertificate(tbs_certificate_tlv, {}, &tbs, nullptr)) { | |
67 return false; | |
68 } | |
69 | |
70 der::Input issuer_value; | |
71 std::string normalized_cert_issuer; | |
72 if (!GetSequenceValue(tbs.issuer_tlv, &issuer_value) || | |
73 !NormalizeName(issuer_value, &normalized_cert_issuer)) | |
eroman
2017/03/29 23:06:54
Curly brace for consistency with above? Or convers
mattm
2017/03/30 04:38:10
oops, I've switched to what is (I think) the commo
| |
74 return false; | |
75 | |
76 return std::find(normalized_issuers.begin(), normalized_issuers.end(), | |
77 normalized_cert_issuer) != normalized_issuers.end(); | |
78 } | |
79 | |
80 // Sets |out| to UTF-8 encoding of |name_attribute|. Returns true on success or | |
81 // false if |name_attribute| could not be converted to UTF-8. | |
82 bool NameAttributeToString(const X509NameAttribute& name_attribute, | |
83 std::string* out) { | |
84 if (name_attribute.value_tag == der::kTeletexString) { | |
85 for (char c : name_attribute.value.AsStringPiece()) { | |
86 if (c < 32 || c > 126) | |
87 return false; | |
88 } | |
89 *out = name_attribute.value.AsString(); | |
90 return true; | |
91 } | |
92 return name_attribute.ValueAsStringUnsafe(out); | |
eroman
2017/03/29 23:06:54
Should this case explicitly check value_tag as wel
mattm
2017/03/30 04:38:10
I was gonna say ValueAsStringUnsafe checks value_t
| |
93 } | |
94 | |
95 // Fills |principal| from the DER encoded |name_tlv|, returning true on success | |
96 // or false if parsing failed or some of the values could not be converted to | |
97 // UTF-8. | |
98 bool ParsePrincipal(const der::Input& name_tlv, CertPrincipal* principal) { | |
99 RDNSequence rdns; | |
100 if (!ParseName(name_tlv, &rdns)) | |
101 return false; | |
102 | |
103 for (const RelativeDistinguishedName& rdn : rdns) { | |
104 for (const X509NameAttribute& name_attribute : rdn) { | |
105 if (name_attribute.type == TypeCommonNameOid()) { | |
106 if (principal->common_name.empty() && | |
107 !NameAttributeToString(name_attribute, &principal->common_name)) | |
108 return false; | |
109 } else if (name_attribute.type == TypeLocalityNameOid()) { | |
110 if (principal->locality_name.empty() && | |
111 !NameAttributeToString(name_attribute, &principal->locality_name)) | |
112 return false; | |
113 } else if (name_attribute.type == TypeStateOrProvinceNameOid()) { | |
114 if (principal->state_or_province_name.empty() && | |
115 !NameAttributeToString(name_attribute, | |
116 &principal->state_or_province_name)) | |
117 return false; | |
118 } else if (name_attribute.type == TypeCountryNameOid()) { | |
119 if (principal->country_name.empty() && | |
120 !NameAttributeToString(name_attribute, &principal->country_name)) | |
121 return false; | |
122 } else if (name_attribute.type == TypeStreetAddressOid()) { | |
123 std::string s; | |
124 if (!NameAttributeToString(name_attribute, &s)) | |
125 return false; | |
126 principal->street_addresses.push_back(s); | |
127 } else if (name_attribute.type == TypeOrganizationNameOid()) { | |
128 std::string s; | |
129 if (!NameAttributeToString(name_attribute, &s)) | |
130 return false; | |
131 principal->organization_names.push_back(s); | |
132 } else if (name_attribute.type == TypeOrganizationUnitNameOid()) { | |
133 std::string s; | |
134 if (!NameAttributeToString(name_attribute, &s)) | |
135 return false; | |
136 principal->organization_unit_names.push_back(s); | |
137 } else if (name_attribute.type == TypeDomainComponentOid()) { | |
138 std::string s; | |
139 if (!NameAttributeToString(name_attribute, &s)) | |
140 return false; | |
141 principal->domain_components.push_back(s); | |
142 } | |
143 } | |
144 } | |
145 return true; | |
146 } | |
147 | |
148 // Parses certificates from a PKCS#7 SignedData structure, appending them to | |
149 // |handles|. | |
150 void CreateOSCertHandlesFromPKCS7Bytes( | |
151 const char* data, | |
152 size_t length, | |
153 X509Certificate::OSCertHandles* handles) { | |
154 crypto::EnsureOpenSSLInit(); | |
155 crypto::OpenSSLErrStackTracer err_cleaner(FROM_HERE); | |
156 | |
157 CBS der_data; | |
158 CBS_init(&der_data, reinterpret_cast<const uint8_t*>(data), length); | |
159 STACK_OF(X509)* certs = sk_X509_new_null(); | |
160 | |
161 if (PKCS7_get_certificates(certs, &der_data)) { | |
162 for (size_t i = 0; i < sk_X509_num(certs); ++i) { | |
163 base::StringPiece stringpiece; | |
164 x509_util::GetDER(sk_X509_value(certs, i), &stringpiece); | |
165 handles->push_back(x509_util::CreateCryptoBuffer(stringpiece).release()); | |
166 } | |
167 } | |
168 sk_X509_pop_free(certs, X509_free); | |
169 } | |
170 | |
171 } // namespace | |
172 | |
173 bool X509Certificate::Initialize() { | |
174 der::Input tbs_certificate_tlv; | |
175 der::Input signature_algorithm_tlv; | |
176 der::BitString signature_value; | |
177 | |
178 if (!ParseCertificate(der::Input(CRYPTO_BUFFER_data(cert_handle_), | |
179 CRYPTO_BUFFER_len(cert_handle_)), | |
180 &tbs_certificate_tlv, &signature_algorithm_tlv, | |
181 &signature_value, nullptr)) { | |
182 return false; | |
183 } | |
184 | |
185 ParsedTbsCertificate tbs; | |
186 if (!ParseTbsCertificate(tbs_certificate_tlv, {}, &tbs, nullptr)) | |
187 return false; | |
188 | |
189 if (!ParsePrincipal(tbs.subject_tlv, &subject_) || | |
190 !ParsePrincipal(tbs.issuer_tlv, &issuer_)) | |
191 return false; | |
192 | |
193 if (!GeneralizedTimeToBaseTime(tbs.validity_not_before, &valid_start_) || | |
194 !GeneralizedTimeToBaseTime(tbs.validity_not_after, &valid_expiry_)) { | |
195 return false; | |
196 } | |
197 serial_number_ = tbs.serial_number.AsString(); | |
198 return true; | |
199 } | |
200 | |
201 bool X509Certificate::GetSubjectAltName( | |
202 std::vector<std::string>* dns_names, | |
203 std::vector<std::string>* ip_addrs) const { | |
204 if (dns_names) | |
205 dns_names->clear(); | |
206 if (ip_addrs) | |
207 ip_addrs->clear(); | |
208 | |
209 der::Input tbs_certificate_tlv; | |
210 der::Input signature_algorithm_tlv; | |
211 der::BitString signature_value; | |
212 if (!ParseCertificate(der::Input(CRYPTO_BUFFER_data(cert_handle_), | |
213 CRYPTO_BUFFER_len(cert_handle_)), | |
214 &tbs_certificate_tlv, &signature_algorithm_tlv, | |
215 &signature_value, nullptr)) { | |
216 return false; | |
217 } | |
218 | |
219 ParsedTbsCertificate tbs; | |
220 if (!ParseTbsCertificate(tbs_certificate_tlv, {}, &tbs, nullptr)) { | |
eroman
2017/03/29 23:06:55
same comment for single-line ifs
mattm
2017/03/30 04:38:09
Done.
| |
221 return false; | |
222 } | |
223 if (!tbs.has_extensions) | |
224 return false; | |
225 | |
226 std::map<der::Input, ParsedExtension> extensions; | |
227 if (!ParseExtensions(tbs.extensions_tlv, &extensions)) | |
228 return false; | |
229 | |
230 ParsedExtension subject_alt_names_extension; | |
231 if (!ConsumeExtension(SubjectAltNameOid(), &extensions, | |
232 &subject_alt_names_extension)) { | |
233 return false; | |
234 } | |
235 | |
236 std::unique_ptr<GeneralNames> subject_alt_names = | |
237 GeneralNames::Create(subject_alt_names_extension.value); | |
238 if (!subject_alt_names) | |
239 return false; | |
240 | |
241 if (dns_names) | |
242 *dns_names = subject_alt_names->dns_names; | |
243 if (ip_addrs) { | |
244 for (const IPAddress& addr : subject_alt_names->ip_addresses) { | |
245 ip_addrs->push_back( | |
246 std::string(reinterpret_cast<const char*>(addr.bytes().data()), | |
247 addr.bytes().size())); | |
248 } | |
249 } | |
250 | |
251 return !subject_alt_names->dns_names.empty() || | |
252 !subject_alt_names->ip_addresses.empty(); | |
253 } | |
254 | |
255 bool X509Certificate::IsIssuedByEncoded( | |
256 const std::vector<std::string>& valid_issuers) { | |
257 std::vector<std::string> normalized_issuers; | |
258 for (const auto& raw_issuer : valid_issuers) { | |
259 der::Input issuer_value; | |
260 std::string normalized_issuer; | |
261 if (!GetSequenceValue(der::Input(&raw_issuer), &issuer_value) || | |
262 !NormalizeName(issuer_value, &normalized_issuer)) | |
263 continue; | |
264 normalized_issuers.push_back(std::move(normalized_issuer)); | |
265 } | |
266 | |
267 if (IsCertIssuerMatch(cert_handle_, normalized_issuers)) | |
eroman
2017/03/29 23:06:55
[optional] I am not a fan of this function, but I
mattm
2017/03/30 04:38:10
Hmm, okay. done.
| |
268 return true; | |
269 for (CRYPTO_BUFFER* intermediate : intermediate_ca_certs_) { | |
270 if (IsCertIssuerMatch(intermediate, normalized_issuers)) | |
271 return true; | |
272 } | |
273 return false; | |
274 } | |
275 | |
276 // static | |
277 bool X509Certificate::GetDEREncoded(X509Certificate::OSCertHandle cert_handle, | |
278 std::string* encoded) { | |
279 if (!cert_handle) | |
280 return false; | |
281 encoded->assign( | |
282 reinterpret_cast<const char*>(CRYPTO_BUFFER_data(cert_handle)), | |
283 CRYPTO_BUFFER_len(cert_handle)); | |
284 return true; | |
285 } | |
286 | |
287 // static | |
288 void X509Certificate::GetPublicKeyInfo(OSCertHandle cert_handle, | |
289 size_t* size_bits, | |
290 PublicKeyType* type) { | |
291 *type = kPublicKeyTypeUnknown; | |
292 *size_bits = 0; | |
293 | |
294 der::Input tbs_certificate_tlv; | |
295 der::Input signature_algorithm_tlv; | |
296 der::BitString signature_value; | |
297 if (!ParseCertificate(der::Input(CRYPTO_BUFFER_data(cert_handle), | |
eroman
2017/03/29 23:06:54
You could replace this with asn1::ExtractSPKIFromD
mattm
2017/03/30 04:38:10
Done.
| |
298 CRYPTO_BUFFER_len(cert_handle)), | |
299 &tbs_certificate_tlv, &signature_algorithm_tlv, | |
300 &signature_value, nullptr)) { | |
301 return; | |
302 } | |
303 | |
304 ParsedTbsCertificate tbs; | |
305 if (!ParseTbsCertificate(tbs_certificate_tlv, {}, &tbs, nullptr)) | |
306 return; | |
307 | |
308 bssl::UniquePtr<EVP_PKEY> pkey; | |
309 crypto::OpenSSLErrStackTracer err_tracer(FROM_HERE); | |
310 CBS cbs; | |
311 CBS_init(&cbs, tbs.spki_tlv.UnsafeData(), tbs.spki_tlv.Length()); | |
312 pkey.reset(EVP_parse_public_key(&cbs)); | |
313 if (!pkey) | |
314 return; | |
315 | |
316 switch (pkey->type) { | |
317 case EVP_PKEY_RSA: | |
318 *type = kPublicKeyTypeRSA; | |
319 break; | |
320 case EVP_PKEY_DSA: | |
321 *type = kPublicKeyTypeDSA; | |
322 break; | |
323 case EVP_PKEY_EC: | |
324 *type = kPublicKeyTypeECDSA; | |
325 break; | |
326 case EVP_PKEY_DH: | |
327 *type = kPublicKeyTypeDH; | |
328 break; | |
329 } | |
330 *size_bits = EVP_PKEY_bits(pkey.get()); | |
eroman
2017/03/29 23:06:54
EVP_PKEY_bits() returns an int -- do you think it
mattm
2017/03/30 04:38:09
From some code spelunking it seem the impls return
| |
331 } | |
332 | |
333 // static | |
334 bool X509Certificate::IsSameOSCert(X509Certificate::OSCertHandle a, | |
335 X509Certificate::OSCertHandle b) { | |
336 DCHECK(a && b); | |
337 if (a == b) | |
338 return true; | |
339 return CRYPTO_BUFFER_len(a) == CRYPTO_BUFFER_len(b) && | |
340 memcmp(CRYPTO_BUFFER_data(a), CRYPTO_BUFFER_data(b), | |
341 CRYPTO_BUFFER_len(a)) == 0; | |
342 } | |
343 | |
344 // static | |
345 X509Certificate::OSCertHandle X509Certificate::CreateOSCertHandleFromBytes( | |
346 const char* data, | |
347 size_t length) { | |
348 der::Input tbs_certificate_tlv; | |
349 der::Input signature_algorithm_tlv; | |
350 der::BitString signature_value; | |
351 // Do a bare minimum of DER parsing here to make sure the input is not | |
352 // completely crazy. (This is required for at least | |
353 // CreateCertificateListFromBytes with FORMAT_AUTO, if not more.) | |
354 if (!ParseCertificate( | |
355 der::Input(reinterpret_cast<const uint8_t*>(data), length), | |
356 &tbs_certificate_tlv, &signature_algorithm_tlv, &signature_value, | |
357 nullptr)) { | |
358 return nullptr; | |
359 } | |
360 | |
361 return CRYPTO_BUFFER_new(reinterpret_cast<const uint8_t*>(data), length, | |
362 x509_util::GetBufferPool()); | |
363 } | |
364 | |
365 // static | |
366 X509Certificate::OSCertHandles X509Certificate::CreateOSCertHandlesFromBytes( | |
367 const char* data, | |
368 size_t length, | |
369 Format format) { | |
370 OSCertHandles results; | |
371 | |
372 switch (format) { | |
373 case FORMAT_SINGLE_CERTIFICATE: { | |
374 OSCertHandle handle = CreateOSCertHandleFromBytes(data, length); | |
375 if (handle) | |
376 results.push_back(handle); | |
377 break; | |
378 } | |
379 case FORMAT_PKCS7: { | |
380 CreateOSCertHandlesFromPKCS7Bytes(data, length, &results); | |
381 break; | |
382 } | |
383 default: { | |
384 NOTREACHED() << "Certificate format " << format << " unimplemented"; | |
385 break; | |
386 } | |
387 } | |
388 | |
389 return results; | |
390 } | |
391 | |
392 // static | |
393 X509Certificate::OSCertHandle X509Certificate::DupOSCertHandle( | |
394 OSCertHandle cert_handle) { | |
395 CRYPTO_BUFFER_up_ref(cert_handle); | |
396 return cert_handle; | |
397 } | |
398 | |
399 // static | |
400 void X509Certificate::FreeOSCertHandle(OSCertHandle cert_handle) { | |
401 CRYPTO_BUFFER_free(cert_handle); | |
402 } | |
403 | |
404 // static | |
405 SHA256HashValue X509Certificate::CalculateFingerprint256(OSCertHandle cert) { | |
406 SHA256HashValue sha256; | |
407 | |
408 SHA256(CRYPTO_BUFFER_data(cert), CRYPTO_BUFFER_len(cert), sha256.data); | |
409 return sha256; | |
410 } | |
411 | |
412 // static | |
413 SHA256HashValue X509Certificate::CalculateCAFingerprint256( | |
414 const OSCertHandles& intermediates) { | |
415 SHA256HashValue sha256; | |
416 memset(sha256.data, 0, sizeof(sha256.data)); | |
417 | |
418 SHA256_CTX sha256_ctx; | |
419 SHA256_Init(&sha256_ctx); | |
420 for (CRYPTO_BUFFER* cert : intermediates) { | |
421 SHA256_Update(&sha256_ctx, CRYPTO_BUFFER_data(cert), | |
422 CRYPTO_BUFFER_len(cert)); | |
423 } | |
424 SHA256_Final(sha256.data, &sha256_ctx); | |
eroman
2017/03/29 23:06:54
Should we be checking the return values from these
mattm
2017/03/30 04:38:09
It seems like no existing code checks the results
| |
425 | |
426 return sha256; | |
427 } | |
428 | |
429 // static | |
430 bool X509Certificate::IsSelfSigned(OSCertHandle cert_handle) { | |
431 der::Input tbs_certificate_tlv; | |
432 der::Input signature_algorithm_tlv; | |
433 der::BitString signature_value; | |
434 if (!ParseCertificate(der::Input(CRYPTO_BUFFER_data(cert_handle), | |
eroman
2017/03/29 23:06:55
Having seen this pattern a few times, I wonder if
mattm
2017/03/30 04:38:09
Acknowledged.
| |
435 CRYPTO_BUFFER_len(cert_handle)), | |
436 &tbs_certificate_tlv, &signature_algorithm_tlv, | |
437 &signature_value, nullptr)) { | |
438 return false; | |
439 } | |
440 ParsedTbsCertificate tbs; | |
441 if (!ParseTbsCertificate(tbs_certificate_tlv, {}, &tbs, nullptr)) { | |
442 return false; | |
443 } | |
444 | |
445 der::Input subject_value; | |
446 std::string normalized_subject; | |
447 if (!GetSequenceValue(tbs.subject_tlv, &subject_value) || | |
448 !NormalizeName(subject_value, &normalized_subject)) | |
449 return false; | |
450 der::Input issuer_value; | |
451 std::string normalized_issuer; | |
452 if (!GetSequenceValue(tbs.issuer_tlv, &issuer_value) || | |
453 !NormalizeName(issuer_value, &normalized_issuer)) | |
454 return false; | |
455 | |
456 if (normalized_subject != normalized_issuer) | |
eroman
2017/03/29 23:06:54
Interestingly, I just glanced at the _mac.cc versi
mattm
2017/03/30 04:38:09
Apparently:
CSSMOID_X509V1IssuerName and CSSMOID_X
| |
457 return false; | |
458 | |
459 std::unique_ptr<SignatureAlgorithm> signature_algorithm = | |
460 SignatureAlgorithm::Create(signature_algorithm_tlv, nullptr /* errors */); | |
461 if (!signature_algorithm) | |
462 return false; | |
463 | |
464 SimpleSignaturePolicy signature_policy(1024); | |
465 CertErrors unused_errors; | |
466 return VerifySignedData(*signature_algorithm, tbs_certificate_tlv, | |
eroman
2017/03/29 23:06:54
I wonder is this even necessary? I see some implem
mattm
2017/03/30 04:38:09
Yeah, based on how it's used (and the unittest as
| |
467 signature_value, tbs.spki_tlv, &signature_policy, | |
468 &unused_errors); | |
469 } | |
470 | |
471 // static | |
472 X509Certificate::OSCertHandle X509Certificate::ReadOSCertHandleFromPickle( | |
473 base::PickleIterator* pickle_iter) { | |
474 const char* data; | |
475 int length; | |
476 if (!pickle_iter->ReadData(&data, &length)) | |
477 return NULL; | |
478 | |
479 return CreateOSCertHandleFromBytes(data, length); | |
eroman
2017/03/29 23:06:54
paranoid crazy person: is length always non-negati
mattm
2017/03/30 04:38:10
Looks like the pickle ReadData code will return fa
| |
480 } | |
481 | |
482 // static | |
483 bool X509Certificate::WriteOSCertHandleToPickle(OSCertHandle cert_handle, | |
484 base::Pickle* pickle) { | |
485 return pickle->WriteData( | |
486 reinterpret_cast<const char*>(CRYPTO_BUFFER_data(cert_handle)), | |
487 CRYPTO_BUFFER_len(cert_handle)); | |
488 } | |
489 | |
490 } // namespace net | |
OLD | NEW |