| OLD | NEW |
| (Empty) |
| 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/base/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_piece.h" | |
| 22 #include "base/string_util.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/base/pem_tokenizer.h" | |
| 28 | |
| 29 namespace net { | |
| 30 | |
| 31 namespace { | |
| 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 | |
| 35 const X509Certificate::Format kFormatDecodePriority[] = { | |
| 36 X509Certificate::FORMAT_SINGLE_CERTIFICATE, | |
| 37 X509Certificate::FORMAT_PKCS7 | |
| 38 }; | |
| 39 | |
| 40 // The PEM block header used for DER certificates | |
| 41 const char kCertificateHeader[] = "CERTIFICATE"; | |
| 42 // The PEM block header used for PKCS#7 data | |
| 43 const 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. | |
| 59 class 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 | |
| 111 base::LazyInstance<X509CertificateCache>::Leaky | |
| 112 g_x509_certificate_cache = LAZY_INSTANCE_INITIALIZER; | |
| 113 | |
| 114 void 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 | |
| 162 void 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. | |
| 188 void 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. | |
| 195 void 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. | |
| 204 void 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 | |
| 220 bool 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 | |
| 235 X509Certificate::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 | |
| 249 X509Certificate* 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 | |
| 257 X509Certificate* 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 | |
| 291 X509Certificate* 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 | |
| 303 X509Certificate* 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 | |
| 389 CertificateList 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 | |
| 465 void 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 | |
| 486 void 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 | |
| 492 bool X509Certificate::HasExpired() const { | |
| 493 return base::Time::Now() > valid_expiry(); | |
| 494 } | |
| 495 | |
| 496 bool X509Certificate::Equals(const X509Certificate* other) const { | |
| 497 return IsSameOSCert(cert_handle_, other->cert_handle_); | |
| 498 } | |
| 499 | |
| 500 // static | |
| 501 bool 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) | |
| 626 bool 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 | |
| 634 bool 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 | |
| 657 bool 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 | |
| 673 X509Certificate::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 | |
| 690 X509Certificate::~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 | |
| OLD | NEW |