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

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

Issue 8342054: net: enable CRL sets behind a command line flag. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: ... Created 9 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 | Annotate | Revision Log
OLDNEW
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 <nss.h> 9 #include <nss.h>
10 #include <pk11pub.h> 10 #include <pk11pub.h>
11 #include <prerror.h> 11 #include <prerror.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 #include <sslerr.h> 16 #include <sslerr.h>
17 17
18 #include "base/logging.h" 18 #include "base/logging.h"
19 #include "base/memory/scoped_ptr.h" 19 #include "base/memory/scoped_ptr.h"
20 #include "base/pickle.h" 20 #include "base/pickle.h"
21 #include "base/time.h" 21 #include "base/time.h"
22 #include "crypto/nss_util.h" 22 #include "crypto/nss_util.h"
23 #include "crypto/rsa_private_key.h" 23 #include "crypto/rsa_private_key.h"
24 #include "net/base/asn1_util.h"
24 #include "net/base/cert_status_flags.h" 25 #include "net/base/cert_status_flags.h"
25 #include "net/base/cert_verify_result.h" 26 #include "net/base/cert_verify_result.h"
27 #include "net/base/crl_set.h"
26 #include "net/base/ev_root_ca_metadata.h" 28 #include "net/base/ev_root_ca_metadata.h"
27 #include "net/base/net_errors.h" 29 #include "net/base/net_errors.h"
28 #include "net/base/x509_util_nss.h" 30 #include "net/base/x509_util_nss.h"
29 31
30 namespace net { 32 namespace net {
31 33
32 namespace { 34 namespace {
33 35
34 class ScopedCERTCertificatePolicies { 36 class ScopedCERTCertificatePolicies {
35 public: 37 public:
(...skipping 185 matching lines...) Expand 10 before | Expand all | Expand 10 after
221 bool IsKnownRoot(CERTCertificate* root) { 223 bool IsKnownRoot(CERTCertificate* root) {
222 if (!root->slot) 224 if (!root->slot)
223 return false; 225 return false;
224 226
225 // This magic name is taken from 227 // This magic name is taken from
226 // http://bonsai.mozilla.org/cvsblame.cgi?file=mozilla/security/nss/lib/ckfw/b uiltins/constants.c&rev=1.13&mark=86,89#79 228 // http://bonsai.mozilla.org/cvsblame.cgi?file=mozilla/security/nss/lib/ckfw/b uiltins/constants.c&rev=1.13&mark=86,89#79
227 return 0 == strcmp(PK11_GetSlotName(root->slot), 229 return 0 == strcmp(PK11_GetSlotName(root->slot),
228 "NSS Builtin Objects"); 230 "NSS Builtin Objects");
229 } 231 }
230 232
233 enum CRLSetResult {
234 kCRLSetRevoked,
235 kCRLSetOk,
236 kCRLSetError,
237 };
238
239 // CheckRevocationWithCRLSet attempts to check each element of |cert_list|
240 // against |crl_set|. It returns:
241 // kCRLSetRevoked: if any element of the chain is known to have been revoked.
242 // kCRLSetError: if an error occurs in processing.
243 // kCRLSetOk: if no element in the chain is known to have been revoked.
244 CRLSetResult CheckRevocationWithCRLSet(CERTCertList* cert_list,
245 CERTCertificate* root,
246 CRLSet* crl_set) {
247 std::vector<CERTCertificate*> certs;
248 for (CERTCertListNode* node = CERT_LIST_HEAD(cert_list);
249 !CERT_LIST_END(node, cert_list);
250 node = CERT_LIST_NEXT(node)) {
251 certs.push_back(node->cert);
252 }
253 certs.push_back(root);
254
255 CERTCertificate* last = NULL;
wtc 2011/10/21 23:17:31 Nit: |prev| would be better because |last| may als
agl 2011/10/24 20:44:27 Done.
256 for (std::vector<CERTCertificate*>::iterator i = certs.begin();
257 i != certs.end(); i++) {
wtc 2011/10/21 23:17:31 Nit: ++i
agl 2011/10/24 20:44:27 Done.
258 CERTCertificate* cert = *i;
259 CERTCertificate* child = last;
260 last = cert;
261 if (child == NULL)
262 continue;
263
264 base::StringPiece der(reinterpret_cast<char*>(cert->derCert.data),
265 cert->derCert.len);
266
267 base::StringPiece spki;
268 if (!asn1::ExtractSPKIFromDERCert(der, &spki)) {
269 NOTREACHED();
270 return kCRLSetError;
271 }
272
273 std::string serial_number(
274 reinterpret_cast<char*>(child->serialNumber.data),
275 child->serialNumber.len);
276 // Remove leading zeros.
277 while (serial_number.size() > 1 && serial_number[0] == 0)
278 serial_number = serial_number.substr(1, serial_number.size() - 1);
wtc 2011/10/21 23:17:31 I'm sorry that I'm bringing this up again. We sho
agl 2011/10/24 20:44:27 This has been addressed in http://codereview.chrom
279
280 CRLSet::Result result = crl_set->CheckCertificate(serial_number, spki);
281
282 switch (result) {
283 case CRLSet::REVOKED:
284 return kCRLSetRevoked;
285 case CRLSet::UNKNOWN:
wtc 2011/10/21 23:17:31 IMPORTANT: are you sure we should ignore CRLSet::U
agl 2011/10/24 20:44:27 Yes. The intended semantics are that, unless a ser
286 case CRLSet::GOOD:
287 continue;
288 default:
289 NOTREACHED();
wtc 2011/10/21 23:17:31 BUG (corner case): We should return kCRLSetError i
agl 2011/10/24 20:44:27 Done.
290 }
291 }
292
293 return kCRLSetOk;
294 }
295
231 void ParsePrincipal(CERTName* name, 296 void ParsePrincipal(CERTName* name,
232 CertPrincipal* principal) { 297 CertPrincipal* principal) {
233 typedef char* (*CERTGetNameFunc)(CERTName* name); 298 typedef char* (*CERTGetNameFunc)(CERTName* name);
234 299
235 // TODO(jcampan): add business_category and serial_number. 300 // TODO(jcampan): add business_category and serial_number.
236 // TODO(wtc): NSS has the CERT_GetOrgName, CERT_GetOrgUnitName, and 301 // TODO(wtc): NSS has the CERT_GetOrgName, CERT_GetOrgUnitName, and
237 // CERT_GetDomainComponentName functions, but they return only the most 302 // CERT_GetDomainComponentName functions, but they return only the most
238 // general (the first) RDN. NSS doesn't have a function for the street 303 // general (the first) RDN. NSS doesn't have a function for the street
239 // address. 304 // address.
240 static const SECOidTag kOIDs[] = { 305 static const SECOidTag kOIDs[] = {
(...skipping 441 matching lines...) Expand 10 before | Expand all | Expand 10 after
682 } 747 }
683 name = CERT_GetNextGeneralName(name); 748 name = CERT_GetNextGeneralName(name);
684 if (name == alt_name_list) 749 if (name == alt_name_list)
685 break; 750 break;
686 } 751 }
687 PORT_FreeArena(arena, PR_FALSE); 752 PORT_FreeArena(arena, PR_FALSE);
688 } 753 }
689 754
690 int X509Certificate::VerifyInternal(const std::string& hostname, 755 int X509Certificate::VerifyInternal(const std::string& hostname,
691 int flags, 756 int flags,
692 CertVerifyResult* verify_result) const { 757 CertVerifyResult* verify_result,
758 CRLSet* crl_set) const {
693 // Make sure that the hostname matches with the common name of the cert. 759 // Make sure that the hostname matches with the common name of the cert.
694 SECStatus status = CERT_VerifyCertName(cert_handle_, hostname.c_str()); 760 SECStatus status = CERT_VerifyCertName(cert_handle_, hostname.c_str());
695 if (status != SECSuccess) 761 if (status != SECSuccess)
696 verify_result->cert_status |= CERT_STATUS_COMMON_NAME_INVALID; 762 verify_result->cert_status |= CERT_STATUS_COMMON_NAME_INVALID;
697 763
698 // Make sure that the cert is valid now. 764 // Make sure that the cert is valid now.
699 SECCertTimeValidity validity = CERT_CheckCertValidTimes( 765 SECCertTimeValidity validity = CERT_CheckCertValidTimes(
700 cert_handle_, PR_Now(), PR_TRUE); 766 cert_handle_, PR_Now(), PR_TRUE);
701 if (validity != secCertTimeValid) 767 if (validity != secCertTimeValid)
702 verify_result->cert_status |= CERT_STATUS_DATE_INVALID; 768 verify_result->cert_status |= CERT_STATUS_DATE_INVALID;
(...skipping 11 matching lines...) Expand all
714 cvout[cvout_index].type = cert_po_end; 780 cvout[cvout_index].type = cert_po_end;
715 ScopedCERTValOutParam scoped_cvout(cvout); 781 ScopedCERTValOutParam scoped_cvout(cvout);
716 782
717 bool check_revocation = (flags & VERIFY_REV_CHECKING_ENABLED); 783 bool check_revocation = (flags & VERIFY_REV_CHECKING_ENABLED);
718 if (check_revocation) { 784 if (check_revocation) {
719 verify_result->cert_status |= CERT_STATUS_REV_CHECKING_ENABLED; 785 verify_result->cert_status |= CERT_STATUS_REV_CHECKING_ENABLED;
720 } else { 786 } else {
721 // EV requires revocation checking. 787 // EV requires revocation checking.
722 flags &= ~VERIFY_EV_CERT; 788 flags &= ~VERIFY_EV_CERT;
723 } 789 }
724 status = PKIXVerifyCert(cert_handle_, check_revocation, NULL, 0, cvout); 790
791 status = SECSuccess;
wtc 2011/10/21 23:17:31 This assignment is not necessary.
agl 2011/10/24 20:44:27 Done.
792 if (check_revocation && crl_set) {
793 // We have a CRLSet so we build a chain without revocation checking in
794 // order to try and check it ourselves.
795 status = PKIXVerifyCert(cert_handle_, false /* no revocation checking */,
796 NULL, 0, cvout);
797 if (status == SECSuccess) {
798 CRLSetResult crl_set_result = CheckRevocationWithCRLSet(
799 cvout[cvout_cert_list_index].value.pointer.chain,
800 cvout[cvout_trust_anchor_index].value.pointer.cert,
801 crl_set);
802 if (crl_set_result == kCRLSetError) {
803 // An error occured during processing so we fall back to standard
804 // revocation checking.
805 status = PKIXVerifyCert(cert_handle_, check_revocation, NULL, 0, cvout);
806 } else {
807 DCHECK(crl_set_result == kCRLSetRevoked || crl_set_result == kCRLSetOk);
808 verify_result->cert_status |= CERT_STATUS_USED_CRL_SET;
809 if (crl_set_result == kCRLSetRevoked)
810 verify_result->cert_status |= CERT_STATUS_REVOKED;
wtc 2011/10/21 23:17:31 BUG: we need to set |status| to SECFailure and set
agl 2011/10/24 20:44:27 Ah, yes. Thank you. Done.
811 }
812 }
813 } else {
814 status = PKIXVerifyCert(cert_handle_, check_revocation,
815 NULL, 0, cvout);
816 }
817
725 if (status != SECSuccess) { 818 if (status != SECSuccess) {
726 int err = PORT_GetError(); 819 int err = PORT_GetError();
727 LOG(ERROR) << "CERT_PKIXVerifyCert for " << hostname 820 LOG(ERROR) << "CERT_PKIXVerifyCert for " << hostname
728 << " failed err=" << err; 821 << " failed err=" << err;
729 // CERT_PKIXVerifyCert rerports the wrong error code for 822 // CERT_PKIXVerifyCert rerports the wrong error code for
730 // expired certificates (NSS bug 491174) 823 // expired certificates (NSS bug 491174)
731 if (err == SEC_ERROR_CERT_NOT_VALID && 824 if (err == SEC_ERROR_CERT_NOT_VALID &&
732 (verify_result->cert_status & CERT_STATUS_DATE_INVALID)) 825 (verify_result->cert_status & CERT_STATUS_DATE_INVALID))
733 err = SEC_ERROR_EXPIRED_CERTIFICATE; 826 err = SEC_ERROR_EXPIRED_CERTIFICATE;
734 CertStatus cert_status = MapCertErrorToCertStatus(err); 827 CertStatus cert_status = MapCertErrorToCertStatus(err);
(...skipping 191 matching lines...) Expand 10 before | Expand all | Expand 10 after
926 1019
927 // static 1020 // static
928 bool X509Certificate::WriteOSCertHandleToPickle(OSCertHandle cert_handle, 1021 bool X509Certificate::WriteOSCertHandleToPickle(OSCertHandle cert_handle,
929 Pickle* pickle) { 1022 Pickle* pickle) {
930 return pickle->WriteData( 1023 return pickle->WriteData(
931 reinterpret_cast<const char*>(cert_handle->derCert.data), 1024 reinterpret_cast<const char*>(cert_handle->derCert.data),
932 cert_handle->derCert.len); 1025 cert_handle->derCert.len);
933 } 1026 }
934 1027
935 } // namespace net 1028 } // namespace net
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698