Bob Beck | bc97b7a | 2023-04-18 08:35:15 -0600 | [diff] [blame] | 1 | // Copyright 2012 The Chromium Authors |
| 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 "fillins/bits.h" |
| 6 | #include "string_util.h" |
| 7 | #include "x509_certificate.h" |
| 8 | |
| 9 | #include <limits.h> |
| 10 | #include <stdlib.h> |
| 11 | |
| 12 | #include <memory> |
| 13 | #include <string> |
| 14 | #include <vector> |
| 15 | |
| 16 | #include "fillins/base64.h" |
| 17 | |
| 18 | #include <openssl/span.h> |
| 19 | #include "base/logging.h" |
| 20 | |
| 21 | |
| 22 | #include <string_view> |
| 23 | |
| 24 | #include "fillins/string_util.h" |
| 25 | |
| 26 | |
| 27 | #include "fillins/openssl_util.h" |
| 28 | #include "fillins/ip_address.h" |
| 29 | #include "base/registry_controlled_domains/registry_controlled_domain.h" |
| 30 | #include "base/tracing.h" |
| 31 | #include "base/url_util.h" |
| 32 | #include "asn1_util.h" |
| 33 | #include "pem.h" |
| 34 | #include "cert_errors.h" |
| 35 | #include "name_constraints.h" |
| 36 | #include "parsed_certificate.h" |
| 37 | #include "signature_algorithm.h" |
| 38 | #include "verify_certificate_chain.h" |
| 39 | #include "verify_name_match.h" |
| 40 | #include "verify_signed_data.h" |
| 41 | #include "time_conversions.h" |
| 42 | #include "fillins/x509_util.h" |
| 43 | #include "parser.h" |
| 44 | |
| 45 | #include <openssl/evp.h> |
| 46 | #include <openssl/pool.h> |
| 47 | #include <openssl/sha.h> |
| 48 | #include "url/url_canon.h" |
| 49 | |
| 50 | namespace bssl { |
| 51 | |
| 52 | namespace { |
| 53 | |
| 54 | // Indicates the order to use when trying to decode binary data, which is |
| 55 | // based on (speculation) as to what will be most common -> least common |
| 56 | const X509Certificate::Format kFormatDecodePriority[] = { |
| 57 | X509Certificate::FORMAT_SINGLE_CERTIFICATE, |
| 58 | X509Certificate::FORMAT_PKCS7 |
| 59 | }; |
| 60 | |
| 61 | // The PEM block header used for DER certificates |
| 62 | const char kCertificateHeader[] = "CERTIFICATE"; |
| 63 | // The PEM block header used for PKCS#7 data |
| 64 | const char kPKCS7Header[] = "PKCS7"; |
| 65 | |
| 66 | // Utility to split |src| on the first occurrence of |c|, if any. |right| will |
| 67 | // either be empty if |c| was not found, or will contain the remainder of the |
| 68 | // string including the split character itself. |
| 69 | void SplitOnChar(std::string_view src, |
| 70 | char c, |
| 71 | std::string_view* left, |
| 72 | std::string_view* right) { |
| 73 | size_t pos = src.find(c); |
| 74 | if (pos == std::string_view::npos) { |
| 75 | *left = src; |
| 76 | *right = std::string_view(); |
| 77 | } else { |
| 78 | *left = src.substr(0, pos); |
| 79 | *right = src.substr(pos); |
| 80 | } |
| 81 | } |
| 82 | |
| 83 | // Sets |value| to the Value from a DER Sequence Tag-Length-Value and return |
| 84 | // true, or return false if the TLV was not a valid DER Sequence. |
| 85 | [[nodiscard]] bool ParseSequenceValue(const der::Input& tlv, |
| 86 | der::Input* value) { |
| 87 | der::Parser parser(tlv); |
| 88 | return parser.ReadTag(der::kSequence, value) && !parser.HasMore(); |
| 89 | } |
| 90 | |
| 91 | // Normalize |cert|'s Issuer and store it in |out_normalized_issuer|, returning |
| 92 | // true on success or false if there was a parsing error. |
| 93 | bool GetNormalizedCertIssuer(CRYPTO_BUFFER* cert, |
| 94 | std::string* out_normalized_issuer) { |
| 95 | der::Input tbs_certificate_tlv; |
| 96 | der::Input signature_algorithm_tlv; |
| 97 | der::BitString signature_value; |
| 98 | if (!ParseCertificate( |
| 99 | der::Input(CRYPTO_BUFFER_data(cert), CRYPTO_BUFFER_len(cert)), |
| 100 | &tbs_certificate_tlv, &signature_algorithm_tlv, &signature_value, |
| 101 | nullptr)) { |
| 102 | return false; |
| 103 | } |
| 104 | ParsedTbsCertificate tbs; |
| 105 | if (!ParseTbsCertificate(tbs_certificate_tlv, |
| 106 | x509_util::DefaultParseCertificateOptions(), &tbs, |
| 107 | nullptr)) |
| 108 | return false; |
| 109 | |
| 110 | der::Input issuer_value; |
| 111 | if (!ParseSequenceValue(tbs.issuer_tlv, &issuer_value)) |
| 112 | return false; |
| 113 | |
| 114 | CertErrors errors; |
| 115 | return NormalizeName(issuer_value, out_normalized_issuer, &errors); |
| 116 | } |
| 117 | |
| 118 | bssl::UniquePtr<CRYPTO_BUFFER> CreateCertBufferFromBytesWithSanityCheck( |
| 119 | bssl::Span<const uint8_t> data) { |
| 120 | der::Input tbs_certificate_tlv; |
| 121 | der::Input signature_algorithm_tlv; |
| 122 | der::BitString signature_value; |
| 123 | // Do a bare minimum of DER parsing here to see if the input looks |
| 124 | // certificate-ish. |
| 125 | if (!ParseCertificate(der::Input(data.data(), data.size()), |
| 126 | &tbs_certificate_tlv, &signature_algorithm_tlv, |
| 127 | &signature_value, nullptr)) { |
| 128 | return nullptr; |
| 129 | } |
| 130 | return x509_util::CreateCryptoBuffer(data); |
| 131 | } |
| 132 | |
| 133 | } // namespace |
| 134 | |
| 135 | // static |
| 136 | std::shared_ptr<X509Certificate> X509Certificate::CreateFromBuffer( |
| 137 | bssl::UniquePtr<CRYPTO_BUFFER> cert_buffer, |
| 138 | std::vector<bssl::UniquePtr<CRYPTO_BUFFER>> intermediates) { |
| 139 | return CreateFromBufferUnsafeOptions(std::move(cert_buffer), |
| 140 | std::move(intermediates), {}); |
| 141 | } |
| 142 | |
| 143 | // static |
| 144 | std::shared_ptr<X509Certificate> X509Certificate::CreateFromBufferUnsafeOptions( |
| 145 | bssl::UniquePtr<CRYPTO_BUFFER> cert_buffer, |
| 146 | std::vector<bssl::UniquePtr<CRYPTO_BUFFER>> intermediates, |
| 147 | UnsafeCreateOptions options) { |
| 148 | DCHECK(cert_buffer); |
| 149 | ParsedFields parsed; |
| 150 | if (!parsed.Initialize(cert_buffer.get(), options)) { |
| 151 | return nullptr; |
| 152 | } |
| 153 | return base::WrapRefCounted(new X509Certificate( |
| 154 | std::move(parsed), std::move(cert_buffer), std::move(intermediates))); |
| 155 | } |
| 156 | |
| 157 | // static |
| 158 | std::shared_ptr<X509Certificate> X509Certificate::CreateFromDERCertChain( |
| 159 | const std::vector<std::string_view>& der_certs) { |
| 160 | return CreateFromDERCertChainUnsafeOptions(der_certs, {}); |
| 161 | } |
| 162 | |
| 163 | // static |
| 164 | std::shared_ptr<X509Certificate> |
| 165 | X509Certificate::CreateFromDERCertChainUnsafeOptions( |
| 166 | const std::vector<std::string_view>& der_certs, |
| 167 | UnsafeCreateOptions options) { |
| 168 | TRACE_EVENT0("io", "X509Certificate::CreateFromDERCertChain"); |
| 169 | if (der_certs.empty()) |
| 170 | return nullptr; |
| 171 | |
| 172 | std::vector<bssl::UniquePtr<CRYPTO_BUFFER>> intermediate_ca_certs; |
| 173 | intermediate_ca_certs.reserve(der_certs.size() - 1); |
| 174 | for (size_t i = 1; i < der_certs.size(); i++) { |
| 175 | intermediate_ca_certs.push_back( |
| 176 | x509_util::CreateCryptoBuffer(der_certs[i])); |
| 177 | } |
| 178 | |
| 179 | return CreateFromBufferUnsafeOptions( |
| 180 | x509_util::CreateCryptoBuffer(der_certs[0]), |
| 181 | std::move(intermediate_ca_certs), options); |
| 182 | } |
| 183 | |
| 184 | // static |
| 185 | std::shared_ptr<X509Certificate> X509Certificate::CreateFromBytes( |
| 186 | bssl::Span<const uint8_t> data) { |
| 187 | return CreateFromBytesUnsafeOptions(data, {}); |
| 188 | } |
| 189 | |
| 190 | // static |
| 191 | std::shared_ptr<X509Certificate> X509Certificate::CreateFromBytesUnsafeOptions( |
| 192 | bssl::Span<const uint8_t> data, |
| 193 | UnsafeCreateOptions options) { |
| 194 | std::shared_ptr<X509Certificate> cert = CreateFromBufferUnsafeOptions( |
| 195 | x509_util::CreateCryptoBuffer(data), {}, options); |
| 196 | return cert; |
| 197 | } |
| 198 | |
| 199 | // static |
| 200 | std::shared_ptr<X509Certificate> X509Certificate::CreateFromPickle( |
| 201 | base::PickleIterator* pickle_iter) { |
| 202 | return CreateFromPickleUnsafeOptions(pickle_iter, {}); |
| 203 | } |
| 204 | |
| 205 | // static |
| 206 | std::shared_ptr<X509Certificate> X509Certificate::CreateFromPickleUnsafeOptions( |
| 207 | base::PickleIterator* pickle_iter, |
| 208 | UnsafeCreateOptions options) { |
| 209 | size_t chain_length = 0; |
| 210 | if (!pickle_iter->ReadLength(&chain_length)) |
| 211 | return nullptr; |
| 212 | |
| 213 | std::vector<std::string_view> cert_chain; |
| 214 | const char* data = nullptr; |
| 215 | size_t data_length = 0; |
| 216 | for (size_t i = 0; i < chain_length; ++i) { |
| 217 | if (!pickle_iter->ReadData(&data, &data_length)) |
| 218 | return nullptr; |
| 219 | cert_chain.emplace_back(data, data_length); |
| 220 | } |
| 221 | return CreateFromDERCertChainUnsafeOptions(cert_chain, options); |
| 222 | } |
| 223 | |
| 224 | // static |
| 225 | CertificateList X509Certificate::CreateCertificateListFromBytes( |
| 226 | bssl::Span<const uint8_t> data, |
| 227 | int format) { |
| 228 | std::vector<bssl::UniquePtr<CRYPTO_BUFFER>> certificates; |
| 229 | |
| 230 | // Check to see if it is in a PEM-encoded form. This check is performed |
| 231 | // first, as both OS X and NSS will both try to convert if they detect |
| 232 | // PEM encoding, except they don't do it consistently between the two. |
| 233 | std::string_view data_string(reinterpret_cast<const char*>(data.data()), |
| 234 | data.size()); |
| 235 | std::vector<std::string> pem_headers; |
| 236 | |
| 237 | // To maintain compatibility with NSS/Firefox, CERTIFICATE is a universally |
| 238 | // valid PEM block header for any format. |
| 239 | pem_headers.push_back(kCertificateHeader); |
| 240 | if (format & FORMAT_PKCS7) |
| 241 | pem_headers.push_back(kPKCS7Header); |
| 242 | |
| 243 | PEMTokenizer pem_tokenizer(data_string, pem_headers); |
| 244 | while (pem_tokenizer.GetNext()) { |
| 245 | std::string decoded(pem_tokenizer.data()); |
| 246 | |
| 247 | bssl::UniquePtr<CRYPTO_BUFFER> handle; |
| 248 | if (format & FORMAT_PEM_CERT_SEQUENCE) { |
| 249 | handle = CreateCertBufferFromBytesWithSanityCheck( |
| 250 | fillins::as_bytes(bssl::MakeSpan(decoded))); |
| 251 | } |
| 252 | if (handle) { |
| 253 | // Parsed a DER encoded certificate. All PEM blocks that follow must |
| 254 | // also be DER encoded certificates wrapped inside of PEM blocks. |
| 255 | format = FORMAT_PEM_CERT_SEQUENCE; |
| 256 | certificates.push_back(std::move(handle)); |
| 257 | continue; |
| 258 | } |
| 259 | |
| 260 | // If the first block failed to parse as a DER certificate, and |
| 261 | // formats other than PEM are acceptable, check to see if the decoded |
| 262 | // data is one of the accepted formats. |
| 263 | if (format & ~FORMAT_PEM_CERT_SEQUENCE) { |
| 264 | for (size_t i = 0; |
| 265 | certificates.empty() && i < std::size(kFormatDecodePriority); ++i) { |
| 266 | if (format & kFormatDecodePriority[i]) { |
| 267 | certificates = CreateCertBuffersFromBytes( |
| 268 | fillins::as_bytes(bssl::MakeSpan(decoded)), |
| 269 | kFormatDecodePriority[i]); |
| 270 | } |
| 271 | } |
| 272 | } |
| 273 | |
| 274 | // Stop parsing after the first block for any format but a sequence of |
| 275 | // PEM-encoded DER certificates. The case of FORMAT_PEM_CERT_SEQUENCE |
| 276 | // is handled above, and continues processing until a certificate fails |
| 277 | // to parse. |
| 278 | break; |
| 279 | } |
| 280 | |
| 281 | // Try each of the formats, in order of parse preference, to see if |data| |
| 282 | // contains the binary representation of a Format, if it failed to parse |
| 283 | // as a PEM certificate/chain. |
| 284 | for (size_t i = 0; |
| 285 | certificates.empty() && i < std::size(kFormatDecodePriority); ++i) { |
| 286 | if (format & kFormatDecodePriority[i]) |
| 287 | certificates = CreateCertBuffersFromBytes(data, kFormatDecodePriority[i]); |
| 288 | } |
| 289 | |
| 290 | CertificateList results; |
| 291 | // No certificates parsed. |
| 292 | if (certificates.empty()) |
| 293 | return results; |
| 294 | |
| 295 | for (auto& it : certificates) { |
| 296 | std::shared_ptr<X509Certificate> cert = CreateFromBuffer(std::move(it), {}); |
| 297 | if (cert) |
| 298 | results.push_back(std::move(cert)); |
| 299 | } |
| 300 | |
| 301 | return results; |
| 302 | } |
| 303 | |
| 304 | std::shared_ptr<X509Certificate> X509Certificate::CloneWithDifferentIntermediates( |
| 305 | std::vector<bssl::UniquePtr<CRYPTO_BUFFER>> intermediates) { |
| 306 | // If intermediates are the same, return another reference to the same |
| 307 | // object. Note that this only does a pointer equality comparison on the |
| 308 | // CRYPTO_BUFFERs, which is generally sufficient, but in some edge cases |
| 309 | // buffers have equal contents but with different addresses. This is |
| 310 | // acceptable as this is just an optimization. |
| 311 | if (intermediates == intermediate_ca_certs_) { |
| 312 | return this; |
| 313 | } |
| 314 | |
| 315 | return base::WrapRefCounted( |
| 316 | new X509Certificate(*this, std::move(intermediates))); |
| 317 | } |
| 318 | |
| 319 | void X509Certificate::Persist(base::Pickle* pickle) const { |
| 320 | DCHECK(cert_buffer_); |
| 321 | // This would be an absolutely insane number of intermediates. |
| 322 | if (intermediate_ca_certs_.size() > static_cast<size_t>(INT_MAX) - 1) { |
| 323 | abort(); //NOTREACHED; |
| 324 | return; |
| 325 | } |
| 326 | pickle->WriteInt(static_cast<int>(intermediate_ca_certs_.size() + 1)); |
| 327 | pickle->WriteString(x509_util::CryptoBufferAsStringPiece(cert_buffer_.get())); |
| 328 | for (const auto& intermediate : intermediate_ca_certs_) { |
| 329 | pickle->WriteString( |
| 330 | x509_util::CryptoBufferAsStringPiece(intermediate.get())); |
| 331 | } |
| 332 | } |
| 333 | |
| 334 | bool X509Certificate::GetSubjectAltName( |
| 335 | std::vector<std::string>* dns_names, |
| 336 | std::vector<std::string>* ip_addrs) const { |
| 337 | if (dns_names) |
| 338 | dns_names->clear(); |
| 339 | if (ip_addrs) |
| 340 | ip_addrs->clear(); |
| 341 | |
| 342 | der::Input tbs_certificate_tlv; |
| 343 | der::Input signature_algorithm_tlv; |
| 344 | der::BitString signature_value; |
| 345 | if (!ParseCertificate(der::Input(CRYPTO_BUFFER_data(cert_buffer_.get()), |
| 346 | CRYPTO_BUFFER_len(cert_buffer_.get())), |
| 347 | &tbs_certificate_tlv, &signature_algorithm_tlv, |
| 348 | &signature_value, nullptr)) { |
| 349 | return false; |
| 350 | } |
| 351 | |
| 352 | ParsedTbsCertificate tbs; |
| 353 | if (!ParseTbsCertificate(tbs_certificate_tlv, |
| 354 | x509_util::DefaultParseCertificateOptions(), &tbs, |
| 355 | nullptr)) |
| 356 | return false; |
| 357 | if (!tbs.extensions_tlv) |
| 358 | return false; |
| 359 | |
| 360 | std::map<der::Input, ParsedExtension> extensions; |
| 361 | if (!ParseExtensions(tbs.extensions_tlv.value(), &extensions)) |
| 362 | return false; |
| 363 | |
| 364 | ParsedExtension subject_alt_names_extension; |
| 365 | if (!ConsumeExtension(der::Input(kSubjectAltNameOid), &extensions, |
| 366 | &subject_alt_names_extension)) { |
| 367 | return false; |
| 368 | } |
| 369 | |
| 370 | CertErrors errors; |
| 371 | std::unique_ptr<GeneralNames> subject_alt_names = |
| 372 | GeneralNames::Create(subject_alt_names_extension.value, &errors); |
| 373 | if (!subject_alt_names) |
| 374 | return false; |
| 375 | |
| 376 | if (dns_names) { |
| 377 | for (const auto& dns_name : subject_alt_names->dns_names) |
| 378 | dns_names->push_back(std::string(dns_name)); |
| 379 | } |
| 380 | if (ip_addrs) { |
| 381 | for (const fillins::IPAddress& addr : subject_alt_names->ip_addresses) { |
| 382 | ip_addrs->push_back( |
| 383 | std::string(reinterpret_cast<const char*>(addr.bytes().data()), |
| 384 | addr.bytes().size())); |
| 385 | } |
| 386 | } |
| 387 | |
| 388 | return !subject_alt_names->dns_names.empty() || |
| 389 | !subject_alt_names->ip_addresses.empty(); |
| 390 | } |
| 391 | |
| 392 | bool X509Certificate::HasExpired() const { |
| 393 | return absl::Now() > valid_expiry(); |
| 394 | } |
| 395 | |
| 396 | bool X509Certificate::EqualsExcludingChain(const X509Certificate* other) const { |
| 397 | return x509_util::CryptoBufferEqual(cert_buffer_.get(), |
| 398 | other->cert_buffer_.get()); |
| 399 | } |
| 400 | |
| 401 | bool X509Certificate::EqualsIncludingChain(const X509Certificate* other) const { |
| 402 | if (intermediate_ca_certs_.size() != other->intermediate_ca_certs_.size() || |
| 403 | !EqualsExcludingChain(other)) { |
| 404 | return false; |
| 405 | } |
| 406 | for (size_t i = 0; i < intermediate_ca_certs_.size(); ++i) { |
| 407 | if (!x509_util::CryptoBufferEqual(intermediate_ca_certs_[i].get(), |
| 408 | other->intermediate_ca_certs_[i].get())) { |
| 409 | return false; |
| 410 | } |
| 411 | } |
| 412 | return true; |
| 413 | } |
| 414 | |
| 415 | bool X509Certificate::IsIssuedByEncoded( |
| 416 | const std::vector<std::string>& valid_issuers) const { |
| 417 | std::vector<std::string> normalized_issuers; |
| 418 | CertErrors errors; |
| 419 | for (const auto& raw_issuer : valid_issuers) { |
| 420 | der::Input issuer_value; |
| 421 | std::string normalized_issuer; |
| 422 | if (!ParseSequenceValue(der::Input(&raw_issuer), &issuer_value) || |
| 423 | !NormalizeName(issuer_value, &normalized_issuer, &errors)) { |
| 424 | continue; |
| 425 | } |
| 426 | normalized_issuers.push_back(std::move(normalized_issuer)); |
| 427 | } |
| 428 | |
| 429 | std::string normalized_cert_issuer; |
| 430 | if (!GetNormalizedCertIssuer(cert_buffer_.get(), &normalized_cert_issuer)) |
| 431 | return false; |
| 432 | if (base::Contains(normalized_issuers, normalized_cert_issuer)) |
| 433 | return true; |
| 434 | |
| 435 | for (const auto& intermediate : intermediate_ca_certs_) { |
| 436 | if (!GetNormalizedCertIssuer(intermediate.get(), &normalized_cert_issuer)) |
| 437 | return false; |
| 438 | if (base::Contains(normalized_issuers, normalized_cert_issuer)) |
| 439 | return true; |
| 440 | } |
| 441 | return false; |
| 442 | } |
| 443 | |
| 444 | // static |
| 445 | bool X509Certificate::VerifyHostname( |
| 446 | const std::string& hostname, |
| 447 | const std::vector<std::string>& cert_san_dns_names, |
| 448 | const std::vector<std::string>& cert_san_ip_addrs) { |
| 449 | DCHECK(!hostname.empty()); |
| 450 | |
| 451 | if (cert_san_dns_names.empty() && cert_san_ip_addrs.empty()) { |
| 452 | // Either a dNSName or iPAddress subjectAltName MUST be present in order |
| 453 | // to match, so fail quickly if not. |
| 454 | return false; |
| 455 | } |
| 456 | |
| 457 | // Perform name verification following http://tools.ietf.org/html/rfc6125. |
| 458 | // The terminology used in this method is as per that RFC:- |
| 459 | // Reference identifier == the host the local user/agent is intending to |
| 460 | // access, i.e. the thing displayed in the URL bar. |
| 461 | // Presented identifier(s) == name(s) the server knows itself as, in its cert. |
| 462 | |
| 463 | // CanonicalizeHost requires surrounding brackets to parse an IPv6 address. |
| 464 | const std::string host_or_ip = hostname.find(':') != std::string::npos ? |
| 465 | "[" + hostname + "]" : hostname; |
| 466 | url::CanonHostInfo host_info; |
| 467 | std::string reference_name = CanonicalizeHost(host_or_ip, &host_info); |
| 468 | |
| 469 | // If the host cannot be canonicalized, fail fast. |
| 470 | if (reference_name.empty()) |
| 471 | return false; |
| 472 | |
| 473 | // Fully handle all cases where |hostname| contains an IP address. |
| 474 | if (host_info.IsIPAddress()) { |
| 475 | std::string_view ip_addr_string( |
| 476 | reinterpret_cast<const char*>(host_info.address), |
| 477 | host_info.AddressLength()); |
| 478 | return base::Contains(cert_san_ip_addrs, ip_addr_string); |
| 479 | } |
| 480 | |
| 481 | // The host portion of a URL may support a variety of name resolution formats |
| 482 | // and services. However, the only supported name types in this code are IP |
| 483 | // addresses, which have been handled above via iPAddress subjectAltNames, |
| 484 | // and DNS names, via dNSName subjectAltNames. |
| 485 | // Validate that the host conforms to the DNS preferred name syntax, in |
| 486 | // either relative or absolute form, and exclude the "root" label for DNS. |
| 487 | if (reference_name == "." || !IsCanonicalizedHostCompliant(reference_name)) |
| 488 | return false; |
| 489 | |
| 490 | // CanonicalizeHost does not normalize absolute vs relative DNS names. If |
| 491 | // the input name was absolute (included trailing .), normalize it as if it |
| 492 | // was relative. |
| 493 | if (reference_name.back() == '.') |
| 494 | reference_name.pop_back(); |
| 495 | |
| 496 | // |reference_domain| is the remainder of |host| after the leading host |
| 497 | // component is stripped off, but includes the leading dot e.g. |
| 498 | // "www.f.com" -> ".f.com". |
| 499 | // If there is no meaningful domain part to |host| (e.g. it contains no dots) |
| 500 | // then |reference_domain| will be empty. |
| 501 | std::string_view reference_host, reference_domain; |
| 502 | SplitOnChar(reference_name, '.', &reference_host, &reference_domain); |
| 503 | bool allow_wildcards = false; |
| 504 | if (!reference_domain.empty()) { |
| 505 | DCHECK(bssl::string_util::StartsWith(reference_domain, ".")); |
| 506 | |
| 507 | // Do not allow wildcards for public/ICANN registry controlled domains - |
| 508 | // that is, prevent *.com or *.co.uk as valid presented names, but do not |
| 509 | // prevent *.appspot.com (a private registry controlled domain). |
| 510 | // In addition, unknown top-level domains (such as 'intranet' domains or |
| 511 | // new TLDs/gTLDs not yet added to the registry controlled domain dataset) |
| 512 | // are also implicitly prevented. |
| 513 | // Because |reference_domain| must contain at least one name component that |
| 514 | // is not registry controlled, this ensures that all reference domains |
| 515 | // contain at least three domain components when using wildcards. |
| 516 | size_t registry_length = |
| 517 | registry_controlled_domains::GetCanonicalHostRegistryLength( |
| 518 | reference_name, |
| 519 | registry_controlled_domains::INCLUDE_UNKNOWN_REGISTRIES, |
| 520 | registry_controlled_domains::EXCLUDE_PRIVATE_REGISTRIES); |
| 521 | |
| 522 | // Because |reference_name| was already canonicalized, the following |
| 523 | // should never happen. |
| 524 | CHECK_NE(std::string::npos, registry_length); |
| 525 | |
| 526 | // Account for the leading dot in |reference_domain|. |
| 527 | bool is_registry_controlled = |
| 528 | registry_length != 0 && |
| 529 | registry_length == (reference_domain.size() - 1); |
| 530 | |
| 531 | // Additionally, do not attempt wildcard matching for purely numeric |
| 532 | // hostnames. |
| 533 | allow_wildcards = |
| 534 | !is_registry_controlled && |
| 535 | reference_name.find_first_not_of("0123456789.") != std::string::npos; |
| 536 | } |
| 537 | |
| 538 | // Now step through the DNS names doing wild card comparison (if necessary) |
| 539 | // on each against the reference name. |
| 540 | for (const auto& cert_san_dns_name : cert_san_dns_names) { |
| 541 | // Catch badly corrupt cert names up front. |
| 542 | if (cert_san_dns_name.empty() || |
| 543 | cert_san_dns_name.find('\0') != std::string::npos) { |
| 544 | continue; |
| 545 | } |
| 546 | std::string presented_name(base::ToLowerASCII(cert_san_dns_name)); |
| 547 | |
| 548 | // Remove trailing dot, if any. |
| 549 | if (*presented_name.rbegin() == '.') |
| 550 | presented_name.resize(presented_name.length() - 1); |
| 551 | |
| 552 | // The hostname must be at least as long as the cert name it is matching, |
| 553 | // as we require the wildcard (if present) to match at least one character. |
| 554 | if (presented_name.length() > reference_name.length()) |
| 555 | continue; |
| 556 | |
| 557 | std::string_view presented_host, presented_domain; |
| 558 | SplitOnChar(presented_name, '.', &presented_host, &presented_domain); |
| 559 | |
| 560 | if (presented_domain != reference_domain) |
| 561 | continue; |
| 562 | |
| 563 | if (presented_host != "*") { |
| 564 | if (presented_host == reference_host) |
| 565 | return true; |
| 566 | continue; |
| 567 | } |
| 568 | |
| 569 | if (!allow_wildcards) |
| 570 | continue; |
| 571 | |
| 572 | return true; |
| 573 | } |
| 574 | return false; |
| 575 | } |
| 576 | |
| 577 | bool X509Certificate::VerifyNameMatch(const std::string& hostname) const { |
| 578 | std::vector<std::string> dns_names, ip_addrs; |
| 579 | GetSubjectAltName(&dns_names, &ip_addrs); |
| 580 | return VerifyHostname(hostname, dns_names, ip_addrs); |
| 581 | } |
| 582 | |
| 583 | // static |
| 584 | bool X509Certificate::GetPEMEncodedFromDER(std::string_view der_encoded, |
| 585 | std::string* pem_encoded) { |
| 586 | if (der_encoded.empty()) |
| 587 | return false; |
| 588 | |
| 589 | *pem_encoded = PEMEncode(der_encoded, "CERTIFICATE"); |
| 590 | return true; |
| 591 | } |
| 592 | |
| 593 | // static |
| 594 | bool X509Certificate::GetPEMEncoded(const CRYPTO_BUFFER* cert_buffer, |
| 595 | std::string* pem_encoded) { |
| 596 | return GetPEMEncodedFromDER(x509_util::CryptoBufferAsStringPiece(cert_buffer), |
| 597 | pem_encoded); |
| 598 | } |
| 599 | |
| 600 | bool X509Certificate::GetPEMEncodedChain( |
| 601 | std::vector<std::string>* pem_encoded) const { |
| 602 | std::vector<std::string> encoded_chain; |
| 603 | std::string pem_data; |
| 604 | if (!GetPEMEncoded(cert_buffer(), &pem_data)) |
| 605 | return false; |
| 606 | encoded_chain.push_back(pem_data); |
| 607 | for (const auto& intermediate_ca_cert : intermediate_ca_certs_) { |
| 608 | if (!GetPEMEncoded(intermediate_ca_cert.get(), &pem_data)) |
| 609 | return false; |
| 610 | encoded_chain.push_back(pem_data); |
| 611 | } |
| 612 | pem_encoded->swap(encoded_chain); |
| 613 | return true; |
| 614 | } |
| 615 | |
| 616 | // static |
| 617 | void X509Certificate::GetPublicKeyInfo(const CRYPTO_BUFFER* cert_buffer, |
| 618 | size_t* size_bits, |
| 619 | PublicKeyType* type) { |
| 620 | *type = kPublicKeyTypeUnknown; |
| 621 | *size_bits = 0; |
| 622 | |
| 623 | std::string_view spki; |
| 624 | if (!asn1::ExtractSPKIFromDERCert( |
| 625 | std::string_view( |
| 626 | reinterpret_cast<const char*>(CRYPTO_BUFFER_data(cert_buffer)), |
| 627 | CRYPTO_BUFFER_len(cert_buffer)), |
| 628 | &spki)) { |
| 629 | return; |
| 630 | } |
| 631 | |
| 632 | bssl::UniquePtr<EVP_PKEY> pkey; |
| 633 | fillins::OpenSSLErrStackTracer err_tracer; |
| 634 | CBS cbs; |
| 635 | CBS_init(&cbs, reinterpret_cast<const uint8_t*>(spki.data()), spki.size()); |
| 636 | pkey.reset(EVP_parse_public_key(&cbs)); |
| 637 | if (!pkey) |
| 638 | return; |
| 639 | |
| 640 | switch (EVP_PKEY_id(pkey.get())) { |
| 641 | case EVP_PKEY_RSA: |
| 642 | *type = kPublicKeyTypeRSA; |
| 643 | break; |
| 644 | case EVP_PKEY_DSA: |
| 645 | *type = kPublicKeyTypeDSA; |
| 646 | break; |
| 647 | case EVP_PKEY_EC: |
| 648 | *type = kPublicKeyTypeECDSA; |
| 649 | break; |
| 650 | case EVP_PKEY_DH: |
| 651 | *type = kPublicKeyTypeDH; |
| 652 | break; |
| 653 | } |
| 654 | *size_bits = base::saturated_cast<size_t>(EVP_PKEY_bits(pkey.get())); |
| 655 | } |
| 656 | |
| 657 | // static |
| 658 | std::vector<bssl::UniquePtr<CRYPTO_BUFFER>> |
| 659 | X509Certificate::CreateCertBuffersFromBytes(bssl::Span<const uint8_t> data, |
| 660 | Format format) { |
| 661 | std::vector<bssl::UniquePtr<CRYPTO_BUFFER>> results; |
| 662 | |
| 663 | switch (format) { |
| 664 | case FORMAT_SINGLE_CERTIFICATE: { |
| 665 | bssl::UniquePtr<CRYPTO_BUFFER> handle = |
| 666 | CreateCertBufferFromBytesWithSanityCheck(data); |
| 667 | if (handle) |
| 668 | results.push_back(std::move(handle)); |
| 669 | break; |
| 670 | } |
| 671 | case FORMAT_PKCS7: { |
| 672 | x509_util::CreateCertBuffersFromPKCS7Bytes(data, &results); |
| 673 | break; |
| 674 | } |
| 675 | default: { |
| 676 | abort(); //NOTREACHED << "Certificate format " << format << " unimplemented"; |
| 677 | break; |
| 678 | } |
| 679 | } |
| 680 | |
| 681 | return results; |
| 682 | } |
| 683 | |
| 684 | // static |
| 685 | SHA256HashValue X509Certificate::CalculateFingerprint256( |
| 686 | const CRYPTO_BUFFER* cert) { |
| 687 | SHA256HashValue sha256; |
| 688 | |
| 689 | SHA256(CRYPTO_BUFFER_data(cert), CRYPTO_BUFFER_len(cert), sha256.data); |
| 690 | return sha256; |
| 691 | } |
| 692 | |
| 693 | SHA256HashValue X509Certificate::CalculateChainFingerprint256() const { |
| 694 | SHA256HashValue sha256; |
| 695 | memset(sha256.data, 0, sizeof(sha256.data)); |
| 696 | |
| 697 | SHA256_CTX sha256_ctx; |
| 698 | SHA256_Init(&sha256_ctx); |
| 699 | SHA256_Update(&sha256_ctx, CRYPTO_BUFFER_data(cert_buffer_.get()), |
| 700 | CRYPTO_BUFFER_len(cert_buffer_.get())); |
| 701 | for (const auto& cert : intermediate_ca_certs_) { |
| 702 | SHA256_Update(&sha256_ctx, CRYPTO_BUFFER_data(cert.get()), |
| 703 | CRYPTO_BUFFER_len(cert.get())); |
| 704 | } |
| 705 | SHA256_Final(sha256.data, &sha256_ctx); |
| 706 | |
| 707 | return sha256; |
| 708 | } |
| 709 | |
| 710 | // static |
| 711 | bool X509Certificate::IsSelfSigned(CRYPTO_BUFFER* cert_buffer) { |
| 712 | std::shared_ptr<const ParsedCertificate> parsed_cert = |
| 713 | ParsedCertificate::Create(bssl::UpRef(cert_buffer), |
| 714 | x509_util::DefaultParseCertificateOptions(), |
| 715 | /*errors=*/nullptr); |
| 716 | if (!parsed_cert) { |
| 717 | return false; |
| 718 | } |
| 719 | return VerifyCertificateIsSelfSigned(*parsed_cert, /*cache=*/nullptr, |
| 720 | /*errors=*/nullptr); |
| 721 | } |
| 722 | |
| 723 | X509Certificate::X509Certificate( |
| 724 | ParsedFields parsed, |
| 725 | bssl::UniquePtr<CRYPTO_BUFFER> cert_buffer, |
| 726 | std::vector<bssl::UniquePtr<CRYPTO_BUFFER>> intermediates) |
| 727 | : parsed_(std::move(parsed)), |
| 728 | cert_buffer_(std::move(cert_buffer)), |
| 729 | intermediate_ca_certs_(std::move(intermediates)) {} |
| 730 | |
| 731 | X509Certificate::X509Certificate( |
| 732 | const X509Certificate& other, |
| 733 | std::vector<bssl::UniquePtr<CRYPTO_BUFFER>> intermediates) |
| 734 | : parsed_(other.parsed_), |
| 735 | cert_buffer_(bssl::UpRef(other.cert_buffer_)), |
| 736 | intermediate_ca_certs_(std::move(intermediates)) {} |
| 737 | |
| 738 | X509Certificate::~X509Certificate() = default; |
| 739 | |
| 740 | X509Certificate::ParsedFields::ParsedFields() = default; |
| 741 | X509Certificate::ParsedFields::ParsedFields(const ParsedFields&) = default; |
| 742 | X509Certificate::ParsedFields::ParsedFields(ParsedFields&&) = default; |
| 743 | X509Certificate::ParsedFields::~ParsedFields() = default; |
| 744 | |
| 745 | bool X509Certificate::ParsedFields::Initialize( |
| 746 | const CRYPTO_BUFFER* cert_buffer, |
| 747 | X509Certificate::UnsafeCreateOptions options) { |
| 748 | der::Input tbs_certificate_tlv; |
| 749 | der::Input signature_algorithm_tlv; |
| 750 | der::BitString signature_value; |
| 751 | |
| 752 | if (!ParseCertificate(der::Input(CRYPTO_BUFFER_data(cert_buffer), |
| 753 | CRYPTO_BUFFER_len(cert_buffer)), |
| 754 | &tbs_certificate_tlv, &signature_algorithm_tlv, |
| 755 | &signature_value, nullptr)) { |
| 756 | return false; |
| 757 | } |
| 758 | |
| 759 | ParsedTbsCertificate tbs; |
| 760 | if (!ParseTbsCertificate(tbs_certificate_tlv, |
| 761 | x509_util::DefaultParseCertificateOptions(), &tbs, |
| 762 | nullptr)) |
| 763 | return false; |
| 764 | |
| 765 | CertPrincipal::PrintableStringHandling printable_string_handling = |
| 766 | options.printable_string_is_utf8 |
| 767 | ? CertPrincipal::PrintableStringHandling::kAsUTF8Hack |
| 768 | : CertPrincipal::PrintableStringHandling::kDefault; |
| 769 | if (!subject_.ParseDistinguishedName(tbs.subject_tlv, |
| 770 | printable_string_handling) || |
| 771 | !issuer_.ParseDistinguishedName(tbs.issuer_tlv, |
| 772 | printable_string_handling)) { |
| 773 | return false; |
| 774 | } |
| 775 | |
| 776 | if (!GeneralizedTimeToTime(tbs.validity_not_before, &valid_start_) || |
| 777 | !GeneralizedTimeToTime(tbs.validity_not_after, &valid_expiry_)) { |
| 778 | return false; |
| 779 | } |
| 780 | serial_number_ = tbs.serial_number.AsString(); |
| 781 | return true; |
| 782 | } |
| 783 | |
| 784 | } // namespace net |