OLD | NEW |
1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2010 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_chain.h" | 5 #include "net/base/x509_chain.h" |
6 | 6 |
7 #include <cert.h> | 7 #include <cert.h> |
8 #include <nss.h> | 8 #include <nss.h> |
9 #include <prerror.h> | 9 #include <prerror.h> |
10 #include <secerr.h> | 10 #include <secerr.h> |
(...skipping 124 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
135 case SEC_ERROR_POLICY_VALIDATION_FAILED: | 135 case SEC_ERROR_POLICY_VALIDATION_FAILED: |
136 return CERT_STATUS_INVALID; | 136 return CERT_STATUS_INVALID; |
137 default: | 137 default: |
138 return 0; | 138 return 0; |
139 } | 139 } |
140 } | 140 } |
141 | 141 |
142 // Saves some information about the certificate chain cert_list in | 142 // Saves some information about the certificate chain cert_list in |
143 // *verify_result. The caller MUST initialize *verify_result before calling | 143 // *verify_result. The caller MUST initialize *verify_result before calling |
144 // this function. | 144 // this function. |
145 // Note that cert_list[0] is the end entity certificate and cert_list doesn't | 145 // Note that cert_list[0] is the end entity certificate |
146 // contain the root CA certificate. | 146 void GetCertChainInfo(int flags, |
147 void GetCertChainInfo(CERTCertList* cert_list, | 147 CERTCertList* cert_list, |
| 148 CERTCertificate* trust_anchor, |
148 CertVerifyResult* verify_result) { | 149 CertVerifyResult* verify_result) { |
149 // NOTE: Using a NSS library before 3.12.3.1 will crash below. To see the | 150 // NOTE: Using a NSS library before 3.12.3.1 will crash below. To see the |
150 // NSS version currently in use: | 151 // NSS version currently in use: |
151 // 1. use ldd on the chrome executable for NSS's location (ie. libnss3.so*) | 152 // 1. use ldd on the chrome executable for NSS's location (ie. libnss3.so*) |
152 // 2. use ident libnss3.so* for the library's version | 153 // 2. use ident libnss3.so* for the library's version |
153 DCHECK(cert_list); | 154 DCHECK(cert_list); |
| 155 bool return_chain = !!(flags & x509_chain::VERIFY_RETURN_CHAIN); |
| 156 X509Certificate::OSCertHandles intermediates; |
154 int i = 0; | 157 int i = 0; |
155 for (CERTCertListNode* node = CERT_LIST_HEAD(cert_list); | 158 for (CERTCertListNode* node = CERT_LIST_HEAD(cert_list); |
156 !CERT_LIST_END(node, cert_list); | 159 !CERT_LIST_END(node, cert_list); |
157 node = CERT_LIST_NEXT(node), i++) { | 160 node = CERT_LIST_NEXT(node), i++) { |
158 SECAlgorithmID& signature = node->cert->signature; | 161 SECAlgorithmID& signature = node->cert->signature; |
159 SECOidTag oid_tag = SECOID_FindOIDTag(&signature.algorithm); | 162 SECOidTag oid_tag = SECOID_FindOIDTag(&signature.algorithm); |
160 switch (oid_tag) { | 163 switch (oid_tag) { |
161 case SEC_OID_PKCS1_MD5_WITH_RSA_ENCRYPTION: | 164 case SEC_OID_PKCS1_MD5_WITH_RSA_ENCRYPTION: |
162 verify_result->has_md5 = true; | 165 verify_result->has_md5 = true; |
163 if (i != 0) | 166 if (i != 0) |
164 verify_result->has_md5_ca = true; | 167 verify_result->has_md5_ca = true; |
165 break; | 168 break; |
166 case SEC_OID_PKCS1_MD2_WITH_RSA_ENCRYPTION: | 169 case SEC_OID_PKCS1_MD2_WITH_RSA_ENCRYPTION: |
167 verify_result->has_md2 = true; | 170 verify_result->has_md2 = true; |
168 if (i != 0) | 171 if (i != 0) |
169 verify_result->has_md2_ca = true; | 172 verify_result->has_md2_ca = true; |
170 break; | 173 break; |
171 case SEC_OID_PKCS1_MD4_WITH_RSA_ENCRYPTION: | 174 case SEC_OID_PKCS1_MD4_WITH_RSA_ENCRYPTION: |
172 verify_result->has_md4 = true; | 175 verify_result->has_md4 = true; |
173 break; | 176 break; |
174 default: | 177 default: |
175 break; | 178 break; |
176 } | 179 } |
| 180 |
| 181 if (return_chain && i != 0) |
| 182 intermediates.push_back(node->cert); |
| 183 } |
| 184 |
| 185 if (return_chain) { |
| 186 if (trust_anchor) |
| 187 intermediates.push_back(trust_anchor); |
| 188 verify_result->certificate = X509Certificate::CreateFromHandle( |
| 189 CERT_LIST_HEAD(cert_list)->cert, intermediates); |
177 } | 190 } |
178 } | 191 } |
179 | 192 |
180 // Forward declarations. | 193 // Forward declarations. |
181 SECStatus RetryPKIXVerifyCertWithWorkarounds( | 194 SECStatus RetryPKIXVerifyCertWithWorkarounds( |
182 X509Certificate::OSCertHandle cert_handle, int num_policy_oids, | 195 X509Certificate::OSCertHandle cert_handle, int num_policy_oids, |
183 std::vector<CERTValInParam>* cvin, CERTValOutParam* cvout); | 196 std::vector<CERTValInParam>* cvin, CERTValOutParam* cvout); |
184 SECOidTag GetFirstCertPolicy(X509Certificate::OSCertHandle cert_handle); | 197 SECOidTag GetFirstCertPolicy(X509Certificate::OSCertHandle cert_handle); |
185 | 198 |
186 // Call CERT_PKIXVerifyCert for the cert_handle. | 199 // Call CERT_PKIXVerifyCert for the cert_handle. |
(...skipping 297 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
484 hostname.c_str()); | 497 hostname.c_str()); |
485 if (status != SECSuccess) | 498 if (status != SECSuccess) |
486 verify_result->cert_status |= CERT_STATUS_COMMON_NAME_INVALID; | 499 verify_result->cert_status |= CERT_STATUS_COMMON_NAME_INVALID; |
487 | 500 |
488 // Make sure that the cert is valid now. | 501 // Make sure that the cert is valid now. |
489 SECCertTimeValidity validity = CERT_CheckCertValidTimes( | 502 SECCertTimeValidity validity = CERT_CheckCertValidTimes( |
490 certificate->os_cert_handle(), PR_Now(), PR_TRUE); | 503 certificate->os_cert_handle(), PR_Now(), PR_TRUE); |
491 if (validity != secCertTimeValid) | 504 if (validity != secCertTimeValid) |
492 verify_result->cert_status |= CERT_STATUS_DATE_INVALID; | 505 verify_result->cert_status |= CERT_STATUS_DATE_INVALID; |
493 | 506 |
494 CERTValOutParam cvout[3]; | 507 CERTValOutParam cvout[4]; |
495 int cvout_index = 0; | 508 int cvout_index = 0; |
496 // We don't need the trust anchor for the first PKIXVerifyCert call. | |
497 cvout[cvout_index].type = cert_po_certList; | 509 cvout[cvout_index].type = cert_po_certList; |
498 cvout[cvout_index].value.pointer.chain = NULL; | 510 cvout[cvout_index].value.pointer.chain = NULL; |
499 int cvout_cert_list_index = cvout_index; | 511 int cvout_cert_list_index = cvout_index; |
500 cvout_index++; | 512 cvout_index++; |
| 513 cvout[cvout_index].type = cert_po_trustAnchor; |
| 514 cvout[cvout_index].value.pointer.cert = NULL; |
| 515 int cvout_trust_anchor_index = cvout_index; |
| 516 cvout_index++; |
501 cvout[cvout_index].type = cert_po_end; | 517 cvout[cvout_index].type = cert_po_end; |
502 ScopedCERTValOutParam scoped_cvout(cvout); | 518 ScopedCERTValOutParam scoped_cvout(cvout); |
503 | 519 |
504 bool check_revocation = (flags & VERIFY_REV_CHECKING_ENABLED); | 520 bool check_revocation = (flags & VERIFY_REV_CHECKING_ENABLED); |
505 if (check_revocation) { | 521 if (check_revocation) { |
506 verify_result->cert_status |= CERT_STATUS_REV_CHECKING_ENABLED; | 522 verify_result->cert_status |= CERT_STATUS_REV_CHECKING_ENABLED; |
507 } else { | 523 } else { |
508 // EV requires revocation checking. | 524 // EV requires revocation checking. |
509 flags &= ~VERIFY_EV_CERT; | 525 flags &= ~VERIFY_EV_CERT; |
510 } | 526 } |
(...skipping 10 matching lines...) Expand all Loading... |
521 err = SEC_ERROR_EXPIRED_CERTIFICATE; | 537 err = SEC_ERROR_EXPIRED_CERTIFICATE; |
522 int cert_status = MapCertErrorToCertStatus(err); | 538 int cert_status = MapCertErrorToCertStatus(err); |
523 if (cert_status) { | 539 if (cert_status) { |
524 verify_result->cert_status |= cert_status; | 540 verify_result->cert_status |= cert_status; |
525 return MapCertStatusToNetError(verify_result->cert_status); | 541 return MapCertStatusToNetError(verify_result->cert_status); |
526 } | 542 } |
527 // |err| is not a certificate error. | 543 // |err| is not a certificate error. |
528 return MapSecurityError(err); | 544 return MapSecurityError(err); |
529 } | 545 } |
530 | 546 |
531 GetCertChainInfo(cvout[cvout_cert_list_index].value.pointer.chain, | 547 GetCertChainInfo(flags, cvout[cvout_cert_list_index].value.pointer.chain, |
| 548 cvout[cvout_trust_anchor_index].value.pointer.cert, |
532 verify_result); | 549 verify_result); |
533 if (IsCertStatusError(verify_result->cert_status)) | 550 if (IsCertStatusError(verify_result->cert_status)) |
534 return MapCertStatusToNetError(verify_result->cert_status); | 551 return MapCertStatusToNetError(verify_result->cert_status); |
535 | 552 |
536 if ((flags & VERIFY_EV_CERT) && VerifyEV(certificate)) | 553 if ((flags & VERIFY_EV_CERT) && VerifyEV(certificate)) |
537 verify_result->cert_status |= CERT_STATUS_IS_EV; | 554 verify_result->cert_status |= CERT_STATUS_IS_EV; |
538 return OK; | 555 return OK; |
539 } | 556 } |
540 | 557 |
541 } // namespace x509_chain | 558 } // namespace x509_chain |
542 | 559 |
543 } // namespace net | 560 } // namespace net |
OLD | NEW |