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