Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 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/lazy_instance.h" | 7 #include "base/lazy_instance.h" |
| 8 #include "base/logging.h" | 8 #include "base/logging.h" |
| 9 #include "base/pickle.h" | 9 #include "base/pickle.h" |
| 10 #include "base/sha1.h" | 10 #include "base/sha1.h" |
| 11 #include "base/string_tokenizer.h" | 11 #include "base/string_tokenizer.h" |
| 12 #include "base/string_util.h" | 12 #include "base/string_util.h" |
| 13 #include "base/utf_string_conversions.h" | 13 #include "base/utf_string_conversions.h" |
| 14 #include "crypto/rsa_private_key.h" | 14 #include "crypto/rsa_private_key.h" |
| 15 #include "crypto/scoped_capi_types.h" | 15 #include "crypto/scoped_capi_types.h" |
| 16 #include "net/base/asn1_util.h" | 16 #include "net/base/asn1_util.h" |
| 17 #include "net/base/cert_status_flags.h" | 17 #include "net/base/cert_status_flags.h" |
| 18 #include "net/base/cert_verify_result.h" | 18 #include "net/base/cert_verify_result.h" |
| 19 #include "net/base/ev_root_ca_metadata.h" | 19 #include "net/base/ev_root_ca_metadata.h" |
| 20 #include "net/base/net_errors.h" | 20 #include "net/base/net_errors.h" |
| 21 #include "net/base/scoped_cert_chain_context.h" | |
| 22 #include "net/base/test_root_certs.h" | 21 #include "net/base/test_root_certs.h" |
| 23 #include "net/base/x509_certificate_known_roots_win.h" | 22 #include "net/base/x509_certificate_known_roots_win.h" |
| 24 | 23 |
| 25 #pragma comment(lib, "crypt32.lib") | 24 #pragma comment(lib, "crypt32.lib") |
| 26 | 25 |
| 27 using base::Time; | 26 using base::Time; |
| 28 | 27 |
| 29 namespace net { | 28 namespace net { |
| 30 | 29 |
| 31 namespace { | 30 namespace { |
| 32 | 31 |
| 33 typedef crypto::ScopedCAPIHandle< | |
| 34 HCERTSTORE, | |
| 35 crypto::CAPIDestroyerWithFlags<HCERTSTORE, | |
| 36 CertCloseStore, 0> > ScopedHCERTSTORE; | |
| 37 | |
| 38 struct FreeChainEngineFunctor { | 32 struct FreeChainEngineFunctor { |
| 39 void operator()(HCERTCHAINENGINE engine) const { | 33 void operator()(HCERTCHAINENGINE engine) const { |
| 40 if (engine) | 34 if (engine) |
| 41 CertFreeCertificateChainEngine(engine); | 35 CertFreeCertificateChainEngine(engine); |
| 42 } | 36 } |
| 43 }; | 37 }; |
| 44 | 38 |
| 39 struct FreeCertContextFunctor { | |
| 40 void operator()(PCCERT_CONTEXT context) const { | |
| 41 if (context) | |
| 42 CertFreeCertificateContext(context); | |
| 43 } | |
| 44 }; | |
| 45 | |
| 46 struct FreeCertChainContextFunctor { | |
| 47 void operator()(PCCERT_CHAIN_CONTEXT chain_context) const { | |
| 48 if (context) | |
| 49 CertFreeCertificateChain(context); | |
| 50 } | |
| 51 }; | |
| 52 | |
| 53 typedef crypto::ScopedCAPIHandle< | |
| 54 HCERTSTORE, | |
| 55 crypto::CAPIDestroyerWithFlags<HCERTSTORE, | |
| 56 CertCloseStore, 0> > ScopedHCERTSTORE; | |
| 57 | |
| 45 typedef crypto::ScopedCAPIHandle<HCERTCHAINENGINE, FreeChainEngineFunctor> | 58 typedef crypto::ScopedCAPIHandle<HCERTCHAINENGINE, FreeChainEngineFunctor> |
| 46 ScopedHCERTCHAINENGINE; | 59 ScopedHCERTCHAINENGINE; |
| 47 | 60 |
| 61 typedef scoped_ptr_malloc<const CERT_CONTEXT, | |
| 62 FreeCertContextFunctor> ScopedCertContext; | |
| 63 | |
| 64 typedef scoped_ptr_malloc<const CERT_CHAIN_CONTEXT, | |
| 65 FreeCertChainContextFunctor> ScopedCertChainContext; | |
| 66 | |
|
wtc
2011/10/04 18:00:52
Nit: delete one blank line.
| |
| 67 | |
| 48 //----------------------------------------------------------------------------- | 68 //----------------------------------------------------------------------------- |
| 49 | 69 |
| 50 // TODO(wtc): This is a copy of the MapSecurityError function in | 70 // TODO(wtc): This is a copy of the MapSecurityError function in |
| 51 // ssl_client_socket_win.cc. Another function that maps Windows error codes | 71 // ssl_client_socket_win.cc. Another function that maps Windows error codes |
| 52 // to our network error codes is WinInetUtil::OSErrorToNetError. We should | 72 // to our network error codes is WinInetUtil::OSErrorToNetError. We should |
| 53 // eliminate the code duplication. | 73 // eliminate the code duplication. |
| 54 int MapSecurityError(SECURITY_STATUS err) { | 74 int MapSecurityError(SECURITY_STATUS err) { |
| 55 // There are numerous security error codes, but these are the ones we thus | 75 // There are numerous security error codes, but these are the ones we thus |
| 56 // far find interesting. | 76 // far find interesting. |
| 57 switch (err) { | 77 switch (err) { |
| (...skipping 639 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 697 | 717 |
| 698 static base::LazyInstance<GlobalCertStore, | 718 static base::LazyInstance<GlobalCertStore, |
| 699 base::LeakyLazyInstanceTraits<GlobalCertStore> > | 719 base::LeakyLazyInstanceTraits<GlobalCertStore> > |
| 700 g_cert_store(base::LINKER_INITIALIZED); | 720 g_cert_store(base::LINKER_INITIALIZED); |
| 701 | 721 |
| 702 // static | 722 // static |
| 703 HCERTSTORE X509Certificate::cert_store() { | 723 HCERTSTORE X509Certificate::cert_store() { |
| 704 return g_cert_store.Get().cert_store(); | 724 return g_cert_store.Get().cert_store(); |
| 705 } | 725 } |
| 706 | 726 |
| 727 X509Certificate::OSCertListHandle | |
| 728 X509Certificate::CreateOSCertListHandle() const { | |
| 729 // Create an in-memory certificate store to hold |cert_handle_| and any | |
| 730 // associated intermediate certificates. The store will be referenced in the | |
| 731 // returned OSCertListHandle, and will not be freed until the | |
| 732 // OSCertListHandle is freed. | |
| 733 OSCertListHandle cert_list = NULL; | |
| 734 DWORD flags = CERT_STORE_DEFER_CLOSE_UNTIL_LAST_FREE_FLAG; | |
| 735 HCERTSTORE store = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, | |
| 736 NULL, flags, NULL); | |
| 737 | |
| 738 if (store) { | |
| 739 // NOTE: This preserves all of the properties of |cert_handle_| except for | |
| 740 // CERT_KEY_PROV_HANDLE_PROP_ID and CERT_KEY_CONTEXT_PROP_ID - the two | |
| 741 // properties that hold access to already-opened private keys. If a handle | |
| 742 // has already been unlocked (eg: PIN prompt), then the first time that | |
| 743 // the identity is used for client auth, it may prompt the user again. | |
| 744 BOOL ok = CertAddCertificateContextToStore(store, cert_handle_, | |
| 745 CERT_STORE_ADD_ALWAYS, | |
| 746 &cert_list); | |
| 747 if (ok && cert_list) { | |
| 748 for (size_t i = 0; ok && i < intermediate_ca_certs_.size(); ++i) { | |
| 749 ok = CertAddCertificateContextToStore(store, intermediate_ca_certs_[i], | |
| 750 CERT_STORE_ADD_ALWAYS, NULL); | |
| 751 } | |
| 752 } | |
| 753 | |
| 754 // If |cert_list| points to a valid certificate, this will not actually | |
| 755 // close and free |store| until |cert_list| is freed. | |
| 756 CertCloseStore(store, 0); | |
| 757 | |
| 758 if (!ok) { | |
| 759 FreeOSCertListHandle(cert_list); | |
| 760 return NULL; | |
| 761 } | |
| 762 } | |
| 763 | |
| 764 return cert_list; | |
| 765 } | |
| 766 | |
| 707 int X509Certificate::VerifyInternal(const std::string& hostname, | 767 int X509Certificate::VerifyInternal(const std::string& hostname, |
| 708 int flags, | 768 int flags, |
| 709 CertVerifyResult* verify_result) const { | 769 CertVerifyResult* verify_result) const { |
| 710 if (!cert_handle_) | 770 if (!cert_handle_) |
| 711 return ERR_UNEXPECTED; | 771 return ERR_UNEXPECTED; |
| 712 | 772 |
| 713 // Build and validate certificate chain. | 773 // Build and validate certificate chain. |
| 714 CERT_CHAIN_PARA chain_para; | 774 CERT_CHAIN_PARA chain_para; |
| 715 memset(&chain_para, 0, sizeof(chain_para)); | 775 memset(&chain_para, 0, sizeof(chain_para)); |
| 716 chain_para.cbSize = sizeof(chain_para); | 776 chain_para.cbSize = sizeof(chain_para); |
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 763 // corresponds to HCCE_CURRENT_USER and is is initialized as needed by | 823 // corresponds to HCCE_CURRENT_USER and is is initialized as needed by |
| 764 // crypt32. However, when testing, it is necessary to create a new | 824 // crypt32. However, when testing, it is necessary to create a new |
| 765 // HCERTCHAINENGINE and use that instead. This is because each | 825 // HCERTCHAINENGINE and use that instead. This is because each |
| 766 // HCERTCHAINENGINE maintains a cache of information about certificates | 826 // HCERTCHAINENGINE maintains a cache of information about certificates |
| 767 // encountered, and each test run may modify the trust status of a | 827 // encountered, and each test run may modify the trust status of a |
| 768 // certificate. | 828 // certificate. |
| 769 ScopedHCERTCHAINENGINE chain_engine(NULL); | 829 ScopedHCERTCHAINENGINE chain_engine(NULL); |
| 770 if (TestRootCerts::HasInstance()) | 830 if (TestRootCerts::HasInstance()) |
| 771 chain_engine.reset(TestRootCerts::GetInstance()->GetChainEngine()); | 831 chain_engine.reset(TestRootCerts::GetInstance()->GetChainEngine()); |
| 772 | 832 |
| 833 ScopedPCCERT_CONTEXT cert_list(CreateOSCertListHandle()); | |
|
wtc
2011/10/04 18:00:52
I don't see where the ScopedPCCERT_CONTEXT type is
| |
| 773 PCCERT_CHAIN_CONTEXT chain_context; | 834 PCCERT_CHAIN_CONTEXT chain_context; |
| 774 // IE passes a non-NULL pTime argument that specifies the current system | 835 // IE passes a non-NULL pTime argument that specifies the current system |
| 775 // time. IE passes CERT_CHAIN_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT as the | 836 // time. IE passes CERT_CHAIN_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT as the |
| 776 // chain_flags argument. | 837 // chain_flags argument. |
| 777 if (!CertGetCertificateChain( | 838 if (!CertGetCertificateChain( |
| 778 chain_engine, | 839 chain_engine, |
| 779 cert_handle_, | 840 cert_list, |
| 780 NULL, // current system time | 841 NULL, // current system time |
| 781 cert_handle_->hCertStore, | 842 cert_list->hCertStore, |
| 782 &chain_para, | 843 &chain_para, |
| 783 chain_flags, | 844 chain_flags, |
| 784 NULL, // reserved | 845 NULL, // reserved |
| 785 &chain_context)) { | 846 &chain_context)) { |
| 786 return MapSecurityError(GetLastError()); | 847 return MapSecurityError(GetLastError()); |
| 787 } | 848 } |
| 849 | |
| 788 if (chain_context->TrustStatus.dwErrorStatus & | 850 if (chain_context->TrustStatus.dwErrorStatus & |
| 789 CERT_TRUST_IS_NOT_VALID_FOR_USAGE) { | 851 CERT_TRUST_IS_NOT_VALID_FOR_USAGE) { |
| 790 ev_policy_oid = NULL; | 852 ev_policy_oid = NULL; |
| 791 chain_para.RequestedIssuancePolicy.Usage.cUsageIdentifier = 0; | 853 chain_para.RequestedIssuancePolicy.Usage.cUsageIdentifier = 0; |
| 792 chain_para.RequestedIssuancePolicy.Usage.rgpszUsageIdentifier = NULL; | 854 chain_para.RequestedIssuancePolicy.Usage.rgpszUsageIdentifier = NULL; |
| 793 CertFreeCertificateChain(chain_context); | 855 CertFreeCertificateChain(chain_context); |
| 794 if (!CertGetCertificateChain( | 856 if (!CertGetCertificateChain( |
| 795 chain_engine, | 857 chain_engine, |
| 796 cert_handle_, | 858 cert_list, |
| 797 NULL, // current system time | 859 NULL, // current system time |
| 798 cert_handle_->hCertStore, | 860 cert_list->hCertStore, |
| 799 &chain_para, | 861 &chain_para, |
| 800 chain_flags, | 862 chain_flags, |
| 801 NULL, // reserved | 863 NULL, // reserved |
| 802 &chain_context)) { | 864 &chain_context)) { |
| 803 return MapSecurityError(GetLastError()); | 865 return MapSecurityError(GetLastError()); |
| 804 } | 866 } |
| 805 } | 867 } |
| 868 | |
| 806 ScopedCertChainContext scoped_chain_context(chain_context); | 869 ScopedCertChainContext scoped_chain_context(chain_context); |
| 807 | 870 |
| 808 GetCertChainInfo(chain_context, verify_result); | 871 GetCertChainInfo(chain_context, verify_result); |
| 809 verify_result->cert_status |= MapCertChainErrorStatusToCertStatus( | 872 verify_result->cert_status |= MapCertChainErrorStatusToCertStatus( |
| 810 chain_context->TrustStatus.dwErrorStatus); | 873 chain_context->TrustStatus.dwErrorStatus); |
| 811 | 874 |
| 812 // Treat certificates signed using broken signature algorithms as invalid. | 875 // Treat certificates signed using broken signature algorithms as invalid. |
| 813 if (verify_result->has_md4) | 876 if (verify_result->has_md4) |
| 814 verify_result->cert_status |= CERT_STATUS_INVALID; | 877 verify_result->cert_status |= CERT_STATUS_INVALID; |
| 815 | 878 |
| (...skipping 188 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1004 OSCertHandle cert_handle) { | 1067 OSCertHandle cert_handle) { |
| 1005 return CertDuplicateCertificateContext(cert_handle); | 1068 return CertDuplicateCertificateContext(cert_handle); |
| 1006 } | 1069 } |
| 1007 | 1070 |
| 1008 // static | 1071 // static |
| 1009 void X509Certificate::FreeOSCertHandle(OSCertHandle cert_handle) { | 1072 void X509Certificate::FreeOSCertHandle(OSCertHandle cert_handle) { |
| 1010 CertFreeCertificateContext(cert_handle); | 1073 CertFreeCertificateContext(cert_handle); |
| 1011 } | 1074 } |
| 1012 | 1075 |
| 1013 // static | 1076 // static |
| 1077 void X509Certificate::FreeOSCertListHandle(OSCertListHandle cert_list) { | |
| 1078 CertFreeCertificateContext(cert_list); | |
| 1079 } | |
| 1080 | |
| 1081 // static | |
| 1014 SHA1Fingerprint X509Certificate::CalculateFingerprint( | 1082 SHA1Fingerprint X509Certificate::CalculateFingerprint( |
| 1015 OSCertHandle cert) { | 1083 OSCertHandle cert) { |
| 1016 DCHECK(NULL != cert->pbCertEncoded); | 1084 DCHECK(NULL != cert->pbCertEncoded); |
| 1017 DCHECK_NE(static_cast<DWORD>(0), cert->cbCertEncoded); | 1085 DCHECK_NE(static_cast<DWORD>(0), cert->cbCertEncoded); |
| 1018 | 1086 |
| 1019 BOOL rv; | 1087 BOOL rv; |
| 1020 SHA1Fingerprint sha1; | 1088 SHA1Fingerprint sha1; |
| 1021 DWORD sha1_size = sizeof(sha1.data); | 1089 DWORD sha1_size = sizeof(sha1.data); |
| 1022 rv = CryptHashCertificate(NULL, CALG_SHA1, 0, cert->pbCertEncoded, | 1090 rv = CryptHashCertificate(NULL, CALG_SHA1, 0, cert->pbCertEncoded, |
| 1023 cert->cbCertEncoded, sha1.data, &sha1_size); | 1091 cert->cbCertEncoded, sha1.data, &sha1_size); |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1061 if (!CertSerializeCertificateStoreElement(cert_handle, 0, &buffer[0], | 1129 if (!CertSerializeCertificateStoreElement(cert_handle, 0, &buffer[0], |
| 1062 &length)) { | 1130 &length)) { |
| 1063 return false; | 1131 return false; |
| 1064 } | 1132 } |
| 1065 | 1133 |
| 1066 return pickle->WriteData(reinterpret_cast<const char*>(&buffer[0]), | 1134 return pickle->WriteData(reinterpret_cast<const char*>(&buffer[0]), |
| 1067 length); | 1135 length); |
| 1068 } | 1136 } |
| 1069 | 1137 |
| 1070 } // namespace net | 1138 } // namespace net |
| OLD | NEW |