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 <cert.h> | 7 #include <cert.h> |
| 8 #include <cryptohi.h> | 8 #include <cryptohi.h> |
| 9 #include <keyhi.h> | 9 #include <keyhi.h> |
| 10 #include <nss.h> | 10 #include <nss.h> |
| (...skipping 150 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 161 case SEC_ERROR_EXTENSION_VALUE_INVALID: | 161 case SEC_ERROR_EXTENSION_VALUE_INVALID: |
| 162 return CERT_STATUS_INVALID; | 162 return CERT_STATUS_INVALID; |
| 163 default: | 163 default: |
| 164 return 0; | 164 return 0; |
| 165 } | 165 } |
| 166 } | 166 } |
| 167 | 167 |
| 168 // Saves some information about the certificate chain cert_list in | 168 // Saves some information about the certificate chain cert_list in |
| 169 // *verify_result. The caller MUST initialize *verify_result before calling | 169 // *verify_result. The caller MUST initialize *verify_result before calling |
| 170 // this function. | 170 // this function. |
| 171 // Note that cert_list[0] is the end entity certificate and cert_list doesn't | 171 // Note that cert_list[0] is the end entity certificate. |
| 172 // contain the root CA certificate. | |
| 173 void GetCertChainInfo(CERTCertList* cert_list, | 172 void GetCertChainInfo(CERTCertList* cert_list, |
| 173 CERTCertificate* root_cert, | |
| 174 CertVerifyResult* verify_result) { | 174 CertVerifyResult* verify_result) { |
| 175 // NOTE: Using a NSS library before 3.12.3.1 will crash below. To see the | 175 // NOTE: Using a NSS library before 3.12.3.1 will crash below. To see the |
| 176 // NSS version currently in use: | 176 // NSS version currently in use: |
| 177 // 1. use ldd on the chrome executable for NSS's location (ie. libnss3.so*) | 177 // 1. use ldd on the chrome executable for NSS's location (ie. libnss3.so*) |
| 178 // 2. use ident libnss3.so* for the library's version | 178 // 2. use ident libnss3.so* for the library's version |
| 179 DCHECK(cert_list); | 179 if (!cert_list) |
| 180 return; | |
|
wtc
2011/07/26 00:16:35
Why do you want to allow cert_list to be NULL?
Thi
Ryan Sleevi
2011/07/26 01:44:50
Thanks for catching this. In digging down further
| |
| 181 | |
| 182 CERTCertificate* verified_cert = NULL; | |
| 183 std::vector<CERTCertificate*> verified_chain; | |
| 180 int i = 0; | 184 int i = 0; |
| 181 for (CERTCertListNode* node = CERT_LIST_HEAD(cert_list); | 185 for (CERTCertListNode* node = CERT_LIST_HEAD(cert_list); |
| 182 !CERT_LIST_END(node, cert_list); | 186 !CERT_LIST_END(node, cert_list); |
| 183 node = CERT_LIST_NEXT(node), i++) { | 187 node = CERT_LIST_NEXT(node), ++i) { |
| 188 if (i == 0) { | |
| 189 verified_cert = node->cert; | |
| 190 } else { | |
| 191 verified_chain.push_back(node->cert); | |
| 192 } | |
| 184 SECAlgorithmID& signature = node->cert->signature; | 193 SECAlgorithmID& signature = node->cert->signature; |
| 185 SECOidTag oid_tag = SECOID_FindOIDTag(&signature.algorithm); | 194 SECOidTag oid_tag = SECOID_FindOIDTag(&signature.algorithm); |
| 186 switch (oid_tag) { | 195 switch (oid_tag) { |
| 187 case SEC_OID_PKCS1_MD5_WITH_RSA_ENCRYPTION: | 196 case SEC_OID_PKCS1_MD5_WITH_RSA_ENCRYPTION: |
| 188 verify_result->has_md5 = true; | 197 verify_result->has_md5 = true; |
| 189 if (i != 0) | 198 if (i != 0) |
| 190 verify_result->has_md5_ca = true; | 199 verify_result->has_md5_ca = true; |
| 191 break; | 200 break; |
| 192 case SEC_OID_PKCS1_MD2_WITH_RSA_ENCRYPTION: | 201 case SEC_OID_PKCS1_MD2_WITH_RSA_ENCRYPTION: |
| 193 verify_result->has_md2 = true; | 202 verify_result->has_md2 = true; |
| 194 if (i != 0) | 203 if (i != 0) |
| 195 verify_result->has_md2_ca = true; | 204 verify_result->has_md2_ca = true; |
| 196 break; | 205 break; |
| 197 case SEC_OID_PKCS1_MD4_WITH_RSA_ENCRYPTION: | 206 case SEC_OID_PKCS1_MD4_WITH_RSA_ENCRYPTION: |
| 198 verify_result->has_md4 = true; | 207 verify_result->has_md4 = true; |
| 199 break; | 208 break; |
| 200 default: | 209 default: |
| 201 break; | 210 break; |
| 202 } | 211 } |
| 203 } | 212 } |
| 213 | |
| 214 if (!verified_cert) | |
| 215 return; | |
| 216 | |
| 217 // If the chain was not trusted, |root_cert| may be NULL. | |
| 218 if (root_cert) | |
| 219 verified_chain.push_back(root_cert); | |
| 220 verify_result->verified_cert = | |
| 221 X509Certificate::CreateFromHandle(verified_cert, verified_chain); | |
| 204 } | 222 } |
| 205 | 223 |
| 206 // IsKnownRoot returns true if the given certificate is one that we believe | 224 // IsKnownRoot returns true if the given certificate is one that we believe |
| 207 // is a standard (as opposed to user-installed) root. | 225 // is a standard (as opposed to user-installed) root. |
| 208 bool IsKnownRoot(CERTCertificate* root) { | 226 bool IsKnownRoot(CERTCertificate* root) { |
| 209 if (!root->slot) | 227 if (!root->slot) |
| 210 return false; | 228 return false; |
| 211 | 229 |
| 212 // This magic name is taken from | 230 // This magic name is taken from |
| 213 // http://bonsai.mozilla.org/cvsblame.cgi?file=mozilla/security/nss/lib/ckfw/b uiltins/constants.c&rev=1.13&mark=86,89#79 | 231 // http://bonsai.mozilla.org/cvsblame.cgi?file=mozilla/security/nss/lib/ckfw/b uiltins/constants.c&rev=1.13&mark=86,89#79 |
| (...skipping 548 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 762 | 780 |
| 763 X509Certificate::OSCertListHandle | 781 X509Certificate::OSCertListHandle |
| 764 X509Certificate::CreateOSCertListHandle() const { | 782 X509Certificate::CreateOSCertListHandle() const { |
| 765 return CERT_DupCertificate(cert_handle_); | 783 return CERT_DupCertificate(cert_handle_); |
| 766 } | 784 } |
| 767 | 785 |
| 768 int X509Certificate::Verify(const std::string& hostname, | 786 int X509Certificate::Verify(const std::string& hostname, |
| 769 int flags, | 787 int flags, |
| 770 CertVerifyResult* verify_result) const { | 788 CertVerifyResult* verify_result) const { |
| 771 verify_result->Reset(); | 789 verify_result->Reset(); |
| 790 verify_result->verified_cert = | |
| 791 CreateFromHandle(cert_handle_, GetIntermediateCertificates()); | |
| 772 | 792 |
| 773 if (IsBlacklisted()) { | 793 if (IsBlacklisted()) { |
| 774 verify_result->cert_status |= CERT_STATUS_REVOKED; | 794 verify_result->cert_status |= CERT_STATUS_REVOKED; |
| 775 return ERR_CERT_REVOKED; | 795 return ERR_CERT_REVOKED; |
| 776 } | 796 } |
| 777 | 797 |
| 778 // Make sure that the hostname matches with the common name of the cert. | 798 // Make sure that the hostname matches with the common name of the cert. |
| 779 SECStatus status = CERT_VerifyCertName(cert_handle_, hostname.c_str()); | 799 SECStatus status = CERT_VerifyCertName(cert_handle_, hostname.c_str()); |
| 780 if (status != SECSuccess) | 800 if (status != SECSuccess) |
| 781 verify_result->cert_status |= CERT_STATUS_COMMON_NAME_INVALID; | 801 verify_result->cert_status |= CERT_STATUS_COMMON_NAME_INVALID; |
| (...skipping 18 matching lines...) Expand all Loading... | |
| 800 ScopedCERTValOutParam scoped_cvout(cvout); | 820 ScopedCERTValOutParam scoped_cvout(cvout); |
| 801 | 821 |
| 802 bool check_revocation = (flags & VERIFY_REV_CHECKING_ENABLED); | 822 bool check_revocation = (flags & VERIFY_REV_CHECKING_ENABLED); |
| 803 if (check_revocation) { | 823 if (check_revocation) { |
| 804 verify_result->cert_status |= CERT_STATUS_REV_CHECKING_ENABLED; | 824 verify_result->cert_status |= CERT_STATUS_REV_CHECKING_ENABLED; |
| 805 } else { | 825 } else { |
| 806 // EV requires revocation checking. | 826 // EV requires revocation checking. |
| 807 flags &= ~VERIFY_EV_CERT; | 827 flags &= ~VERIFY_EV_CERT; |
| 808 } | 828 } |
| 809 status = PKIXVerifyCert(cert_handle_, check_revocation, NULL, 0, cvout); | 829 status = PKIXVerifyCert(cert_handle_, check_revocation, NULL, 0, cvout); |
| 830 | |
| 831 GetCertChainInfo(cvout[cvout_cert_list_index].value.pointer.chain, | |
| 832 cvout[cvout_trust_anchor_index].value.pointer.cert, | |
| 833 verify_result); | |
| 834 | |
| 810 if (status != SECSuccess) { | 835 if (status != SECSuccess) { |
| 811 int err = PORT_GetError(); | 836 int err = PORT_GetError(); |
| 812 LOG(ERROR) << "CERT_PKIXVerifyCert for " << hostname | 837 LOG(ERROR) << "CERT_PKIXVerifyCert for " << hostname |
| 813 << " failed err=" << err; | 838 << " failed err=" << err; |
| 814 // CERT_PKIXVerifyCert rerports the wrong error code for | 839 // CERT_PKIXVerifyCert rerports the wrong error code for |
| 815 // expired certificates (NSS bug 491174) | 840 // expired certificates (NSS bug 491174) |
| 816 if (err == SEC_ERROR_CERT_NOT_VALID && | 841 if (err == SEC_ERROR_CERT_NOT_VALID && |
| 817 (verify_result->cert_status & CERT_STATUS_DATE_INVALID) != 0) | 842 (verify_result->cert_status & CERT_STATUS_DATE_INVALID) != 0) |
| 818 err = SEC_ERROR_EXPIRED_CERTIFICATE; | 843 err = SEC_ERROR_EXPIRED_CERTIFICATE; |
| 819 int cert_status = MapCertErrorToCertStatus(err); | 844 int cert_status = MapCertErrorToCertStatus(err); |
| 820 if (cert_status) { | 845 if (cert_status) { |
| 821 verify_result->cert_status |= cert_status; | 846 verify_result->cert_status |= cert_status; |
| 822 return MapCertStatusToNetError(verify_result->cert_status); | 847 return MapCertStatusToNetError(verify_result->cert_status); |
| 823 } | 848 } |
| 824 // |err| is not a certificate error. | 849 // |err| is not a certificate error. |
| 825 return MapSecurityError(err); | 850 return MapSecurityError(err); |
| 826 } | 851 } |
| 827 | 852 |
| 828 GetCertChainInfo(cvout[cvout_cert_list_index].value.pointer.chain, | |
| 829 verify_result); | |
| 830 if (IsCertStatusError(verify_result->cert_status)) | 853 if (IsCertStatusError(verify_result->cert_status)) |
| 831 return MapCertStatusToNetError(verify_result->cert_status); | 854 return MapCertStatusToNetError(verify_result->cert_status); |
| 832 | 855 |
| 833 AppendPublicKeyHashes(cvout[cvout_cert_list_index].value.pointer.chain, | 856 AppendPublicKeyHashes(cvout[cvout_cert_list_index].value.pointer.chain, |
| 834 cvout[cvout_trust_anchor_index].value.pointer.cert, | 857 cvout[cvout_trust_anchor_index].value.pointer.cert, |
| 835 &verify_result->public_key_hashes); | 858 &verify_result->public_key_hashes); |
| 836 | 859 |
| 837 verify_result->is_issued_by_known_root = | 860 verify_result->is_issued_by_known_root = |
| 838 IsKnownRoot(cvout[cvout_trust_anchor_index].value.pointer.cert); | 861 IsKnownRoot(cvout[cvout_trust_anchor_index].value.pointer.cert); |
| 839 | 862 |
| (...skipping 172 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1012 | 1035 |
| 1013 // static | 1036 // static |
| 1014 bool X509Certificate::WriteCertHandleToPickle(OSCertHandle cert_handle, | 1037 bool X509Certificate::WriteCertHandleToPickle(OSCertHandle cert_handle, |
| 1015 Pickle* pickle) { | 1038 Pickle* pickle) { |
| 1016 return pickle->WriteData( | 1039 return pickle->WriteData( |
| 1017 reinterpret_cast<const char*>(cert_handle->derCert.data), | 1040 reinterpret_cast<const char*>(cert_handle->derCert.data), |
| 1018 cert_handle->derCert.len); | 1041 cert_handle->derCert.len); |
| 1019 } | 1042 } |
| 1020 | 1043 |
| 1021 } // namespace net | 1044 } // namespace net |
| OLD | NEW |