x509_certificate.cc revision c2e0dbddbe15c98d52c4786dac06cb8952a8ae6d
1// Copyright (c) 2012 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 <stdlib.h> 8 9#include <algorithm> 10#include <map> 11#include <string> 12#include <vector> 13 14#include "base/base64.h" 15#include "base/lazy_instance.h" 16#include "base/logging.h" 17#include "base/memory/singleton.h" 18#include "base/metrics/histogram.h" 19#include "base/pickle.h" 20#include "base/sha1.h" 21#include "base/string_util.h" 22#include "base/strings/string_piece.h" 23#include "base/synchronization/lock.h" 24#include "base/time.h" 25#include "googleurl/src/url_canon_ip.h" 26#include "net/base/net_util.h" 27#include "net/cert/pem_tokenizer.h" 28 29namespace net { 30 31namespace { 32 33// Indicates the order to use when trying to decode binary data, which is 34// based on (speculation) as to what will be most common -> least common 35const X509Certificate::Format kFormatDecodePriority[] = { 36 X509Certificate::FORMAT_SINGLE_CERTIFICATE, 37 X509Certificate::FORMAT_PKCS7 38}; 39 40// The PEM block header used for DER certificates 41const char kCertificateHeader[] = "CERTIFICATE"; 42// The PEM block header used for PKCS#7 data 43const char kPKCS7Header[] = "PKCS7"; 44 45#if !defined(USE_NSS) 46// A thread-safe cache for OS certificate handles. 47// 48// Within each of the supported underlying crypto libraries, a certificate 49// handle is represented as a ref-counted object that contains the parsed 50// data for the certificate. In addition, the underlying OS handle may also 51// contain a copy of the original ASN.1 DER used to constructed the handle. 52// 53// In order to reduce the memory usage when multiple SSL connections exist, 54// with each connection storing the server's identity certificate plus any 55// intermediates supplied, the certificate handles are cached. Any two 56// X509Certificates that were created from the same ASN.1 DER data, 57// regardless of where that data came from, will share the same underlying 58// OS certificate handle. 59class X509CertificateCache { 60 public: 61 // Performs a compare-and-swap like operation. If an OS certificate handle 62 // for the same certificate data as |*cert_handle| already exists in the 63 // cache, the original |*cert_handle| will be freed and |cert_handle| 64 // will be updated to point to a duplicated reference to the existing cached 65 // certificate, with the caller taking ownership of this duplicated handle. 66 // If an equivalent OS certificate handle is not found, a duplicated 67 // reference to |*cert_handle| will be added to the cache. In either case, 68 // upon return, the caller fully owns |*cert_handle| and is responsible for 69 // calling FreeOSCertHandle(), after first calling Remove(). 70 void InsertOrUpdate(X509Certificate::OSCertHandle* cert_handle); 71 72 // Decrements the cache reference count for |cert_handle|, a handle that was 73 // previously obtained by calling InsertOrUpdate(). If this is the last 74 // cached reference held, this will remove the handle from the cache. The 75 // caller retains ownership of |cert_handle| and remains responsible for 76 // calling FreeOSCertHandle() to release the underlying OS certificate 77 void Remove(X509Certificate::OSCertHandle cert_handle); 78 79 private: 80 // A single entry in the cache. Certificates will be keyed by their SHA1 81 // fingerprints, but will not be considered equivalent unless the entire 82 // certificate data matches. 83 struct Entry { 84 Entry() : cert_handle(NULL), ref_count(0) {} 85 86 X509Certificate::OSCertHandle cert_handle; 87 88 // Increased by each call to InsertOrUpdate(), and balanced by each call 89 // to Remove(). When it equals 0, all references created by 90 // InsertOrUpdate() have been released, so the cache entry will be removed 91 // the cached OS certificate handle will be freed. 92 int ref_count; 93 }; 94 typedef std::map<SHA1HashValue, Entry, SHA1HashValueLessThan> CertMap; 95 96 // Obtain an instance of X509CertificateCache via a LazyInstance. 97 X509CertificateCache() {} 98 ~X509CertificateCache() {} 99 friend struct base::DefaultLazyInstanceTraits<X509CertificateCache>; 100 101 // You must acquire this lock before using any private data of this object 102 // You must not block while holding this lock. 103 base::Lock lock_; 104 105 // The certificate cache. You must acquire |lock_| before using |cache_|. 106 CertMap cache_; 107 108 DISALLOW_COPY_AND_ASSIGN(X509CertificateCache); 109}; 110 111base::LazyInstance<X509CertificateCache>::Leaky 112 g_x509_certificate_cache = LAZY_INSTANCE_INITIALIZER; 113 114void X509CertificateCache::InsertOrUpdate( 115 X509Certificate::OSCertHandle* cert_handle) { 116 DCHECK(cert_handle); 117 SHA1HashValue fingerprint = 118 X509Certificate::CalculateFingerprint(*cert_handle); 119 120 X509Certificate::OSCertHandle old_handle = NULL; 121 { 122 base::AutoLock lock(lock_); 123 CertMap::iterator pos = cache_.find(fingerprint); 124 if (pos == cache_.end()) { 125 // A cached entry was not found, so initialize a new entry. The entry 126 // assumes ownership of the current |*cert_handle|. 127 Entry cache_entry; 128 cache_entry.cert_handle = *cert_handle; 129 cache_entry.ref_count = 0; 130 CertMap::value_type cache_value(fingerprint, cache_entry); 131 pos = cache_.insert(cache_value).first; 132 } else { 133 bool is_same_cert = 134 X509Certificate::IsSameOSCert(*cert_handle, pos->second.cert_handle); 135 if (!is_same_cert) { 136 // Two certificates don't match, due to a SHA1 hash collision. Given 137 // the low probability, the simplest solution is to not cache the 138 // certificate, which should not affect performance too negatively. 139 return; 140 } 141 // A cached entry was found and will be used instead of the caller's 142 // handle. Ensure the caller's original handle will be freed, since 143 // ownership is assumed. 144 old_handle = *cert_handle; 145 } 146 // Whether an existing cached handle or a new handle, increment the 147 // cache's reference count and return a handle that the caller can own. 148 ++pos->second.ref_count; 149 *cert_handle = X509Certificate::DupOSCertHandle(pos->second.cert_handle); 150 } 151 // If the caller's handle was replaced with a cached handle, free the 152 // original handle now. This is done outside of the lock because 153 // |old_handle| may be the only handle for this particular certificate, so 154 // freeing it may be complex or resource-intensive and does not need to 155 // be guarded by the lock. 156 if (old_handle) { 157 X509Certificate::FreeOSCertHandle(old_handle); 158 DHISTOGRAM_COUNTS("X509CertificateReuseCount", 1); 159 } 160} 161 162void X509CertificateCache::Remove(X509Certificate::OSCertHandle cert_handle) { 163 SHA1HashValue fingerprint = 164 X509Certificate::CalculateFingerprint(cert_handle); 165 base::AutoLock lock(lock_); 166 167 CertMap::iterator pos = cache_.find(fingerprint); 168 if (pos == cache_.end()) 169 return; // A hash collision where the winning cert was already freed. 170 171 bool is_same_cert = X509Certificate::IsSameOSCert(cert_handle, 172 pos->second.cert_handle); 173 if (!is_same_cert) 174 return; // A hash collision where the winning cert is still around. 175 176 if (--pos->second.ref_count == 0) { 177 // The last reference to |cert_handle| has been removed, so release the 178 // Entry's OS handle and remove the Entry. The caller still holds a 179 // reference to |cert_handle| and is responsible for freeing it. 180 X509Certificate::FreeOSCertHandle(pos->second.cert_handle); 181 cache_.erase(pos); 182 } 183} 184#endif // !defined(USE_NSS) 185 186// See X509CertificateCache::InsertOrUpdate. NSS has a built-in cache, so there 187// is no point in wrapping another cache around it. 188void InsertOrUpdateCache(X509Certificate::OSCertHandle* cert_handle) { 189#if !defined(USE_NSS) 190 g_x509_certificate_cache.Pointer()->InsertOrUpdate(cert_handle); 191#endif 192} 193 194// See X509CertificateCache::Remove. 195void RemoveFromCache(X509Certificate::OSCertHandle cert_handle) { 196#if !defined(USE_NSS) 197 g_x509_certificate_cache.Pointer()->Remove(cert_handle); 198#endif 199} 200 201// Utility to split |src| on the first occurrence of |c|, if any. |right| will 202// either be empty if |c| was not found, or will contain the remainder of the 203// string including the split character itself. 204void SplitOnChar(const base::StringPiece& src, 205 char c, 206 base::StringPiece* left, 207 base::StringPiece* right) { 208 size_t pos = src.find(c); 209 if (pos == base::StringPiece::npos) { 210 *left = src; 211 right->clear(); 212 } else { 213 *left = src.substr(0, pos); 214 *right = src.substr(pos); 215 } 216} 217 218} // namespace 219 220bool X509Certificate::LessThan::operator()(X509Certificate* lhs, 221 X509Certificate* rhs) const { 222 if (lhs == rhs) 223 return false; 224 225 int rv = memcmp(lhs->fingerprint_.data, rhs->fingerprint_.data, 226 sizeof(lhs->fingerprint_.data)); 227 if (rv != 0) 228 return rv < 0; 229 230 rv = memcmp(lhs->ca_fingerprint_.data, rhs->ca_fingerprint_.data, 231 sizeof(lhs->ca_fingerprint_.data)); 232 return rv < 0; 233} 234 235X509Certificate::X509Certificate(const std::string& subject, 236 const std::string& issuer, 237 base::Time start_date, 238 base::Time expiration_date) 239 : subject_(subject), 240 issuer_(issuer), 241 valid_start_(start_date), 242 valid_expiry_(expiration_date), 243 cert_handle_(NULL) { 244 memset(fingerprint_.data, 0, sizeof(fingerprint_.data)); 245 memset(ca_fingerprint_.data, 0, sizeof(ca_fingerprint_.data)); 246} 247 248// static 249X509Certificate* X509Certificate::CreateFromHandle( 250 OSCertHandle cert_handle, 251 const OSCertHandles& intermediates) { 252 DCHECK(cert_handle); 253 return new X509Certificate(cert_handle, intermediates); 254} 255 256// static 257X509Certificate* X509Certificate::CreateFromDERCertChain( 258 const std::vector<base::StringPiece>& der_certs) { 259 if (der_certs.empty()) 260 return NULL; 261 262 X509Certificate::OSCertHandles intermediate_ca_certs; 263 for (size_t i = 1; i < der_certs.size(); i++) { 264 OSCertHandle handle = CreateOSCertHandleFromBytes( 265 const_cast<char*>(der_certs[i].data()), der_certs[i].size()); 266 if (!handle) 267 break; 268 intermediate_ca_certs.push_back(handle); 269 } 270 271 OSCertHandle handle = NULL; 272 // Return NULL if we failed to parse any of the certs. 273 if (der_certs.size() - 1 == intermediate_ca_certs.size()) { 274 handle = CreateOSCertHandleFromBytes( 275 const_cast<char*>(der_certs[0].data()), der_certs[0].size()); 276 } 277 278 X509Certificate* cert = NULL; 279 if (handle) { 280 cert = CreateFromHandle(handle, intermediate_ca_certs); 281 FreeOSCertHandle(handle); 282 } 283 284 for (size_t i = 0; i < intermediate_ca_certs.size(); i++) 285 FreeOSCertHandle(intermediate_ca_certs[i]); 286 287 return cert; 288} 289 290// static 291X509Certificate* X509Certificate::CreateFromBytes(const char* data, 292 int length) { 293 OSCertHandle cert_handle = CreateOSCertHandleFromBytes(data, length); 294 if (!cert_handle) 295 return NULL; 296 297 X509Certificate* cert = CreateFromHandle(cert_handle, OSCertHandles()); 298 FreeOSCertHandle(cert_handle); 299 return cert; 300} 301 302// static 303X509Certificate* X509Certificate::CreateFromPickle(const Pickle& pickle, 304 PickleIterator* pickle_iter, 305 PickleType type) { 306 if (type == PICKLETYPE_CERTIFICATE_CHAIN_V3) { 307 int chain_length = 0; 308 if (!pickle_iter->ReadLength(&chain_length)) 309 return NULL; 310 311 std::vector<base::StringPiece> cert_chain; 312 const char* data = NULL; 313 int data_length = 0; 314 for (int i = 0; i < chain_length; ++i) { 315 if (!pickle_iter->ReadData(&data, &data_length)) 316 return NULL; 317 cert_chain.push_back(base::StringPiece(data, data_length)); 318 } 319 return CreateFromDERCertChain(cert_chain); 320 } 321 322 // Legacy / Migration code. This should eventually be removed once 323 // sufficient time has passed that all pickles serialized prior to 324 // PICKLETYPE_CERTIFICATE_CHAIN_V3 have been removed. 325 OSCertHandle cert_handle = ReadOSCertHandleFromPickle(pickle_iter); 326 if (!cert_handle) 327 return NULL; 328 329 OSCertHandles intermediates; 330 uint32 num_intermediates = 0; 331 if (type != PICKLETYPE_SINGLE_CERTIFICATE) { 332 if (!pickle_iter->ReadUInt32(&num_intermediates)) { 333 FreeOSCertHandle(cert_handle); 334 return NULL; 335 } 336 337#if defined(OS_POSIX) && !defined(OS_MACOSX) && defined(__x86_64__) 338 // On 64-bit Linux (and any other 64-bit platforms), the intermediate count 339 // might really be a 64-bit field since we used to use Pickle::WriteSize(), 340 // which writes either 32 or 64 bits depending on the architecture. Since 341 // x86-64 is little-endian, if that happens, the next 32 bits will be all 342 // zeroes (the high bits) and the 32 bits we already read above are the 343 // correct value (we assume there are never more than 2^32 - 1 intermediate 344 // certificates in a chain; in practice, more than a dozen or so is 345 // basically unheard of). Since it's invalid for a certificate to start with 346 // 32 bits of zeroes, we check for that here and skip it if we find it. We 347 // save a copy of the pickle iterator to restore in case we don't get 32 348 // bits of zeroes. Now we always write 32 bits, so after a while, these old 349 // cached pickles will all get replaced. 350 // TODO(mdm): remove this compatibility code in April 2013 or so. 351 PickleIterator saved_iter = *pickle_iter; 352 uint32 zero_check = 0; 353 if (!pickle_iter->ReadUInt32(&zero_check)) { 354 // This may not be an error. If there are no intermediates, and we're 355 // reading an old 32-bit pickle, and there's nothing else after this in 356 // the pickle, we should report success. Note that it is technically 357 // possible for us to skip over zeroes that should have occurred after 358 // an empty certificate list; to avoid this going forward, only do this 359 // backward-compatibility stuff for PICKLETYPE_CERTIFICATE_CHAIN_V1 360 // which comes from the pickle version number in http_response_info.cc. 361 if (num_intermediates) { 362 FreeOSCertHandle(cert_handle); 363 return NULL; 364 } 365 } 366 if (zero_check) 367 *pickle_iter = saved_iter; 368#endif // defined(OS_POSIX) && !defined(OS_MACOSX) && defined(__x86_64__) 369 370 for (uint32 i = 0; i < num_intermediates; ++i) { 371 OSCertHandle intermediate = ReadOSCertHandleFromPickle(pickle_iter); 372 if (!intermediate) 373 break; 374 intermediates.push_back(intermediate); 375 } 376 } 377 378 X509Certificate* cert = NULL; 379 if (intermediates.size() == num_intermediates) 380 cert = CreateFromHandle(cert_handle, intermediates); 381 FreeOSCertHandle(cert_handle); 382 for (size_t i = 0; i < intermediates.size(); ++i) 383 FreeOSCertHandle(intermediates[i]); 384 385 return cert; 386} 387 388// static 389CertificateList X509Certificate::CreateCertificateListFromBytes( 390 const char* data, int length, int format) { 391 OSCertHandles certificates; 392 393 // Check to see if it is in a PEM-encoded form. This check is performed 394 // first, as both OS X and NSS will both try to convert if they detect 395 // PEM encoding, except they don't do it consistently between the two. 396 base::StringPiece data_string(data, length); 397 std::vector<std::string> pem_headers; 398 399 // To maintain compatibility with NSS/Firefox, CERTIFICATE is a universally 400 // valid PEM block header for any format. 401 pem_headers.push_back(kCertificateHeader); 402 if (format & FORMAT_PKCS7) 403 pem_headers.push_back(kPKCS7Header); 404 405 PEMTokenizer pem_tok(data_string, pem_headers); 406 while (pem_tok.GetNext()) { 407 std::string decoded(pem_tok.data()); 408 409 OSCertHandle handle = NULL; 410 if (format & FORMAT_PEM_CERT_SEQUENCE) 411 handle = CreateOSCertHandleFromBytes(decoded.c_str(), decoded.size()); 412 if (handle != NULL) { 413 // Parsed a DER encoded certificate. All PEM blocks that follow must 414 // also be DER encoded certificates wrapped inside of PEM blocks. 415 format = FORMAT_PEM_CERT_SEQUENCE; 416 certificates.push_back(handle); 417 continue; 418 } 419 420 // If the first block failed to parse as a DER certificate, and 421 // formats other than PEM are acceptable, check to see if the decoded 422 // data is one of the accepted formats. 423 if (format & ~FORMAT_PEM_CERT_SEQUENCE) { 424 for (size_t i = 0; certificates.empty() && 425 i < arraysize(kFormatDecodePriority); ++i) { 426 if (format & kFormatDecodePriority[i]) { 427 certificates = CreateOSCertHandlesFromBytes(decoded.c_str(), 428 decoded.size(), kFormatDecodePriority[i]); 429 } 430 } 431 } 432 433 // Stop parsing after the first block for any format but a sequence of 434 // PEM-encoded DER certificates. The case of FORMAT_PEM_CERT_SEQUENCE 435 // is handled above, and continues processing until a certificate fails 436 // to parse. 437 break; 438 } 439 440 // Try each of the formats, in order of parse preference, to see if |data| 441 // contains the binary representation of a Format, if it failed to parse 442 // as a PEM certificate/chain. 443 for (size_t i = 0; certificates.empty() && 444 i < arraysize(kFormatDecodePriority); ++i) { 445 if (format & kFormatDecodePriority[i]) 446 certificates = CreateOSCertHandlesFromBytes(data, length, 447 kFormatDecodePriority[i]); 448 } 449 450 CertificateList results; 451 // No certificates parsed. 452 if (certificates.empty()) 453 return results; 454 455 for (OSCertHandles::iterator it = certificates.begin(); 456 it != certificates.end(); ++it) { 457 X509Certificate* result = CreateFromHandle(*it, OSCertHandles()); 458 results.push_back(scoped_refptr<X509Certificate>(result)); 459 FreeOSCertHandle(*it); 460 } 461 462 return results; 463} 464 465void X509Certificate::Persist(Pickle* pickle) { 466 DCHECK(cert_handle_); 467 // This would be an absolutely insane number of intermediates. 468 if (intermediate_ca_certs_.size() > static_cast<size_t>(INT_MAX) - 1) { 469 NOTREACHED(); 470 return; 471 } 472 if (!pickle->WriteInt( 473 static_cast<int>(intermediate_ca_certs_.size() + 1)) || 474 !WriteOSCertHandleToPickle(cert_handle_, pickle)) { 475 NOTREACHED(); 476 return; 477 } 478 for (size_t i = 0; i < intermediate_ca_certs_.size(); ++i) { 479 if (!WriteOSCertHandleToPickle(intermediate_ca_certs_[i], pickle)) { 480 NOTREACHED(); 481 return; 482 } 483 } 484} 485 486void X509Certificate::GetDNSNames(std::vector<std::string>* dns_names) const { 487 GetSubjectAltName(dns_names, NULL); 488 if (dns_names->empty()) 489 dns_names->push_back(subject_.common_name); 490} 491 492bool X509Certificate::HasExpired() const { 493 return base::Time::Now() > valid_expiry(); 494} 495 496bool X509Certificate::Equals(const X509Certificate* other) const { 497 return IsSameOSCert(cert_handle_, other->cert_handle_); 498} 499 500// static 501bool X509Certificate::VerifyHostname( 502 const std::string& hostname, 503 const std::string& cert_common_name, 504 const std::vector<std::string>& cert_san_dns_names, 505 const std::vector<std::string>& cert_san_ip_addrs) { 506 DCHECK(!hostname.empty()); 507 // Perform name verification following http://tools.ietf.org/html/rfc6125. 508 // The terminology used in this method is as per that RFC:- 509 // Reference identifier == the host the local user/agent is intending to 510 // access, i.e. the thing displayed in the URL bar. 511 // Presented identifier(s) == name(s) the server knows itself as, in its cert. 512 513 // CanonicalizeHost requires surrounding brackets to parse an IPv6 address. 514 const std::string host_or_ip = hostname.find(':') != std::string::npos ? 515 "[" + hostname + "]" : hostname; 516 url_canon::CanonHostInfo host_info; 517 std::string reference_name = CanonicalizeHost(host_or_ip, &host_info); 518 // CanonicalizeHost does not normalize absolute vs relative DNS names. If 519 // the input name was absolute (included trailing .), normalize it as if it 520 // was relative. 521 if (!reference_name.empty() && *reference_name.rbegin() == '.') 522 reference_name.resize(reference_name.size() - 1); 523 if (reference_name.empty()) 524 return false; 525 526 // Allow fallback to Common name matching? 527 const bool common_name_fallback = cert_san_dns_names.empty() && 528 cert_san_ip_addrs.empty(); 529 530 // Fully handle all cases where |hostname| contains an IP address. 531 if (host_info.IsIPAddress()) { 532 if (common_name_fallback && 533 host_info.family == url_canon::CanonHostInfo::IPV4) { 534 // Fallback to Common name matching. As this is deprecated and only 535 // supported for compatibility refuse it for IPv6 addresses. 536 return reference_name == cert_common_name; 537 } 538 base::StringPiece ip_addr_string( 539 reinterpret_cast<const char*>(host_info.address), 540 host_info.AddressLength()); 541 return std::find(cert_san_ip_addrs.begin(), cert_san_ip_addrs.end(), 542 ip_addr_string) != cert_san_ip_addrs.end(); 543 } 544 545 // |reference_domain| is the remainder of |host| after the leading host 546 // component is stripped off, but includes the leading dot e.g. 547 // "www.f.com" -> ".f.com". 548 // If there is no meaningful domain part to |host| (e.g. it contains no dots) 549 // then |reference_domain| will be empty. 550 base::StringPiece reference_host, reference_domain; 551 SplitOnChar(reference_name, '.', &reference_host, &reference_domain); 552 bool allow_wildcards = false; 553 if (!reference_domain.empty()) { 554 DCHECK(reference_domain.starts_with(".")); 555 // We required at least 3 components (i.e. 2 dots) as a basic protection 556 // against too-broad wild-carding. 557 // Also we don't attempt wildcard matching on a purely numerical hostname. 558 allow_wildcards = reference_domain.rfind('.') != 0 && 559 reference_name.find_first_not_of("0123456789.") != std::string::npos; 560 } 561 562 // Now step through the DNS names doing wild card comparison (if necessary) 563 // on each against the reference name. If subjectAltName is empty, then 564 // fallback to use the common name instead. 565 std::vector<std::string> common_name_as_vector; 566 const std::vector<std::string>* presented_names = &cert_san_dns_names; 567 if (common_name_fallback) { 568 // Note: there's a small possibility cert_common_name is an international 569 // domain name in non-standard encoding (e.g. UTF8String or BMPString 570 // instead of A-label). As common name fallback is deprecated we're not 571 // doing anything specific to deal with this. 572 common_name_as_vector.push_back(cert_common_name); 573 presented_names = &common_name_as_vector; 574 } 575 for (std::vector<std::string>::const_iterator it = 576 presented_names->begin(); 577 it != presented_names->end(); ++it) { 578 // Catch badly corrupt cert names up front. 579 if (it->empty() || it->find('\0') != std::string::npos) { 580 DVLOG(1) << "Bad name in cert: " << *it; 581 continue; 582 } 583 std::string presented_name(StringToLowerASCII(*it)); 584 585 // Remove trailing dot, if any. 586 if (*presented_name.rbegin() == '.') 587 presented_name.resize(presented_name.length() - 1); 588 589 // The hostname must be at least as long as the cert name it is matching, 590 // as we require the wildcard (if present) to match at least one character. 591 if (presented_name.length() > reference_name.length()) 592 continue; 593 594 base::StringPiece presented_host, presented_domain; 595 SplitOnChar(presented_name, '.', &presented_host, &presented_domain); 596 597 if (presented_domain != reference_domain) 598 continue; 599 600 base::StringPiece pattern_begin, pattern_end; 601 SplitOnChar(presented_host, '*', &pattern_begin, &pattern_end); 602 603 if (pattern_end.empty()) { // No '*' in the presented_host 604 if (presented_host == reference_host) 605 return true; 606 continue; 607 } 608 pattern_end.remove_prefix(1); // move past the * 609 610 if (!allow_wildcards) 611 continue; 612 613 // * must not match a substring of an IDN A label; just a whole fragment. 614 if (reference_host.starts_with("xn--") && 615 !(pattern_begin.empty() && pattern_end.empty())) 616 continue; 617 618 if (reference_host.starts_with(pattern_begin) && 619 reference_host.ends_with(pattern_end)) 620 return true; 621 } 622 return false; 623} 624 625#if !defined(USE_NSS) 626bool X509Certificate::VerifyNameMatch(const std::string& hostname) const { 627 std::vector<std::string> dns_names, ip_addrs; 628 GetSubjectAltName(&dns_names, &ip_addrs); 629 return VerifyHostname(hostname, subject_.common_name, dns_names, ip_addrs); 630} 631#endif 632 633// static 634bool X509Certificate::GetPEMEncoded(OSCertHandle cert_handle, 635 std::string* pem_encoded) { 636 std::string der_encoded; 637 if (!GetDEREncoded(cert_handle, &der_encoded) || der_encoded.empty()) 638 return false; 639 std::string b64_encoded; 640 if (!base::Base64Encode(der_encoded, &b64_encoded) || b64_encoded.empty()) 641 return false; 642 *pem_encoded = "-----BEGIN CERTIFICATE-----\n"; 643 644 // Divide the Base-64 encoded data into 64-character chunks, as per 645 // 4.3.2.4 of RFC 1421. 646 static const size_t kChunkSize = 64; 647 size_t chunks = (b64_encoded.size() + (kChunkSize - 1)) / kChunkSize; 648 for (size_t i = 0, chunk_offset = 0; i < chunks; 649 ++i, chunk_offset += kChunkSize) { 650 pem_encoded->append(b64_encoded, chunk_offset, kChunkSize); 651 pem_encoded->append("\n"); 652 } 653 pem_encoded->append("-----END CERTIFICATE-----\n"); 654 return true; 655} 656 657bool X509Certificate::GetPEMEncodedChain( 658 std::vector<std::string>* pem_encoded) const { 659 std::vector<std::string> encoded_chain; 660 std::string pem_data; 661 if (!GetPEMEncoded(os_cert_handle(), &pem_data)) 662 return false; 663 encoded_chain.push_back(pem_data); 664 for (size_t i = 0; i < intermediate_ca_certs_.size(); ++i) { 665 if (!GetPEMEncoded(intermediate_ca_certs_[i], &pem_data)) 666 return false; 667 encoded_chain.push_back(pem_data); 668 } 669 pem_encoded->swap(encoded_chain); 670 return true; 671} 672 673X509Certificate::X509Certificate(OSCertHandle cert_handle, 674 const OSCertHandles& intermediates) 675 : cert_handle_(DupOSCertHandle(cert_handle)) { 676 InsertOrUpdateCache(&cert_handle_); 677 for (size_t i = 0; i < intermediates.size(); ++i) { 678 // Duplicate the incoming certificate, as the caller retains ownership 679 // of |intermediates|. 680 OSCertHandle intermediate = DupOSCertHandle(intermediates[i]); 681 // Update the cache, which will assume ownership of the duplicated 682 // handle and return a suitable equivalent, potentially from the cache. 683 InsertOrUpdateCache(&intermediate); 684 intermediate_ca_certs_.push_back(intermediate); 685 } 686 // Platform-specific initialization. 687 Initialize(); 688} 689 690X509Certificate::~X509Certificate() { 691 if (cert_handle_) { 692 RemoveFromCache(cert_handle_); 693 FreeOSCertHandle(cert_handle_); 694 } 695 for (size_t i = 0; i < intermediate_ca_certs_.size(); ++i) { 696 RemoveFromCache(intermediate_ca_certs_[i]); 697 FreeOSCertHandle(intermediate_ca_certs_[i]); 698 } 699} 700 701} // namespace net 702