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 |