| OLD | NEW |
| 1 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "net/base/x509_certificate.h" | 5 #include "net/base/x509_certificate.h" |
| 6 | 6 |
| 7 #include "base/histogram.h" | |
| 8 #include "base/logging.h" | 7 #include "base/logging.h" |
| 9 #include "base/pickle.h" | 8 #include "base/pickle.h" |
| 10 #include "base/string_tokenizer.h" | 9 #include "base/string_tokenizer.h" |
| 11 #include "base/string_util.h" | 10 #include "base/string_util.h" |
| 12 #include "net/base/cert_status_flags.h" | 11 #include "net/base/cert_status_flags.h" |
| 13 #include "net/base/ev_root_ca_metadata.h" | 12 #include "net/base/ev_root_ca_metadata.h" |
| 14 #include "net/base/scoped_cert_chain_context.h" | 13 #include "net/base/scoped_cert_chain_context.h" |
| 15 | 14 |
| 16 #pragma comment(lib, "crypt32.lib") | 15 #pragma comment(lib, "crypt32.lib") |
| 17 | 16 |
| 18 using base::Time; | 17 using base::Time; |
| 19 | 18 |
| 20 namespace net { | 19 namespace net { |
| 21 | 20 |
| 22 namespace { | 21 namespace { |
| 23 | 22 |
| 24 // Calculates the SHA-1 fingerprint of the certificate. Returns an empty | |
| 25 // (all zero) fingerprint on failure. | |
| 26 X509Certificate::Fingerprint CalculateFingerprint(PCCERT_CONTEXT cert) { | |
| 27 DCHECK(NULL != cert->pbCertEncoded); | |
| 28 DCHECK(0 != cert->cbCertEncoded); | |
| 29 | |
| 30 BOOL rv; | |
| 31 X509Certificate::Fingerprint sha1; | |
| 32 DWORD sha1_size = sizeof(sha1.data); | |
| 33 rv = CryptHashCertificate(NULL, CALG_SHA1, 0, cert->pbCertEncoded, | |
| 34 cert->cbCertEncoded, sha1.data, &sha1_size); | |
| 35 DCHECK(rv && sha1_size == sizeof(sha1.data)); | |
| 36 if (!rv) | |
| 37 memset(sha1.data, 0, sizeof(sha1.data)); | |
| 38 return sha1; | |
| 39 } | |
| 40 | |
| 41 // Wrappers of malloc and free for CRYPT_DECODE_PARA, which requires the | 23 // Wrappers of malloc and free for CRYPT_DECODE_PARA, which requires the |
| 42 // WINAPI calling convention. | 24 // WINAPI calling convention. |
| 43 void* WINAPI MyCryptAlloc(size_t size) { | 25 void* WINAPI MyCryptAlloc(size_t size) { |
| 44 return malloc(size); | 26 return malloc(size); |
| 45 } | 27 } |
| 46 | 28 |
| 47 void WINAPI MyCryptFree(void* p) { | 29 void WINAPI MyCryptFree(void* p) { |
| 48 free(p); | 30 free(p); |
| 49 } | 31 } |
| 50 | 32 |
| (...skipping 197 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 248 valid_start_ = Time::FromFileTime(cert_handle_->pCertInfo->NotBefore); | 230 valid_start_ = Time::FromFileTime(cert_handle_->pCertInfo->NotBefore); |
| 249 valid_expiry_ = Time::FromFileTime(cert_handle_->pCertInfo->NotAfter); | 231 valid_expiry_ = Time::FromFileTime(cert_handle_->pCertInfo->NotAfter); |
| 250 | 232 |
| 251 fingerprint_ = CalculateFingerprint(cert_handle_); | 233 fingerprint_ = CalculateFingerprint(cert_handle_); |
| 252 | 234 |
| 253 // Store the certificate in the cache in case we need it later. | 235 // Store the certificate in the cache in case we need it later. |
| 254 X509Certificate::Cache::GetInstance()->Insert(this); | 236 X509Certificate::Cache::GetInstance()->Insert(this); |
| 255 } | 237 } |
| 256 | 238 |
| 257 // static | 239 // static |
| 258 X509Certificate* X509Certificate::CreateFromHandle(OSCertHandle cert_handle) { | |
| 259 DCHECK(cert_handle); | |
| 260 | |
| 261 // Check if we already have this certificate in memory. | |
| 262 X509Certificate::Cache* cache = X509Certificate::Cache::GetInstance(); | |
| 263 X509Certificate* cert = cache->Find(CalculateFingerprint(cert_handle)); | |
| 264 if (cert) { | |
| 265 // We've found a certificate with the same fingerprint in our cache. We own | |
| 266 // the |cert_handle|, which makes it our job to free it. | |
| 267 CertFreeCertificateContext(cert_handle); | |
| 268 DHISTOGRAM_COUNTS(L"X509CertificateReuseCount", 1); | |
| 269 return cert; | |
| 270 } | |
| 271 // Otherwise, allocate a new object. | |
| 272 return new X509Certificate(cert_handle); | |
| 273 } | |
| 274 | |
| 275 // static | |
| 276 X509Certificate* X509Certificate::CreateFromBytes(const char* data, | |
| 277 int length) { | |
| 278 OSCertHandle cert_handle = NULL; | |
| 279 if (!CertAddEncodedCertificateToStore( | |
| 280 NULL, // the cert won't be persisted in any cert store | |
| 281 X509_ASN_ENCODING, | |
| 282 reinterpret_cast<const BYTE*>(data), length, | |
| 283 CERT_STORE_ADD_USE_EXISTING, | |
| 284 &cert_handle)) | |
| 285 return NULL; | |
| 286 | |
| 287 return CreateFromHandle(cert_handle); | |
| 288 } | |
| 289 | |
| 290 // static | |
| 291 X509Certificate* X509Certificate::CreateFromPickle(const Pickle& pickle, | 240 X509Certificate* X509Certificate::CreateFromPickle(const Pickle& pickle, |
| 292 void** pickle_iter) { | 241 void** pickle_iter) { |
| 293 const char* data; | 242 const char* data; |
| 294 int length; | 243 int length; |
| 295 if (!pickle.ReadData(pickle_iter, &data, &length)) | 244 if (!pickle.ReadData(pickle_iter, &data, &length)) |
| 296 return NULL; | 245 return NULL; |
| 297 | 246 |
| 298 OSCertHandle cert_handle = NULL; | 247 OSCertHandle cert_handle = NULL; |
| 299 if (!CertAddSerializedElementToStore( | 248 if (!CertAddSerializedElementToStore( |
| 300 NULL, // the cert won't be persisted in any cert store | 249 NULL, // the cert won't be persisted in any cert store |
| 301 reinterpret_cast<const BYTE*>(data), length, | 250 reinterpret_cast<const BYTE*>(data), length, |
| 302 CERT_STORE_ADD_USE_EXISTING, 0, CERT_STORE_CERTIFICATE_CONTEXT_FLAG, | 251 CERT_STORE_ADD_USE_EXISTING, 0, CERT_STORE_CERTIFICATE_CONTEXT_FLAG, |
| 303 NULL, reinterpret_cast<const void **>(&cert_handle))) | 252 NULL, reinterpret_cast<const void **>(&cert_handle))) |
| 304 return NULL; | 253 return NULL; |
| 305 | 254 |
| 306 return CreateFromHandle(cert_handle); | 255 return CreateFromHandle(cert_handle, SOURCE_LONE_CERT_IMPORT); |
| 307 } | |
| 308 | |
| 309 X509Certificate::X509Certificate(OSCertHandle cert_handle) | |
| 310 : cert_handle_(cert_handle) { | |
| 311 Initialize(); | |
| 312 } | |
| 313 | |
| 314 X509Certificate::X509Certificate(std::string subject, std::string issuer, | |
| 315 Time start_date, Time expiration_date) | |
| 316 : subject_(subject), | |
| 317 issuer_(issuer), | |
| 318 valid_start_(start_date), | |
| 319 valid_expiry_(expiration_date), | |
| 320 cert_handle_(NULL) { | |
| 321 memset(fingerprint_.data, 0, sizeof(fingerprint_.data)); | |
| 322 } | 256 } |
| 323 | 257 |
| 324 void X509Certificate::Persist(Pickle* pickle) { | 258 void X509Certificate::Persist(Pickle* pickle) { |
| 325 DWORD length; | 259 DWORD length; |
| 326 if (!CertSerializeCertificateStoreElement(cert_handle_, 0, | 260 if (!CertSerializeCertificateStoreElement(cert_handle_, 0, |
| 327 NULL, &length)) { | 261 NULL, &length)) { |
| 328 NOTREACHED(); | 262 NOTREACHED(); |
| 329 return; | 263 return; |
| 330 } | 264 } |
| 331 BYTE* data = reinterpret_cast<BYTE*>(pickle->BeginWriteData(length)); | 265 BYTE* data = reinterpret_cast<BYTE*>(pickle->BeginWriteData(length)); |
| 332 if (!CertSerializeCertificateStoreElement(cert_handle_, 0, | 266 if (!CertSerializeCertificateStoreElement(cert_handle_, 0, |
| 333 data, &length)) { | 267 data, &length)) { |
| 334 NOTREACHED(); | 268 NOTREACHED(); |
| 335 length = 0; | 269 length = 0; |
| 336 } | 270 } |
| 337 pickle->TrimWriteData(length); | 271 pickle->TrimWriteData(length); |
| 338 } | 272 } |
| 339 | 273 |
| 340 X509Certificate::~X509Certificate() { | |
| 341 // We might not be in the cache, but it is safe to remove ourselves anyway. | |
| 342 X509Certificate::Cache::GetInstance()->Remove(this); | |
| 343 if (cert_handle_) | |
| 344 CertFreeCertificateContext(cert_handle_); | |
| 345 } | |
| 346 | |
| 347 void X509Certificate::GetDNSNames(std::vector<std::string>* dns_names) const { | 274 void X509Certificate::GetDNSNames(std::vector<std::string>* dns_names) const { |
| 348 dns_names->clear(); | 275 dns_names->clear(); |
| 349 scoped_ptr_malloc<CERT_ALT_NAME_INFO> alt_name_info; | 276 scoped_ptr_malloc<CERT_ALT_NAME_INFO> alt_name_info; |
| 350 GetCertSubjectAltName(cert_handle_, &alt_name_info); | 277 GetCertSubjectAltName(cert_handle_, &alt_name_info); |
| 351 CERT_ALT_NAME_INFO* alt_name = alt_name_info.get(); | 278 CERT_ALT_NAME_INFO* alt_name = alt_name_info.get(); |
| 352 if (alt_name) { | 279 if (alt_name) { |
| 353 int num_entries = alt_name->cAltEntry; | 280 int num_entries = alt_name->cAltEntry; |
| 354 for (int i = 0; i < num_entries; i++) { | 281 for (int i = 0; i < num_entries; i++) { |
| 355 // dNSName is an ASN.1 IA5String representing a string of ASCII | 282 // dNSName is an ASN.1 IA5String representing a string of ASCII |
| 356 // characters, so we can use WideToASCII here. | 283 // characters, so we can use WideToASCII here. |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 399 // Check the end certificate simple chain (chain_context->rgpChain[0]). | 326 // Check the end certificate simple chain (chain_context->rgpChain[0]). |
| 400 // If the end certificate's certificatePolicies extension contains the | 327 // If the end certificate's certificatePolicies extension contains the |
| 401 // EV policy OID of the root CA, return true. | 328 // EV policy OID of the root CA, return true. |
| 402 PCERT_CHAIN_ELEMENT* element = chain_context->rgpChain[0]->rgpElement; | 329 PCERT_CHAIN_ELEMENT* element = chain_context->rgpChain[0]->rgpElement; |
| 403 int num_elements = chain_context->rgpChain[0]->cElement; | 330 int num_elements = chain_context->rgpChain[0]->cElement; |
| 404 if (num_elements < 2) | 331 if (num_elements < 2) |
| 405 return false; | 332 return false; |
| 406 | 333 |
| 407 // Look up the EV policy OID of the root CA. | 334 // Look up the EV policy OID of the root CA. |
| 408 PCCERT_CONTEXT root_cert = element[num_elements - 1]->pCertContext; | 335 PCCERT_CONTEXT root_cert = element[num_elements - 1]->pCertContext; |
| 409 X509Certificate::Fingerprint fingerprint = CalculateFingerprint(root_cert); | 336 Fingerprint fingerprint = CalculateFingerprint(root_cert); |
| 410 std::string ev_policy_oid; | 337 std::string ev_policy_oid; |
| 411 if (!metadata->GetPolicyOID(fingerprint, &ev_policy_oid)) | 338 if (!metadata->GetPolicyOID(fingerprint, &ev_policy_oid)) |
| 412 return false; | 339 return false; |
| 413 DCHECK(!ev_policy_oid.empty()); | 340 DCHECK(!ev_policy_oid.empty()); |
| 414 | 341 |
| 415 // Get the certificatePolicies extension of the end certificate. | 342 // Get the certificatePolicies extension of the end certificate. |
| 416 PCCERT_CONTEXT end_cert = element[0]->pCertContext; | 343 PCCERT_CONTEXT end_cert = element[0]->pCertContext; |
| 417 scoped_ptr_malloc<CERT_POLICIES_INFO> policies_info; | 344 scoped_ptr_malloc<CERT_POLICIES_INFO> policies_info; |
| 418 GetCertPoliciesInfo(end_cert, &policies_info); | 345 GetCertPoliciesInfo(end_cert, &policies_info); |
| 419 if (!policies_info.get()) | 346 if (!policies_info.get()) |
| 420 return false; | 347 return false; |
| 421 | 348 |
| 422 return ContainsPolicy(policies_info.get(), ev_policy_oid.c_str()); | 349 return ContainsPolicy(policies_info.get(), ev_policy_oid.c_str()); |
| 423 } | 350 } |
| 424 | 351 |
| 352 // static |
| 353 X509Certificate::OSCertHandle X509Certificate::CreateOSCertHandleFromBytes( |
| 354 const char* data, int length) { |
| 355 OSCertHandle cert_handle = NULL; |
| 356 if (!CertAddEncodedCertificateToStore( |
| 357 NULL, // the cert won't be persisted in any cert store |
| 358 X509_ASN_ENCODING, |
| 359 reinterpret_cast<const BYTE*>(data), length, |
| 360 CERT_STORE_ADD_USE_EXISTING, |
| 361 &cert_handle)) |
| 362 return NULL; |
| 363 |
| 364 return cert_handle; |
| 365 } |
| 366 |
| 367 // static |
| 368 void X509Certificate::FreeOSCertHandle(OSCertHandle cert_handle) { |
| 369 CertFreeCertificateContext(cert_handle); |
| 370 } |
| 371 |
| 372 // static |
| 373 X509Certificate::Fingerprint X509Certificate::CalculateFingerprint( |
| 374 OSCertHandle cert) { |
| 375 DCHECK(NULL != cert->pbCertEncoded); |
| 376 DCHECK(0 != cert->cbCertEncoded); |
| 377 |
| 378 BOOL rv; |
| 379 Fingerprint sha1; |
| 380 DWORD sha1_size = sizeof(sha1.data); |
| 381 rv = CryptHashCertificate(NULL, CALG_SHA1, 0, cert->pbCertEncoded, |
| 382 cert->cbCertEncoded, sha1.data, &sha1_size); |
| 383 DCHECK(rv && sha1_size == sizeof(sha1.data)); |
| 384 if (!rv) |
| 385 memset(sha1.data, 0, sizeof(sha1.data)); |
| 386 return sha1; |
| 387 } |
| 388 |
| 425 } // namespace net | 389 } // namespace net |
| 426 | 390 |
| OLD | NEW |