| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 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 <openssl/asn1.h> | 7 #include <openssl/asn1.h> |
| 8 #include <openssl/crypto.h> | 8 #include <openssl/crypto.h> |
| 9 #include <openssl/obj_mac.h> | 9 #include <openssl/obj_mac.h> |
| 10 #include <openssl/pem.h> | 10 #include <openssl/pem.h> |
| (...skipping 347 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 358 if (!asn1::ExtractSPKIFromDERCert(der_bytes, &spki_bytes)) | 358 if (!asn1::ExtractSPKIFromDERCert(der_bytes, &spki_bytes)) |
| 359 continue; | 359 continue; |
| 360 | 360 |
| 361 SHA1Fingerprint hash; | 361 SHA1Fingerprint hash; |
| 362 base::SHA1HashBytes(reinterpret_cast<const uint8*>(spki_bytes.data()), | 362 base::SHA1HashBytes(reinterpret_cast<const uint8*>(spki_bytes.data()), |
| 363 spki_bytes.size(), hash.data); | 363 spki_bytes.size(), hash.data); |
| 364 hashes->push_back(hash); | 364 hashes->push_back(hash); |
| 365 } | 365 } |
| 366 } | 366 } |
| 367 | 367 |
| 368 #if defined(OS_ANDROID) |
| 369 |
| 370 // Returns true if we have verification result in |verify_result| from Android |
| 371 // Trust Manager. Otherwise returns false. |
| 372 bool VerifyFromAndroidTrustManager(const std::vector<std::string>& cert_bytes, |
| 373 CertVerifyResult* verify_result) { |
| 374 // TODO(joth): Fetch the authentication type from SSL rather than hardcode. |
| 375 // TODO(jnd): Remove unused |hostname| from net::android::VerifyX509CertChain. |
| 376 bool verified = true; |
| 377 #if 0 |
| 378 android::VerifyResult result = |
| 379 android::VerifyX509CertChain(cert_bytes, hostname, "RSA"); |
| 380 #else |
| 381 // TODO(jingzhao): Recover the original implementation once we support JNI. |
| 382 android::VerifyResult result = android::VERIFY_INVOCATION_ERROR; |
| 383 NOTIMPLEMENTED(); |
| 384 #endif |
| 385 switch (result) { |
| 386 case android::VERIFY_OK: |
| 387 break; |
| 388 case android::VERIFY_BAD_HOSTNAME: |
| 389 verify_result->cert_status |= CERT_STATUS_COMMON_NAME_INVALID; |
| 390 break; |
| 391 case android::VERIFY_NO_TRUSTED_ROOT: |
| 392 verify_result->cert_status |= CERT_STATUS_AUTHORITY_INVALID; |
| 393 break; |
| 394 case android::VERIFY_INVOCATION_ERROR: |
| 395 verified = false; |
| 396 break; |
| 397 default: |
| 398 verify_result->cert_status |= CERT_STATUS_INVALID; |
| 399 break; |
| 400 } |
| 401 return verified; |
| 402 } |
| 403 |
| 404 #endif |
| 405 |
| 368 } // namespace | 406 } // namespace |
| 369 | 407 |
| 370 // static | 408 // static |
| 371 X509Certificate::OSCertHandle X509Certificate::DupOSCertHandle( | 409 X509Certificate::OSCertHandle X509Certificate::DupOSCertHandle( |
| 372 OSCertHandle cert_handle) { | 410 OSCertHandle cert_handle) { |
| 373 DCHECK(cert_handle); | 411 DCHECK(cert_handle); |
| 374 // Using X509_dup causes the entire certificate to be reparsed. This | 412 // Using X509_dup causes the entire certificate to be reparsed. This |
| 375 // conversion, besides being non-trivial, drops any associated | 413 // conversion, besides being non-trivial, drops any associated |
| 376 // application-specific data set by X509_set_ex_data. Using CRYPTO_add | 414 // application-specific data set by X509_set_ex_data. Using CRYPTO_add |
| 377 // just bumps up the ref-count for the cert, without causing any allocations | 415 // just bumps up the ref-count for the cert, without causing any allocations |
| (...skipping 131 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 509 ip_addrs->clear(); | 547 ip_addrs->clear(); |
| 510 | 548 |
| 511 ParseSubjectAltName(cert_handle_, dns_names, ip_addrs); | 549 ParseSubjectAltName(cert_handle_, dns_names, ip_addrs); |
| 512 } | 550 } |
| 513 | 551 |
| 514 // static | 552 // static |
| 515 X509_STORE* X509Certificate::cert_store() { | 553 X509_STORE* X509Certificate::cert_store() { |
| 516 return X509InitSingleton::GetInstance()->store(); | 554 return X509InitSingleton::GetInstance()->store(); |
| 517 } | 555 } |
| 518 | 556 |
| 519 #if defined(OS_ANDROID) | |
| 520 int X509Certificate::VerifyInternal(const std::string& hostname, | 557 int X509Certificate::VerifyInternal(const std::string& hostname, |
| 521 int flags, | 558 int flags, |
| 522 CRLSet* crl_set, | 559 CRLSet* crl_set, |
| 523 CertVerifyResult* verify_result) const { | 560 CertVerifyResult* verify_result) const { |
| 524 if (!VerifyNameMatch(hostname)) | 561 if (!VerifyNameMatch(hostname)) |
| 525 verify_result->cert_status |= CERT_STATUS_COMMON_NAME_INVALID; | 562 verify_result->cert_status |= CERT_STATUS_COMMON_NAME_INVALID; |
| 526 | 563 |
| 564 bool verify_attempted = false; |
| 565 |
| 566 #if defined(OS_ANDROID) |
| 527 std::vector<std::string> cert_bytes; | 567 std::vector<std::string> cert_bytes; |
| 528 GetChainDEREncodedBytes(&cert_bytes); | 568 GetChainDEREncodedBytes(&cert_bytes); |
| 529 | 569 |
| 530 // TODO(joth): Fetch the authentication type from SSL rather than hardcode. | 570 verify_attempted = VerifyFromAndroidTrustManager(cert_bytes, verify_result); |
| 531 // TODO(jingzhao): Recover the original implementation once we support JNI. | |
| 532 #if 0 | |
| 533 android::VerifyResult result = | |
| 534 android::VerifyX509CertChain(cert_bytes, hostname, "RSA"); | |
| 535 #else | |
| 536 android::VerifyResult result = android::VERIFY_INVOCATION_ERROR; | |
| 537 NOTIMPLEMENTED(); | |
| 538 #endif | 571 #endif |
| 539 switch (result) { | |
| 540 case android::VERIFY_OK: | |
| 541 break; | |
| 542 case android::VERIFY_BAD_HOSTNAME: | |
| 543 verify_result->cert_status |= CERT_STATUS_COMMON_NAME_INVALID; | |
| 544 break; | |
| 545 case android::VERIFY_NO_TRUSTED_ROOT: | |
| 546 verify_result->cert_status |= CERT_STATUS_AUTHORITY_INVALID; | |
| 547 break; | |
| 548 case android::VERIFY_INVOCATION_ERROR: | |
| 549 default: | |
| 550 verify_result->cert_status |= CERT_STATUS_INVALID; | |
| 551 break; | |
| 552 } | |
| 553 if (IsCertStatusError(verify_result->cert_status)) | |
| 554 return MapCertStatusToNetError(verify_result->cert_status); | |
| 555 return OK; | |
| 556 } | |
| 557 | 572 |
| 558 #else | 573 if (verify_attempted) { |
| 559 int X509Certificate::VerifyInternal(const std::string& hostname, | 574 if (IsCertStatusError(verify_result->cert_status)) |
| 560 int flags, | 575 return MapCertStatusToNetError(verify_result->cert_status); |
| 561 CRLSet* crl_set, | 576 } else { |
| 562 CertVerifyResult* verify_result) const { | 577 crypto::ScopedOpenSSL<X509_STORE_CTX, X509_STORE_CTX_free> ctx( |
| 563 if (!VerifyNameMatch(hostname)) | 578 X509_STORE_CTX_new()); |
| 564 verify_result->cert_status |= CERT_STATUS_COMMON_NAME_INVALID; | |
| 565 | 579 |
| 566 crypto::ScopedOpenSSL<X509_STORE_CTX, X509_STORE_CTX_free> ctx( | 580 crypto::ScopedOpenSSL<STACK_OF(X509), sk_X509_free_fn> intermediates( |
| 567 X509_STORE_CTX_new()); | 581 sk_X509_new_null()); |
| 582 if (!intermediates.get()) |
| 583 return ERR_OUT_OF_MEMORY; |
| 568 | 584 |
| 569 crypto::ScopedOpenSSL<STACK_OF(X509), sk_X509_free_fn> intermediates( | 585 for (OSCertHandles::const_iterator it = intermediate_ca_certs_.begin(); |
| 570 sk_X509_new_null()); | 586 it != intermediate_ca_certs_.end(); ++it) { |
| 571 if (!intermediates.get()) | 587 if (!sk_X509_push(intermediates.get(), *it)) |
| 572 return ERR_OUT_OF_MEMORY; | 588 return ERR_OUT_OF_MEMORY; |
| 589 } |
| 590 int rv = X509_STORE_CTX_init(ctx.get(), cert_store(), |
| 591 cert_handle_, intermediates.get()); |
| 592 CHECK_EQ(1, rv); |
| 573 | 593 |
| 574 for (OSCertHandles::const_iterator it = intermediate_ca_certs_.begin(); | 594 if (X509_verify_cert(ctx.get()) != 1) { |
| 575 it != intermediate_ca_certs_.end(); ++it) { | 595 int x509_error = X509_STORE_CTX_get_error(ctx.get()); |
| 576 if (!sk_X509_push(intermediates.get(), *it)) | 596 CertStatus cert_status = MapCertErrorToCertStatus(x509_error); |
| 577 return ERR_OUT_OF_MEMORY; | 597 LOG(ERROR) << "X509 Verification error " |
| 578 } | 598 << X509_verify_cert_error_string(x509_error) |
| 579 int rv = X509_STORE_CTX_init(ctx.get(), cert_store(), | 599 << " : " << x509_error |
| 580 cert_handle_, intermediates.get()); | 600 << " : " << X509_STORE_CTX_get_error_depth(ctx.get()) |
| 581 CHECK_EQ(1, rv); | 601 << " : " << cert_status; |
| 602 verify_result->cert_status |= cert_status; |
| 603 } |
| 582 | 604 |
| 583 if (X509_verify_cert(ctx.get()) != 1) { | 605 GetCertChainInfo(ctx.get(), verify_result); |
| 584 int x509_error = X509_STORE_CTX_get_error(ctx.get()); | 606 if (IsCertStatusError(verify_result->cert_status)) |
| 585 CertStatus cert_status = MapCertErrorToCertStatus(x509_error); | 607 return MapCertStatusToNetError(verify_result->cert_status); |
| 586 LOG(ERROR) << "X509 Verification error " | 608 AppendPublicKeyHashes(ctx.get(), &verify_result->public_key_hashes); |
| 587 << X509_verify_cert_error_string(x509_error) | |
| 588 << " : " << x509_error | |
| 589 << " : " << X509_STORE_CTX_get_error_depth(ctx.get()) | |
| 590 << " : " << cert_status; | |
| 591 verify_result->cert_status |= cert_status; | |
| 592 } | 609 } |
| 593 | 610 |
| 594 GetCertChainInfo(ctx.get(), verify_result); | |
| 595 | |
| 596 if (IsCertStatusError(verify_result->cert_status)) | |
| 597 return MapCertStatusToNetError(verify_result->cert_status); | |
| 598 | |
| 599 AppendPublicKeyHashes(ctx.get(), &verify_result->public_key_hashes); | |
| 600 // Currently we only ues OpenSSL's default root CA paths, so treat all | 611 // Currently we only ues OpenSSL's default root CA paths, so treat all |
| 601 // correctly verified certs as being from a known root. TODO(joth): if the | 612 // correctly verified certs as being from a known root. TODO(joth): if the |
| 602 // motivations described in http://src.chromium.org/viewvc/chrome?view=rev&rev
ision=80778 | 613 // motivations described in http://src.chromium.org/viewvc/chrome?view=rev&rev
ision=80778 |
| 603 // become an issue on OpenSSL builds, we will need to embed a hardcoded list | 614 // become an issue on OpenSSL builds, we will need to embed a hardcoded list |
| 604 // of well known root CAs, as per the _mac and _win versions. | 615 // of well known root CAs, as per the _mac and _win versions. |
| 605 verify_result->is_issued_by_known_root = true; | 616 verify_result->is_issued_by_known_root = true; |
| 606 | 617 |
| 607 return OK; | 618 return OK; |
| 608 } | 619 } |
| 609 | 620 |
| 610 #endif // defined(OS_ANDROID) | |
| 611 | |
| 612 // static | 621 // static |
| 613 bool X509Certificate::GetDEREncoded(X509Certificate::OSCertHandle cert_handle, | 622 bool X509Certificate::GetDEREncoded(X509Certificate::OSCertHandle cert_handle, |
| 614 std::string* encoded) { | 623 std::string* encoded) { |
| 615 DERCache der_cache; | 624 DERCache der_cache; |
| 616 if (!GetDERAndCacheIfNeeded(cert_handle, &der_cache)) | 625 if (!GetDERAndCacheIfNeeded(cert_handle, &der_cache)) |
| 617 return false; | 626 return false; |
| 618 encoded->assign(reinterpret_cast<const char*>(der_cache.data), | 627 encoded->assign(reinterpret_cast<const char*>(der_cache.data), |
| 619 der_cache.data_length); | 628 der_cache.data_length); |
| 620 return true; | 629 return true; |
| 621 } | 630 } |
| (...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 708 for (OSCertHandles::const_iterator it = cert_handles.begin(); | 717 for (OSCertHandles::const_iterator it = cert_handles.begin(); |
| 709 it != cert_handles.end(); ++it) { | 718 it != cert_handles.end(); ++it) { |
| 710 std::string cert_bytes; | 719 std::string cert_bytes; |
| 711 GetDEREncoded(*it, &cert_bytes); | 720 GetDEREncoded(*it, &cert_bytes); |
| 712 chain_bytes->push_back(cert_bytes); | 721 chain_bytes->push_back(cert_bytes); |
| 713 } | 722 } |
| 714 } | 723 } |
| 715 #endif | 724 #endif |
| 716 | 725 |
| 717 } // namespace net | 726 } // namespace net |
| OLD | NEW |