Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(175)

Side by Side Diff: net/base/x509_certificate_nss.cc

Issue 3112013: Move chain building/verification out of X509Certificate (Closed)
Patch Set: Rebase to trunk - Without OpenSSL fixes Created 10 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2006-2008 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 <nss.h> 8 #include <nss.h>
9 #include <pk11pub.h>
10 #include <prerror.h>
11 #include <prtime.h> 9 #include <prtime.h>
12 #include <secder.h> 10 #include <secder.h>
13 #include <secerr.h>
14 #include <sechash.h> 11 #include <sechash.h>
15 #include <sslerr.h>
16 12
17 #include "base/logging.h" 13 #include "base/logging.h"
18 #include "base/pickle.h" 14 #include "base/pickle.h"
19 #include "base/scoped_ptr.h" 15 #include "base/scoped_ptr.h"
20 #include "base/time.h" 16 #include "base/time.h"
21 #include "base/nss_util.h" 17 #include "base/nss_util.h"
22 #include "net/base/cert_status_flags.h" 18
23 #include "net/base/cert_verify_result.h"
24 #include "net/base/ev_root_ca_metadata.h"
25 #include "net/base/net_errors.h"
26 19
27 namespace net { 20 namespace net {
28 21
29 namespace { 22 namespace {
30 23
31 class ScopedCERTCertificatePolicies {
32 public:
33 explicit ScopedCERTCertificatePolicies(CERTCertificatePolicies* policies)
34 : policies_(policies) {}
35
36 ~ScopedCERTCertificatePolicies() {
37 if (policies_)
38 CERT_DestroyCertificatePoliciesExtension(policies_);
39 }
40
41 private:
42 CERTCertificatePolicies* policies_;
43
44 DISALLOW_COPY_AND_ASSIGN(ScopedCERTCertificatePolicies);
45 };
46
47 // ScopedCERTValOutParam manages destruction of values in the CERTValOutParam
48 // array that cvout points to. cvout must be initialized as passed to
49 // CERT_PKIXVerifyCert, so that the array must be terminated with
50 // cert_po_end type.
51 // When it goes out of scope, it destroys values of cert_po_trustAnchor
52 // and cert_po_certList types, but doesn't release the array itself.
53 class ScopedCERTValOutParam {
54 public:
55 explicit ScopedCERTValOutParam(CERTValOutParam* cvout)
56 : cvout_(cvout) {}
57
58 ~ScopedCERTValOutParam() {
59 if (cvout_ == NULL)
60 return;
61 for (CERTValOutParam *p = cvout_; p->type != cert_po_end; p++) {
62 switch (p->type) {
63 case cert_po_trustAnchor:
64 if (p->value.pointer.cert) {
65 CERT_DestroyCertificate(p->value.pointer.cert);
66 p->value.pointer.cert = NULL;
67 }
68 break;
69 case cert_po_certList:
70 if (p->value.pointer.chain) {
71 CERT_DestroyCertList(p->value.pointer.chain);
72 p->value.pointer.chain = NULL;
73 }
74 break;
75 default:
76 break;
77 }
78 }
79 }
80
81 private:
82 CERTValOutParam* cvout_;
83
84 DISALLOW_COPY_AND_ASSIGN(ScopedCERTValOutParam);
85 };
86
87 // Map PORT_GetError() return values to our network error codes.
88 int MapSecurityError(int err) {
89 switch (err) {
90 case PR_DIRECTORY_LOOKUP_ERROR: // DNS lookup error.
91 return ERR_NAME_NOT_RESOLVED;
92 case SEC_ERROR_INVALID_ARGS:
93 return ERR_INVALID_ARGUMENT;
94 case SSL_ERROR_BAD_CERT_DOMAIN:
95 return ERR_CERT_COMMON_NAME_INVALID;
96 case SEC_ERROR_INVALID_TIME:
97 case SEC_ERROR_EXPIRED_CERTIFICATE:
98 return ERR_CERT_DATE_INVALID;
99 case SEC_ERROR_UNKNOWN_ISSUER:
100 case SEC_ERROR_UNTRUSTED_ISSUER:
101 case SEC_ERROR_CA_CERT_INVALID:
102 case SEC_ERROR_UNTRUSTED_CERT:
103 return ERR_CERT_AUTHORITY_INVALID;
104 case SEC_ERROR_REVOKED_CERTIFICATE:
105 return ERR_CERT_REVOKED;
106 case SEC_ERROR_BAD_DER:
107 case SEC_ERROR_BAD_SIGNATURE:
108 case SEC_ERROR_CERT_NOT_VALID:
109 // TODO(port): add an ERR_CERT_WRONG_USAGE error code.
110 case SEC_ERROR_CERT_USAGES_INVALID:
111 case SEC_ERROR_POLICY_VALIDATION_FAILED:
112 return ERR_CERT_INVALID;
113 default:
114 LOG(WARNING) << "Unknown error " << err << " mapped to net::ERR_FAILED";
115 return ERR_FAILED;
116 }
117 }
118
119 // Map PORT_GetError() return values to our cert status flags.
120 int MapCertErrorToCertStatus(int err) {
121 switch (err) {
122 case SSL_ERROR_BAD_CERT_DOMAIN:
123 return CERT_STATUS_COMMON_NAME_INVALID;
124 case SEC_ERROR_INVALID_TIME:
125 case SEC_ERROR_EXPIRED_CERTIFICATE:
126 return CERT_STATUS_DATE_INVALID;
127 case SEC_ERROR_UNTRUSTED_CERT:
128 case SEC_ERROR_UNKNOWN_ISSUER:
129 case SEC_ERROR_UNTRUSTED_ISSUER:
130 case SEC_ERROR_CA_CERT_INVALID:
131 return CERT_STATUS_AUTHORITY_INVALID;
132 // TODO(port): map CERT_STATUS_NO_REVOCATION_MECHANISM.
133 case SEC_ERROR_OCSP_BAD_HTTP_RESPONSE:
134 case SEC_ERROR_OCSP_SERVER_ERROR:
135 return CERT_STATUS_UNABLE_TO_CHECK_REVOCATION;
136 case SEC_ERROR_REVOKED_CERTIFICATE:
137 return CERT_STATUS_REVOKED;
138 case SEC_ERROR_BAD_DER:
139 case SEC_ERROR_BAD_SIGNATURE:
140 case SEC_ERROR_CERT_NOT_VALID:
141 // TODO(port): add a CERT_STATUS_WRONG_USAGE error code.
142 case SEC_ERROR_CERT_USAGES_INVALID:
143 case SEC_ERROR_POLICY_VALIDATION_FAILED:
144 return CERT_STATUS_INVALID;
145 default:
146 return 0;
147 }
148 }
149
150 // Saves some information about the certificate chain cert_list in
151 // *verify_result. The caller MUST initialize *verify_result before calling
152 // this function.
153 // Note that cert_list[0] is the end entity certificate and cert_list doesn't
154 // contain the root CA certificate.
155 void GetCertChainInfo(CERTCertList* cert_list,
156 CertVerifyResult* verify_result) {
157 // NOTE: Using a NSS library before 3.12.3.1 will crash below. To see the
158 // NSS version currently in use:
159 // 1. use ldd on the chrome executable for NSS's location (ie. libnss3.so*)
160 // 2. use ident libnss3.so* for the library's version
161 DCHECK(cert_list);
162 int i = 0;
163 for (CERTCertListNode* node = CERT_LIST_HEAD(cert_list);
164 !CERT_LIST_END(node, cert_list);
165 node = CERT_LIST_NEXT(node), i++) {
166 SECAlgorithmID& signature = node->cert->signature;
167 SECOidTag oid_tag = SECOID_FindOIDTag(&signature.algorithm);
168 switch (oid_tag) {
169 case SEC_OID_PKCS1_MD5_WITH_RSA_ENCRYPTION:
170 verify_result->has_md5 = true;
171 if (i != 0)
172 verify_result->has_md5_ca = true;
173 break;
174 case SEC_OID_PKCS1_MD2_WITH_RSA_ENCRYPTION:
175 verify_result->has_md2 = true;
176 if (i != 0)
177 verify_result->has_md2_ca = true;
178 break;
179 case SEC_OID_PKCS1_MD4_WITH_RSA_ENCRYPTION:
180 verify_result->has_md4 = true;
181 break;
182 default:
183 break;
184 }
185 }
186 }
187
188 typedef char* (*CERTGetNameFunc)(CERTName* name); 24 typedef char* (*CERTGetNameFunc)(CERTName* name);
189 25
190 void ParsePrincipal(CERTName* name, 26 void ParsePrincipal(CERTName* name,
191 CertPrincipal* principal) { 27 CertPrincipal* principal) {
192 // TODO(jcampan): add business_category and serial_number. 28 // TODO(jcampan): add business_category and serial_number.
193 // TODO(wtc): NSS has the CERT_GetOrgName, CERT_GetOrgUnitName, and 29 // TODO(wtc): NSS has the CERT_GetOrgName, CERT_GetOrgUnitName, and
194 // CERT_GetDomainComponentName functions, but they return only the most 30 // CERT_GetDomainComponentName functions, but they return only the most
195 // general (the first) RDN. NSS doesn't have a function for the street 31 // general (the first) RDN. NSS doesn't have a function for the street
196 // address. 32 // address.
197 static const SECOidTag kOIDs[] = { 33 static const SECOidTag kOIDs[] = {
(...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after
284 std::string value = std::string(reinterpret_cast<char*>(p), len); 120 std::string value = std::string(reinterpret_cast<char*>(p), len);
285 result->push_back(value); 121 result->push_back(value);
286 } 122 }
287 name = CERT_GetNextGeneralName(name); 123 name = CERT_GetNextGeneralName(name);
288 if (name == alt_name_list) 124 if (name == alt_name_list)
289 break; 125 break;
290 } 126 }
291 PORT_FreeArena(arena, PR_FALSE); 127 PORT_FreeArena(arena, PR_FALSE);
292 } 128 }
293 129
294 // Forward declarations.
295 SECStatus RetryPKIXVerifyCertWithWorkarounds(
296 X509Certificate::OSCertHandle cert_handle, int num_policy_oids,
297 std::vector<CERTValInParam>* cvin, CERTValOutParam* cvout);
298 SECOidTag GetFirstCertPolicy(X509Certificate::OSCertHandle cert_handle);
299
300 // Call CERT_PKIXVerifyCert for the cert_handle.
301 // Verification results are stored in an array of CERTValOutParam.
302 // If policy_oids is not NULL and num_policy_oids is positive, policies
303 // are also checked.
304 // Caller must initialize cvout before calling this function.
305 SECStatus PKIXVerifyCert(X509Certificate::OSCertHandle cert_handle,
306 bool check_revocation,
307 const SECOidTag* policy_oids,
308 int num_policy_oids,
309 CERTValOutParam* cvout) {
310 bool use_crl = check_revocation;
311 bool use_ocsp = check_revocation;
312
313 // These CAs have multiple keys, which trigger two bugs in NSS's CRL code.
314 // 1. NSS may use one key to verify a CRL signed with another key,
315 // incorrectly concluding that the CRL's signature is invalid.
316 // Hopefully this bug will be fixed in NSS 3.12.9.
317 // 2. NSS considers all certificates issued by the CA as revoked when it
318 // receives a CRL with an invalid signature. This overly strict policy
319 // has been relaxed in NSS 3.12.7. See
320 // https://bugzilla.mozilla.org/show_bug.cgi?id=562542.
321 // So we have to turn off CRL checking for these CAs. See
322 // http://crbug.com/55695.
323 static const char* const kMultipleKeyCA[] = {
324 "CN=Microsoft Secure Server Authority,"
325 "DC=redmond,DC=corp,DC=microsoft,DC=com",
326 "CN=Microsoft Secure Server Authority",
327 };
328
329 if (!NSS_VersionCheck("3.12.7")) {
330 for (size_t i = 0; i < arraysize(kMultipleKeyCA); ++i) {
331 if (strcmp(cert_handle->issuerName, kMultipleKeyCA[i]) == 0) {
332 use_crl = false;
333 break;
334 }
335 }
336 }
337
338 PRUint64 revocation_method_flags =
339 CERT_REV_M_DO_NOT_TEST_USING_THIS_METHOD |
340 CERT_REV_M_ALLOW_NETWORK_FETCHING |
341 CERT_REV_M_IGNORE_IMPLICIT_DEFAULT_SOURCE |
342 CERT_REV_M_IGNORE_MISSING_FRESH_INFO |
343 CERT_REV_M_STOP_TESTING_ON_FRESH_INFO;
344 PRUint64 revocation_method_independent_flags =
345 CERT_REV_MI_TEST_ALL_LOCAL_INFORMATION_FIRST;
346 if (policy_oids && num_policy_oids > 0) {
347 // EV verification requires revocation checking. Consider the certificate
348 // revoked if we don't have revocation info.
349 // TODO(wtc): Add a bool parameter to expressly specify we're doing EV
350 // verification or we want strict revocation flags.
351 revocation_method_flags |= CERT_REV_M_REQUIRE_INFO_ON_MISSING_SOURCE;
352 revocation_method_independent_flags |=
353 CERT_REV_MI_REQUIRE_SOME_FRESH_INFO_AVAILABLE;
354 } else {
355 revocation_method_flags |= CERT_REV_M_SKIP_TEST_ON_MISSING_SOURCE;
356 revocation_method_independent_flags |=
357 CERT_REV_MI_NO_OVERALL_INFO_REQUIREMENT;
358 }
359 PRUint64 method_flags[2];
360 method_flags[cert_revocation_method_crl] = revocation_method_flags;
361 method_flags[cert_revocation_method_ocsp] = revocation_method_flags;
362
363 if (use_crl) {
364 method_flags[cert_revocation_method_crl] |=
365 CERT_REV_M_TEST_USING_THIS_METHOD;
366 }
367 if (use_ocsp) {
368 method_flags[cert_revocation_method_ocsp] |=
369 CERT_REV_M_TEST_USING_THIS_METHOD;
370 }
371
372 CERTRevocationMethodIndex preferred_revocation_methods[1];
373 if (use_ocsp) {
374 preferred_revocation_methods[0] = cert_revocation_method_ocsp;
375 } else {
376 preferred_revocation_methods[0] = cert_revocation_method_crl;
377 }
378
379 CERTRevocationFlags revocation_flags;
380 revocation_flags.leafTests.number_of_defined_methods =
381 arraysize(method_flags);
382 revocation_flags.leafTests.cert_rev_flags_per_method = method_flags;
383 revocation_flags.leafTests.number_of_preferred_methods =
384 arraysize(preferred_revocation_methods);
385 revocation_flags.leafTests.preferred_methods = preferred_revocation_methods;
386 revocation_flags.leafTests.cert_rev_method_independent_flags =
387 revocation_method_independent_flags;
388
389 revocation_flags.chainTests.number_of_defined_methods =
390 arraysize(method_flags);
391 revocation_flags.chainTests.cert_rev_flags_per_method = method_flags;
392 revocation_flags.chainTests.number_of_preferred_methods =
393 arraysize(preferred_revocation_methods);
394 revocation_flags.chainTests.preferred_methods = preferred_revocation_methods;
395 revocation_flags.chainTests.cert_rev_method_independent_flags =
396 revocation_method_independent_flags;
397
398 std::vector<CERTValInParam> cvin;
399 cvin.reserve(5);
400 CERTValInParam in_param;
401 // No need to set cert_pi_trustAnchors here.
402 in_param.type = cert_pi_revocationFlags;
403 in_param.value.pointer.revocation = &revocation_flags;
404 cvin.push_back(in_param);
405 if (policy_oids && num_policy_oids > 0) {
406 in_param.type = cert_pi_policyOID;
407 in_param.value.arraySize = num_policy_oids;
408 in_param.value.array.oids = policy_oids;
409 cvin.push_back(in_param);
410 }
411 in_param.type = cert_pi_end;
412 cvin.push_back(in_param);
413
414 SECStatus rv = CERT_PKIXVerifyCert(cert_handle, certificateUsageSSLServer,
415 &cvin[0], cvout, NULL);
416 if (rv != SECSuccess) {
417 rv = RetryPKIXVerifyCertWithWorkarounds(cert_handle, num_policy_oids,
418 &cvin, cvout);
419 }
420 return rv;
421 }
422
423 // PKIXVerifyCert calls this function to work around some bugs in
424 // CERT_PKIXVerifyCert. All the arguments of this function are either the
425 // arguments or local variables of PKIXVerifyCert.
426 SECStatus RetryPKIXVerifyCertWithWorkarounds(
427 X509Certificate::OSCertHandle cert_handle, int num_policy_oids,
428 std::vector<CERTValInParam>* cvin, CERTValOutParam* cvout) {
429 // We call this function when the first CERT_PKIXVerifyCert call in
430 // PKIXVerifyCert failed, so we initialize |rv| to SECFailure.
431 SECStatus rv = SECFailure;
432 int nss_error = PORT_GetError();
433 CERTValInParam in_param;
434
435 // If we get SEC_ERROR_UNKNOWN_ISSUER, we may be missing an intermediate
436 // CA certificate, so we retry with cert_pi_useAIACertFetch.
437 // cert_pi_useAIACertFetch has several bugs in its error handling and
438 // error reporting (NSS bug 528743), so we don't use it by default.
439 // Note: When building a certificate chain, CERT_PKIXVerifyCert may
440 // incorrectly pick a CA certificate with the same subject name as the
441 // missing intermediate CA certificate, and fail with the
442 // SEC_ERROR_BAD_SIGNATURE error (NSS bug 524013), so we also retry with
443 // cert_pi_useAIACertFetch on SEC_ERROR_BAD_SIGNATURE.
444 if (nss_error == SEC_ERROR_UNKNOWN_ISSUER ||
445 nss_error == SEC_ERROR_BAD_SIGNATURE) {
446 DCHECK_EQ(cvin->back().type, cert_pi_end);
447 cvin->pop_back();
448 in_param.type = cert_pi_useAIACertFetch;
449 in_param.value.scalar.b = PR_TRUE;
450 cvin->push_back(in_param);
451 in_param.type = cert_pi_end;
452 cvin->push_back(in_param);
453 rv = CERT_PKIXVerifyCert(cert_handle, certificateUsageSSLServer,
454 &(*cvin)[0], cvout, NULL);
455 if (rv == SECSuccess)
456 return rv;
457 int new_nss_error = PORT_GetError();
458 if (new_nss_error == SEC_ERROR_INVALID_ARGS ||
459 new_nss_error == SEC_ERROR_UNKNOWN_AIA_LOCATION_TYPE ||
460 new_nss_error == SEC_ERROR_BAD_HTTP_RESPONSE ||
461 new_nss_error == SEC_ERROR_BAD_LDAP_RESPONSE ||
462 !IS_SEC_ERROR(new_nss_error)) {
463 // Use the original error code because of cert_pi_useAIACertFetch's
464 // bad error reporting.
465 PORT_SetError(nss_error);
466 return rv;
467 }
468 nss_error = new_nss_error;
469 }
470
471 // If an intermediate CA certificate has requireExplicitPolicy in its
472 // policyConstraints extension, CERT_PKIXVerifyCert fails with
473 // SEC_ERROR_POLICY_VALIDATION_FAILED because we didn't specify any
474 // certificate policy (NSS bug 552775). So we retry with the certificate
475 // policy found in the server certificate.
476 if (nss_error == SEC_ERROR_POLICY_VALIDATION_FAILED &&
477 num_policy_oids == 0) {
478 SECOidTag policy = GetFirstCertPolicy(cert_handle);
479 if (policy != SEC_OID_UNKNOWN) {
480 DCHECK_EQ(cvin->back().type, cert_pi_end);
481 cvin->pop_back();
482 in_param.type = cert_pi_policyOID;
483 in_param.value.arraySize = 1;
484 in_param.value.array.oids = &policy;
485 cvin->push_back(in_param);
486 in_param.type = cert_pi_end;
487 cvin->push_back(in_param);
488 rv = CERT_PKIXVerifyCert(cert_handle, certificateUsageSSLServer,
489 &(*cvin)[0], cvout, NULL);
490 if (rv != SECSuccess) {
491 // Use the original error code.
492 PORT_SetError(nss_error);
493 }
494 }
495 }
496
497 return rv;
498 }
499
500 // Decodes the certificatePolicies extension of the certificate. Returns
501 // NULL if the certificate doesn't have the extension or the extension can't
502 // be decoded. The returned value must be freed with a
503 // CERT_DestroyCertificatePoliciesExtension call.
504 CERTCertificatePolicies* DecodeCertPolicies(
505 X509Certificate::OSCertHandle cert_handle) {
506 SECItem policy_ext;
507 SECStatus rv = CERT_FindCertExtension(
508 cert_handle, SEC_OID_X509_CERTIFICATE_POLICIES, &policy_ext);
509 if (rv != SECSuccess)
510 return NULL;
511 CERTCertificatePolicies* policies =
512 CERT_DecodeCertificatePoliciesExtension(&policy_ext);
513 SECITEM_FreeItem(&policy_ext, PR_FALSE);
514 return policies;
515 }
516
517 // Returns the OID tag for the first certificate policy in the certificate's
518 // certificatePolicies extension. Returns SEC_OID_UNKNOWN if the certificate
519 // has no certificate policy.
520 SECOidTag GetFirstCertPolicy(X509Certificate::OSCertHandle cert_handle) {
521 CERTCertificatePolicies* policies = DecodeCertPolicies(cert_handle);
522 if (!policies)
523 return SEC_OID_UNKNOWN;
524 ScopedCERTCertificatePolicies scoped_policies(policies);
525 CERTPolicyInfo* policy_info = policies->policyInfos[0];
526 if (!policy_info)
527 return SEC_OID_UNKNOWN;
528 if (policy_info->oid != SEC_OID_UNKNOWN)
529 return policy_info->oid;
530
531 // The certificate policy is unknown to NSS. We need to create a dynamic
532 // OID tag for the policy.
533 SECOidData od;
534 od.oid.len = policy_info->policyID.len;
535 od.oid.data = policy_info->policyID.data;
536 od.offset = SEC_OID_UNKNOWN;
537 // NSS doesn't allow us to pass an empty description, so I use a hardcoded,
538 // default description here. The description doesn't need to be unique for
539 // each OID.
540 od.desc = "a certificate policy";
541 od.mechanism = CKM_INVALID_MECHANISM;
542 od.supportedExtension = INVALID_CERT_EXTENSION;
543 return SECOID_AddEntry(&od);
544 }
545
546 bool CheckCertPolicies(X509Certificate::OSCertHandle cert_handle,
547 SECOidTag ev_policy_tag) {
548 CERTCertificatePolicies* policies = DecodeCertPolicies(cert_handle);
549 if (!policies) {
550 LOG(ERROR) << "Cert has no policies extension or extension couldn't be "
551 "decoded.";
552 return false;
553 }
554 ScopedCERTCertificatePolicies scoped_policies(policies);
555 CERTPolicyInfo** policy_infos = policies->policyInfos;
556 while (*policy_infos != NULL) {
557 CERTPolicyInfo* policy_info = *policy_infos++;
558 SECOidTag oid_tag = policy_info->oid;
559 if (oid_tag == SEC_OID_UNKNOWN)
560 continue;
561 if (oid_tag == ev_policy_tag)
562 return true;
563 }
564 LOG(ERROR) << "No EV Policy Tag";
565 return false;
566 }
567
568 SECStatus PR_CALLBACK 130 SECStatus PR_CALLBACK
569 CollectCertsCallback(void* arg, SECItem** certs, int num_certs) { 131 CollectCertsCallback(void* arg, SECItem** certs, int num_certs) {
570 X509Certificate::OSCertHandles* results = 132 X509Certificate::OSCertHandles* results =
571 reinterpret_cast<X509Certificate::OSCertHandles*>(arg); 133 reinterpret_cast<X509Certificate::OSCertHandles*>(arg);
572 134
573 for (int i = 0; i < num_certs; ++i) { 135 for (int i = 0; i < num_certs; ++i) {
574 X509Certificate::OSCertHandle handle = 136 X509Certificate::OSCertHandle handle =
575 X509Certificate::CreateOSCertHandleFromBytes( 137 X509Certificate::CreateOSCertHandleFromBytes(
576 reinterpret_cast<char*>(certs[i]->data), certs[i]->len); 138 reinterpret_cast<char*>(certs[i]->data), certs[i]->len);
577 if (handle) 139 if (handle)
(...skipping 23 matching lines...) Expand all
601 163
602 if (dns_names->empty()) 164 if (dns_names->empty())
603 dns_names->push_back(subject_.common_name); 165 dns_names->push_back(subject_.common_name);
604 } 166 }
605 167
606 X509Certificate::OSCertListHandle 168 X509Certificate::OSCertListHandle
607 X509Certificate::CreateOSCertListHandle() const { 169 X509Certificate::CreateOSCertListHandle() const {
608 return CERT_DupCertificate(cert_handle_); 170 return CERT_DupCertificate(cert_handle_);
609 } 171 }
610 172
611 int X509Certificate::Verify(const std::string& hostname,
612 int flags,
613 CertVerifyResult* verify_result) const {
614 verify_result->Reset();
615
616 // Make sure that the hostname matches with the common name of the cert.
617 SECStatus status = CERT_VerifyCertName(cert_handle_, hostname.c_str());
618 if (status != SECSuccess)
619 verify_result->cert_status |= CERT_STATUS_COMMON_NAME_INVALID;
620
621 // Make sure that the cert is valid now.
622 SECCertTimeValidity validity = CERT_CheckCertValidTimes(
623 cert_handle_, PR_Now(), PR_TRUE);
624 if (validity != secCertTimeValid)
625 verify_result->cert_status |= CERT_STATUS_DATE_INVALID;
626
627 CERTValOutParam cvout[3];
628 int cvout_index = 0;
629 // We don't need the trust anchor for the first PKIXVerifyCert call.
630 cvout[cvout_index].type = cert_po_certList;
631 cvout[cvout_index].value.pointer.chain = NULL;
632 int cvout_cert_list_index = cvout_index;
633 cvout_index++;
634 cvout[cvout_index].type = cert_po_end;
635 ScopedCERTValOutParam scoped_cvout(cvout);
636
637 bool check_revocation = (flags & VERIFY_REV_CHECKING_ENABLED);
638 if (check_revocation) {
639 verify_result->cert_status |= CERT_STATUS_REV_CHECKING_ENABLED;
640 } else {
641 // EV requires revocation checking.
642 flags &= ~VERIFY_EV_CERT;
643 }
644 status = PKIXVerifyCert(cert_handle_, check_revocation, NULL, 0, cvout);
645 if (status != SECSuccess) {
646 int err = PORT_GetError();
647 LOG(ERROR) << "CERT_PKIXVerifyCert for " << hostname
648 << " failed err=" << err;
649 // CERT_PKIXVerifyCert rerports the wrong error code for
650 // expired certificates (NSS bug 491174)
651 if (err == SEC_ERROR_CERT_NOT_VALID &&
652 (verify_result->cert_status & CERT_STATUS_DATE_INVALID) != 0)
653 err = SEC_ERROR_EXPIRED_CERTIFICATE;
654 int cert_status = MapCertErrorToCertStatus(err);
655 if (cert_status) {
656 verify_result->cert_status |= cert_status;
657 return MapCertStatusToNetError(verify_result->cert_status);
658 }
659 // |err| is not a certificate error.
660 return MapSecurityError(err);
661 }
662
663 GetCertChainInfo(cvout[cvout_cert_list_index].value.pointer.chain,
664 verify_result);
665 if (IsCertStatusError(verify_result->cert_status))
666 return MapCertStatusToNetError(verify_result->cert_status);
667
668 if ((flags & VERIFY_EV_CERT) && VerifyEV())
669 verify_result->cert_status |= CERT_STATUS_IS_EV;
670 return OK;
671 }
672
673 // Studied Mozilla's code (esp. security/manager/ssl/src/nsIdentityChecking.cpp
674 // and nsNSSCertHelper.cpp) to learn how to verify EV certificate.
675 // TODO(wtc): A possible optimization is that we get the trust anchor from
676 // the first PKIXVerifyCert call. We look up the EV policy for the trust
677 // anchor. If the trust anchor has no EV policy, we know the cert isn't EV.
678 // Otherwise, we pass just that EV policy (as opposed to all the EV policies)
679 // to the second PKIXVerifyCert call.
680 bool X509Certificate::VerifyEV() const {
681 net::EVRootCAMetadata* metadata = net::EVRootCAMetadata::GetInstance();
682
683 CERTValOutParam cvout[3];
684 int cvout_index = 0;
685 cvout[cvout_index].type = cert_po_trustAnchor;
686 cvout[cvout_index].value.pointer.cert = NULL;
687 int cvout_trust_anchor_index = cvout_index;
688 cvout_index++;
689 cvout[cvout_index].type = cert_po_end;
690 ScopedCERTValOutParam scoped_cvout(cvout);
691
692 SECStatus status = PKIXVerifyCert(cert_handle_,
693 true,
694 metadata->GetPolicyOIDs(),
695 metadata->NumPolicyOIDs(),
696 cvout);
697 if (status != SECSuccess)
698 return false;
699
700 CERTCertificate* root_ca =
701 cvout[cvout_trust_anchor_index].value.pointer.cert;
702 if (root_ca == NULL)
703 return false;
704 SHA1Fingerprint fingerprint =
705 X509Certificate::CalculateFingerprint(root_ca);
706 SECOidTag ev_policy_tag = SEC_OID_UNKNOWN;
707 if (!metadata->GetPolicyOID(fingerprint, &ev_policy_tag))
708 return false;
709
710 if (!CheckCertPolicies(cert_handle_, ev_policy_tag))
711 return false;
712
713 return true;
714 }
715
716 // static 173 // static
717 bool X509Certificate::IsSameOSCert(X509Certificate::OSCertHandle a, 174 bool X509Certificate::IsSameOSCert(X509Certificate::OSCertHandle a,
718 X509Certificate::OSCertHandle b) { 175 X509Certificate::OSCertHandle b) {
719 DCHECK(a && b); 176 DCHECK(a && b);
720 if (a == b) 177 if (a == b)
721 return true; 178 return true;
722 return a->derCert.len == b->derCert.len && 179 return a->derCert.len == b->derCert.len &&
723 memcmp(a->derCert.data, b->derCert.data, a->derCert.len) == 0; 180 memcmp(a->derCert.data, b->derCert.data, a->derCert.len) == 0;
724 } 181 }
725 182
(...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after
827 284
828 // static 285 // static
829 bool X509Certificate::WriteCertHandleToPickle(OSCertHandle cert_handle, 286 bool X509Certificate::WriteCertHandleToPickle(OSCertHandle cert_handle,
830 Pickle* pickle) { 287 Pickle* pickle) {
831 return pickle->WriteData( 288 return pickle->WriteData(
832 reinterpret_cast<const char*>(cert_handle->derCert.data), 289 reinterpret_cast<const char*>(cert_handle->derCert.data),
833 cert_handle->derCert.len); 290 cert_handle->derCert.len);
834 } 291 }
835 292
836 } // namespace net 293 } // namespace net
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698