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

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

Issue 119026: Implement X509Certificate::IsEV for NSS.... (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: '' Created 11 years, 4 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 | Annotate | Revision Log
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 // Work around https://bugzilla.mozilla.org/show_bug.cgi?id=455424 7 // Work around https://bugzilla.mozilla.org/show_bug.cgi?id=455424
8 // until NSS 3.12.2 comes out and we update to it. 8 // until NSS 3.12.2 comes out and we update to it.
9 #define Lock FOO_NSS_Lock 9 #define Lock FOO_NSS_Lock
10 #include <cert.h> 10 #include <cert.h>
11 #include <pk11pub.h> 11 #include <pk11pub.h>
12 #include <prtime.h> 12 #include <prtime.h>
13 #include <secder.h> 13 #include <secder.h>
14 #include <secerr.h> 14 #include <secerr.h>
15 #include <sechash.h> 15 #include <sechash.h>
16 #undef Lock 16 #undef Lock
17 17
18 #include "base/logging.h" 18 #include "base/logging.h"
19 #include "base/pickle.h" 19 #include "base/pickle.h"
20 #include "base/time.h" 20 #include "base/time.h"
21 #include "base/nss_init.h" 21 #include "base/nss_init.h"
22 #include "net/base/cert_status_flags.h" 22 #include "net/base/cert_status_flags.h"
23 #include "net/base/cert_verify_result.h" 23 #include "net/base/cert_verify_result.h"
24 #include "net/base/ev_root_ca_metadata.h"
24 #include "net/base/net_errors.h" 25 #include "net/base/net_errors.h"
25 26
26 namespace net { 27 namespace net {
27 28
28 namespace { 29 namespace {
29 30
30 class ScopedCERTCertificate { 31 class ScopedCERTCertificate {
31 public: 32 public:
32 explicit ScopedCERTCertificate(CERTCertificate* cert) 33 explicit ScopedCERTCertificate(CERTCertificate* cert)
33 : cert_(cert) {} 34 : cert_(cert) {}
(...skipping 160 matching lines...) Expand 10 before | Expand all | Expand 10 after
194 exploded.hour = prxtime.tm_hour; 195 exploded.hour = prxtime.tm_hour;
195 exploded.minute = prxtime.tm_min; 196 exploded.minute = prxtime.tm_min;
196 exploded.second = prxtime.tm_sec; 197 exploded.second = prxtime.tm_sec;
197 exploded.millisecond = prxtime.tm_usec / 1000; 198 exploded.millisecond = prxtime.tm_usec / 1000;
198 199
199 return base::Time::FromUTCExploded(exploded); 200 return base::Time::FromUTCExploded(exploded);
200 } 201 }
201 202
202 void ParsePrincipal(SECItem* der_name, 203 void ParsePrincipal(SECItem* der_name,
203 X509Certificate::Principal* principal) { 204 X509Certificate::Principal* principal) {
204
205 CERTName name; 205 CERTName name;
206 PRArenaPool* arena = NULL; 206 PRArenaPool* arena = NULL;
207 207
208 arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); 208 arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
209 DCHECK(arena != NULL); 209 DCHECK(arena != NULL);
210 if (arena == NULL) 210 if (arena == NULL)
211 return; 211 return;
212 212
213 // TODO(dkegel): is CERT_NameTemplate what we always want here? 213 // TODO(dkegel): is CERT_NameTemplate what we always want here?
214 SECStatus rv; 214 SECStatus rv;
(...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after
279 void ParseDate(SECItem* der_date, base::Time* result) { 279 void ParseDate(SECItem* der_date, base::Time* result) {
280 PRTime prtime; 280 PRTime prtime;
281 SECStatus rv = DER_DecodeTimeChoice(&prtime, der_date); 281 SECStatus rv = DER_DecodeTimeChoice(&prtime, der_date);
282 DCHECK(rv == SECSuccess); 282 DCHECK(rv == SECSuccess);
283 *result = PRTimeToBaseTime(prtime); 283 *result = PRTimeToBaseTime(prtime);
284 } 284 }
285 285
286 void GetCertSubjectAltNamesOfType(X509Certificate::OSCertHandle cert_handle, 286 void GetCertSubjectAltNamesOfType(X509Certificate::OSCertHandle cert_handle,
287 CERTGeneralNameType name_type, 287 CERTGeneralNameType name_type,
288 std::vector<std::string>* result) { 288 std::vector<std::string>* result) {
289
290 SECItem alt_name; 289 SECItem alt_name;
291 SECStatus rv = CERT_FindCertExtension(cert_handle, 290 SECStatus rv = CERT_FindCertExtension(cert_handle,
292 SEC_OID_X509_SUBJECT_ALT_NAME, &alt_name); 291 SEC_OID_X509_SUBJECT_ALT_NAME, &alt_name);
293 if (rv != SECSuccess) 292 if (rv != SECSuccess)
294 return; 293 return;
295 294
296 PRArenaPool* arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); 295 PRArenaPool* arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
297 DCHECK(arena != NULL); 296 DCHECK(arena != NULL);
298 297
299 CERTGeneralName* alt_name_list; 298 CERTGeneralName* alt_name_list;
(...skipping 13 matching lines...) Expand all
313 result->push_back(value); 312 result->push_back(value);
314 } 313 }
315 name = CERT_GetNextGeneralName(name); 314 name = CERT_GetNextGeneralName(name);
316 if (name == alt_name_list) 315 if (name == alt_name_list)
317 break; 316 break;
318 } 317 }
319 PORT_FreeArena(arena, PR_FALSE); 318 PORT_FreeArena(arena, PR_FALSE);
320 PORT_Free(alt_name.data); 319 PORT_Free(alt_name.data);
321 } 320 }
322 321
323 } // namespace 322 // TODO(ukai): make a Linux-only method of the EVRootCAMetadata.
wtc 2009/08/07 04:01:20 Nit: make => this should be Add "class" at the en
323 void GetPolicyOidTags(net::EVRootCAMetadata* metadata,
324 std::vector<SECOidTag>* policies) {
325 const char* const* policy_oids = metadata->GetPolicyOIDs();
326 for (int i = 0; i < metadata->NumPolicyOIDs(); i++) {
327 PRUint8 buf[1024];
328 SECItem oid_item;
329 oid_item.data = buf;
330 oid_item.len = sizeof(buf);
331 SECStatus status = SEC_StringToOID(NULL, &oid_item, policy_oids[i], 0);
332 if (status != SECSuccess) {
333 LOG(ERROR) << "Failed to convert to OID: " << policy_oids[i];
334 continue;
335 }
336 SECOidTag policy = SECOID_FindOIDTag(&oid_item);
337 if (policy == SEC_OID_UNKNOWN) {
338 // Register the OID.
339 SECOidData od;
340 od.oid.len = oid_item.len;
341 od.oid.data = oid_item.data;
342 od.offset = SEC_OID_UNKNOWN;
343 od.desc = policy_oids[i];
344 od.mechanism = CKM_INVALID_MECHANISM;
345 od.supportedExtension = INVALID_CERT_EXTENSION;
346 policy = SECOID_AddEntry(&od);
347 DCHECK(policy != SEC_OID_UNKNOWN);
348 }
349 policies->push_back(policy);
350 }
351 return;
352 }
353
354 // Call CERT_PKIXVerifyCert for the cert_handle.
355 // Verification results are stored in an array of CERTValOutParam.
356 // If metadata is not NULL, policies are also checked.
wtc 2009/08/07 04:01:20 This sentence needs to be updated because 'metadat
357 // Caller must initialize cvout before calling this function.
358 SECStatus PKIXVerifyCert(X509Certificate::OSCertHandle cert_handle,
359 const SECOidTag* policy_oids,
360 int num_policy_oids,
361 CERTValOutParam* cvout) {
362 PRUint64 revocation_method_flags =
363 CERT_REV_M_TEST_USING_THIS_METHOD |
364 CERT_REV_M_ALLOW_NETWORK_FETCHING |
365 CERT_REV_M_ALLOW_IMPLICIT_DEFAULT_SOURCE |
alv 2009/08/08 00:47:15 if you plan to allow user to use default source th
366 CERT_REV_M_REQUIRE_INFO_ON_MISSING_SOURCE |
367 CERT_REV_M_STOP_TESTING_ON_FRESH_INFO;
alv 2009/08/08 00:47:15 I would also list here the defalt CERT_REV_M_IGNOR
368 PRUint64 revocation_method_independent_flags =
369 CERT_REV_MI_TEST_ALL_LOCAL_INFORMATION_FIRST |
370 CERT_REV_MI_REQUIRE_SOME_FRESH_INFO_AVAILABLE;
371 PRUint64 method_flags[2];
372 method_flags[cert_revocation_method_crl] = revocation_method_flags;
373 method_flags[cert_revocation_method_ocsp] = revocation_method_flags;
374
375 // TODO(ukai): need to find out if we need to call OCSP-related NSS functions,
376 // CERT_EnableOCSPChecking, CERT_DisableOCSPDefaultResponder and
377 // CERT_SetOCSPFailureMode.
378 CERTRevocationMethodIndex preferred_revocation_methods[1];
379 preferred_revocation_methods[0] = cert_revocation_method_ocsp;
380
381 CERTRevocationFlags revocation_flags;
382 revocation_flags.leafTests.number_of_defined_methods =
383 arraysize(method_flags);
384 revocation_flags.leafTests.cert_rev_flags_per_method = method_flags;
385 revocation_flags.leafTests.number_of_preferred_methods =
386 arraysize(preferred_revocation_methods);
387 revocation_flags.leafTests.preferred_methods = preferred_revocation_methods;
388 revocation_flags.leafTests.cert_rev_method_independent_flags =
389 revocation_method_independent_flags;
390
391 revocation_flags.chainTests.number_of_defined_methods =
392 arraysize(method_flags);
393 revocation_flags.chainTests.cert_rev_flags_per_method = method_flags;
394 revocation_flags.chainTests.number_of_preferred_methods =
395 arraysize(preferred_revocation_methods);
396 revocation_flags.chainTests.preferred_methods = preferred_revocation_methods;
397 revocation_flags.chainTests.cert_rev_method_independent_flags =
398 revocation_method_independent_flags;
399
400 CERTValInParam cvin[3];
401 int cvin_index = 0;
402 // No need to set cert_pi_trustAnchors here.
403 // TODO(ukai): use cert_pi_useAIACertFetch (new feature in NSS 3.12.1).
404 cvin[cvin_index].type = cert_pi_revocationFlags;
405 cvin[cvin_index].value.pointer.revocation = &revocation_flags;
406 cvin_index++;
407 std::vector<SECOidTag> policies;
408 if (policy_oids && num_policy_oids > 0) {
409 cvin[cvin_index].type = cert_pi_policyOID;
410 cvin[cvin_index].value.arraySize = num_policy_oids;
411 cvin[cvin_index].value.array.oids = policy_oids;
412 cvin_index++;
413 }
414 cvin[cvin_index].type = cert_pi_end;
415
416 return CERT_PKIXVerifyCert(cert_handle, certificateUsageSSLServer,
417 cvin, cvout, NULL);
418 }
419
420 // TODO(ukai): make a Linux-only method of the EVRootCAMetadata.
421 bool GetEvPolicyOidTag(net::EVRootCAMetadata* metadata,
alv 2009/08/08 00:47:15 Seems like this method and GetPolicyOidTags belong
422 const X509Certificate::Fingerprint& fingerprint,
423 SECOidTag* ev_policy_tag) {
424 std::string ev_policy_oid;
425 if (!metadata->GetPolicyOID(fingerprint, &ev_policy_oid)) {
426 LOG(ERROR) << "GetPolicyOID failed";
427 return false;
428 }
429 DCHECK(!ev_policy_oid.empty());
430
431 PRUint8 buf[1024];
432 SECItem oid_item;
433 oid_item.data = buf;
434 oid_item.len = sizeof(buf);
435 SECStatus status = SEC_StringToOID(NULL, &oid_item, ev_policy_oid.data(),
436 ev_policy_oid.length());
437 if (status != SECSuccess) {
438 LOG(ERROR) << "Failed to convert OID:" << ev_policy_oid;
439 return false;
440 }
441 *ev_policy_tag = SECOID_FindOIDTag(&oid_item);
442 return true;
443 }
444
445 bool CheckCertPolicies(X509Certificate::OSCertHandle cert_handle,
446 SECOidTag ev_policy_tag) {
447 SECItem policy_ext;
448 SECStatus rv = CERT_FindCertExtension(
449 cert_handle, SEC_OID_X509_CERTIFICATE_POLICIES, &policy_ext);
450 if (rv != SECSuccess) {
451 LOG(ERROR) << "Cert has no policies extension.";
452 return false;
453 }
454 CERTCertificatePolicies* policies =
alv 2009/08/08 00:47:15 Does this function leak policies?
455 CERT_DecodeCertificatePoliciesExtension(&policy_ext);
456 if (!policies) {
457 LOG(ERROR) << "Failed to decode certificate policy.";
458 return false;
459 }
460 CERTPolicyInfo** policy_infos = policies->policyInfos;
461 while (*policy_infos != NULL) {
462 CERTPolicyInfo* policy_info = *policy_infos++;
463 SECOidTag oid_tag = SECOID_FindOIDTag(&policy_info->policyID);
wtc 2009/08/07 04:01:20 Does it work to just use policy_info->oid? Mozill
alv 2009/08/08 00:47:15 You right. Decoder for cert policy extension has a
464 if (oid_tag == SEC_OID_UNKNOWN)
465 continue;
466 if (oid_tag == ev_policy_tag)
467 return true;
468 }
469 LOG(ERROR) << "No EV Policy Tag";
470 return false;
471 }
472
473 } // namespace
324 474
325 void X509Certificate::Initialize() { 475 void X509Certificate::Initialize() {
326 ParsePrincipal(&cert_handle_->derSubject, &subject_); 476 ParsePrincipal(&cert_handle_->derSubject, &subject_);
327 ParsePrincipal(&cert_handle_->derIssuer, &issuer_); 477 ParsePrincipal(&cert_handle_->derIssuer, &issuer_);
328 478
329 ParseDate(&cert_handle_->validity.notBefore, &valid_start_); 479 ParseDate(&cert_handle_->validity.notBefore, &valid_start_);
330 ParseDate(&cert_handle_->validity.notAfter, &valid_expiry_); 480 ParseDate(&cert_handle_->validity.notAfter, &valid_expiry_);
331 481
332 fingerprint_ = CalculateFingerprint(cert_handle_); 482 fingerprint_ = CalculateFingerprint(cert_handle_);
333 483
(...skipping 24 matching lines...) Expand all
358 GetCertSubjectAltNamesOfType(cert_handle_, certDNSName, dns_names); 508 GetCertSubjectAltNamesOfType(cert_handle_, certDNSName, dns_names);
359 509
360 // TODO(port): suppress nss's support of the obsolete extension 510 // TODO(port): suppress nss's support of the obsolete extension
361 // SEC_OID_NS_CERT_EXT_SSL_SERVER_NAME 511 // SEC_OID_NS_CERT_EXT_SSL_SERVER_NAME
362 // by providing our own authCertificate callback. 512 // by providing our own authCertificate callback.
363 513
364 if (dns_names->empty()) 514 if (dns_names->empty())
365 dns_names->push_back(subject_.common_name); 515 dns_names->push_back(subject_.common_name);
366 } 516 }
367 517
368 // TODO(ukai): fix to use this method to verify certificate on SSL channel.
369 // Note that it's not being used yet. We need to fix SSLClientSocketNSS to
370 // use this method to verify ssl certificate.
371 // The problem is that we get segfault when unit tests is going to terminate
372 // if PR_Cleanup is called in NSSInitSingleton destructor.
373 int X509Certificate::Verify(const std::string& hostname, 518 int X509Certificate::Verify(const std::string& hostname,
374 int flags, 519 int flags,
375 CertVerifyResult* verify_result) const { 520 CertVerifyResult* verify_result) const {
376 verify_result->Reset(); 521 verify_result->Reset();
377 522
378 // Make sure that the hostname matches with the common name of the cert. 523 // Make sure that the hostname matches with the common name of the cert.
379 SECStatus status = CERT_VerifyCertName(cert_handle_, hostname.c_str()); 524 SECStatus status = CERT_VerifyCertName(cert_handle_, hostname.c_str());
380 if (status != SECSuccess) 525 if (status != SECSuccess)
381 verify_result->cert_status |= CERT_STATUS_COMMON_NAME_INVALID; 526 verify_result->cert_status |= CERT_STATUS_COMMON_NAME_INVALID;
382 527
383 // Make sure that the cert is valid now. 528 // Make sure that the cert is valid now.
384 SECCertTimeValidity validity = CERT_CheckCertValidTimes( 529 SECCertTimeValidity validity = CERT_CheckCertValidTimes(
385 cert_handle_, PR_Now(), PR_TRUE); 530 cert_handle_, PR_Now(), PR_TRUE);
386 if (validity != secCertTimeValid) 531 if (validity != secCertTimeValid)
387 verify_result->cert_status |= CERT_STATUS_DATE_INVALID; 532 verify_result->cert_status |= CERT_STATUS_DATE_INVALID;
388 533
389 CERTRevocationFlags revocation_flags;
390 // TODO(ukai): Fix to use OCSP.
391 // OCSP mode would fail with SEC_ERROR_UNKNOWN_ISSUER.
392 // We need to set up OCSP and install an HTTP client for NSS.
393 bool use_ocsp = false;
394 // EV requires revocation checking.
395 if (!(flags & VERIFY_REV_CHECKING_ENABLED))
396 flags &= ~VERIFY_EV_CERT;
397
398 // TODO(wtc): Use CERT_REV_M_REQUIRE_INFO_ON_MISSING_SOURCE and
399 // CERT_REV_MI_REQUIRE_SOME_FRESH_INFO_AVAILABLE for EV certificate
400 // verification.
401 PRUint64 revocation_method_flags =
402 CERT_REV_M_TEST_USING_THIS_METHOD |
403 CERT_REV_M_ALLOW_NETWORK_FETCHING |
404 CERT_REV_M_ALLOW_IMPLICIT_DEFAULT_SOURCE |
405 CERT_REV_M_SKIP_TEST_ON_MISSING_SOURCE |
406 CERT_REV_M_STOP_TESTING_ON_FRESH_INFO;
407 PRUint64 revocation_method_independent_flags =
408 CERT_REV_MI_TEST_ALL_LOCAL_INFORMATION_FIRST |
409 CERT_REV_MI_NO_OVERALL_INFO_REQUIREMENT;
410 PRUint64 method_flags[2];
411 method_flags[cert_revocation_method_crl] = revocation_method_flags;
412 method_flags[cert_revocation_method_ocsp] = revocation_method_flags;
413
414 int number_of_defined_methods;
415 CERTRevocationMethodIndex preferred_revocation_methods[1];
416 if (use_ocsp) {
417 number_of_defined_methods = 2;
418 preferred_revocation_methods[0] = cert_revocation_method_ocsp;
419 } else {
420 number_of_defined_methods = 1;
421 preferred_revocation_methods[0] = cert_revocation_method_crl;
422 }
423
424 revocation_flags.leafTests.number_of_defined_methods =
425 number_of_defined_methods;
426 revocation_flags.leafTests.cert_rev_flags_per_method = method_flags;
427 revocation_flags.leafTests.number_of_preferred_methods =
428 arraysize(preferred_revocation_methods);
429 revocation_flags.leafTests.preferred_methods = preferred_revocation_methods;
430 revocation_flags.leafTests.cert_rev_method_independent_flags =
431 revocation_method_independent_flags;
432 revocation_flags.chainTests.number_of_defined_methods =
433 number_of_defined_methods;
434 revocation_flags.chainTests.cert_rev_flags_per_method = method_flags;
435 revocation_flags.chainTests.number_of_preferred_methods =
436 arraysize(preferred_revocation_methods);
437 revocation_flags.chainTests.preferred_methods = preferred_revocation_methods;
438 revocation_flags.chainTests.cert_rev_method_independent_flags =
439 revocation_method_independent_flags;
440
441 CERTValInParam cvin[2];
442 int cvin_index = 0;
443 // We can't use PK11_ListCerts(PK11CertListCA, NULL) for cert_pi_trustAnchors.
444 // We get SEC_ERROR_UNTRUSTED_ISSUER (-8172) for our test root CA cert with
445 // it by NSS 3.12.0.3.
446 // No need to set cert_pi_trustAnchors here.
447 // TODO(ukai): use cert_pi_useAIACertFetch (new feature in NSS 3.12.1).
448 cvin[cvin_index].type = cert_pi_revocationFlags;
449 cvin[cvin_index].value.pointer.revocation = &revocation_flags;
450 cvin_index++;
451 cvin[cvin_index].type = cert_pi_end;
452
453 CERTValOutParam cvout[3]; 534 CERTValOutParam cvout[3];
454 int cvout_index = 0; 535 int cvout_index = 0;
455 cvout[cvout_index].type = cert_po_trustAnchor; 536 // We don't need the trust anchor for the first PKIXVerifyCert call.
456 cvout[cvout_index].value.pointer.cert = NULL;
457 cvout_index++;
458 cvout[cvout_index].type = cert_po_certList; 537 cvout[cvout_index].type = cert_po_certList;
459 cvout[cvout_index].value.pointer.chain = NULL; 538 cvout[cvout_index].value.pointer.chain = NULL;
460 int cvout_cert_list_index = cvout_index; 539 int cvout_cert_list_index = cvout_index;
461 cvout_index++; 540 cvout_index++;
462 cvout[cvout_index].type = cert_po_end; 541 cvout[cvout_index].type = cert_po_end;
463 ScopedCERTValOutParam scoped_cvout(cvout); 542 ScopedCERTValOutParam scoped_cvout(cvout);
464 543
465 status = CERT_PKIXVerifyCert(cert_handle_, certificateUsageSSLServer, 544 verify_result->cert_status |= net::CERT_STATUS_REV_CHECKING_ENABLED;
466 cvin, cvout, NULL); 545 status = PKIXVerifyCert(cert_handle_, NULL, 0, cvout);
467 if (status != SECSuccess) { 546 if (status != SECSuccess) {
468 int err = PORT_GetError(); 547 int err = PORT_GetError();
469 LOG(ERROR) << "CERT_PKIXVerifyCert failed err=" << err; 548 LOG(ERROR) << "CERT_PKIXVerifyCert failed err=" << err;
470 // CERT_PKIXVerifyCert rerports the wrong error code for 549 // CERT_PKIXVerifyCert rerports the wrong error code for
471 // expired certificates (NSS bug 491174) 550 // expired certificates (NSS bug 491174)
472 if (err == SEC_ERROR_CERT_NOT_VALID && 551 if (err == SEC_ERROR_CERT_NOT_VALID &&
473 (verify_result->cert_status & CERT_STATUS_DATE_INVALID) != 0) 552 (verify_result->cert_status & CERT_STATUS_DATE_INVALID) != 0)
474 err = SEC_ERROR_EXPIRED_CERTIFICATE; 553 err = SEC_ERROR_EXPIRED_CERTIFICATE;
475 verify_result->cert_status |= MapCertErrorToCertStatus(err); 554 verify_result->cert_status |= MapCertErrorToCertStatus(err);
476 return MapCertStatusToNetError(verify_result->cert_status); 555 return MapCertStatusToNetError(verify_result->cert_status);
477 } 556 }
478 557
479 GetCertChainInfo(cvout[cvout_cert_list_index].value.pointer.chain, 558 GetCertChainInfo(cvout[cvout_cert_list_index].value.pointer.chain,
480 verify_result); 559 verify_result);
481 if (IsCertStatusError(verify_result->cert_status)) 560 if (IsCertStatusError(verify_result->cert_status))
482 return MapCertStatusToNetError(verify_result->cert_status); 561 return MapCertStatusToNetError(verify_result->cert_status);
483 if ((flags & VERIFY_EV_CERT) && VerifyEV()) 562
484 verify_result->cert_status |= CERT_STATUS_IS_EV; 563 if (flags & VERIFY_EV_CERT) {
wtc 2009/08/07 04:01:20 Nit: use the original form: if ((flags & VERIFY
564 if (VerifyEV())
565 verify_result->cert_status |= CERT_STATUS_IS_EV;
566 }
485 return OK; 567 return OK;
486 } 568 }
487 569
488 // TODO(port): Implement properly on Linux. 570 // Studied Mozilla's code (esp. security/manager/ssl/src/nsNSSCertHelper.cpp)
wtc 2009/08/07 04:01:20 Isn't nsIdentityChecking.cpp the most useful file
571 // to learn how to verify EV certificate.
572 // TODO(wtc): We may be able to request cert_po_policyOID and just
573 // check if any of the returned policies is the EV policy of the trust anchor.
574 // Another possible optimization is that we get the trust anchor from
575 // the first PKIXVerifyCert call. We look up the EV policy for the trust
576 // anchor. If the trust anchor has no EV policy, we know the cert isn't EV.
577 // Otherwise, we pass just that EV policy (as opposed to all the EV policies)
578 // to the second PKIXVerifyCert call.
alv 2009/08/08 00:47:15 The first option does not seem to be a working sol
wtc 2009/08/13 00:22:06 Alexei, you may have misunderstood me. What I mea
489 bool X509Certificate::VerifyEV() const { 579 bool X509Certificate::VerifyEV() const {
490 NOTIMPLEMENTED(); 580 net::EVRootCAMetadata* metadata = net::EVRootCAMetadata::GetInstance();
491 return false; 581
582 CERTValOutParam cvout[3];
583 int cvout_index = 0;
584 cvout[cvout_index].type = cert_po_trustAnchor;
585 cvout[cvout_index].value.pointer.cert = NULL;
586 int cvout_trust_anchor_index = cvout_index;
587 cvout_index++;
588 cvout[cvout_index].type = cert_po_end;
589 ScopedCERTValOutParam scoped_cvout(cvout);
590
591 std::vector<SECOidTag> policies;
592 GetPolicyOidTags(metadata, &policies);
593 SECStatus status = PKIXVerifyCert(cert_handle_,
594 &policies[0], policies.size(), cvout);
595 if (status != SECSuccess)
596 return false;
597
598 CERTCertificate* root_ca =
599 cvout[cvout_trust_anchor_index].value.pointer.cert;
600 if (root_ca == NULL)
601 return false;
602 X509Certificate::Fingerprint fingerprint =
603 X509Certificate::CalculateFingerprint(root_ca);
604 SECOidTag ev_policy_tag;
605 if (!GetEvPolicyOidTag(metadata, fingerprint, &ev_policy_tag))
606 return false;
607
608 if (!CheckCertPolicies(cert_handle_, ev_policy_tag))
609 return false;
610
611 return true;
492 } 612 }
493 613
494 // static 614 // static
495 X509Certificate::OSCertHandle X509Certificate::CreateOSCertHandleFromBytes( 615 X509Certificate::OSCertHandle X509Certificate::CreateOSCertHandleFromBytes(
496 const char* data, int length) { 616 const char* data, int length) {
497 base::EnsureNSSInit(); 617 base::EnsureNSSInit();
498 618
499 SECItem der_cert; 619 SECItem der_cert;
500 der_cert.data = reinterpret_cast<unsigned char*>(const_cast<char*>(data)); 620 der_cert.data = reinterpret_cast<unsigned char*>(const_cast<char*>(data));
501 der_cert.len = length; 621 der_cert.len = length;
(...skipping 16 matching lines...) Expand all
518 DCHECK(0 != cert->derCert.len); 638 DCHECK(0 != cert->derCert.len);
519 639
520 SECStatus rv = HASH_HashBuf(HASH_AlgSHA1, sha1.data, 640 SECStatus rv = HASH_HashBuf(HASH_AlgSHA1, sha1.data,
521 cert->derCert.data, cert->derCert.len); 641 cert->derCert.data, cert->derCert.len);
522 DCHECK(rv == SECSuccess); 642 DCHECK(rv == SECSuccess);
523 643
524 return sha1; 644 return sha1;
525 } 645 }
526 646
527 } // namespace net 647 } // namespace net
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698