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

Side by Side Diff: mozilla/security/nss/lib/certhigh/certvfy.c

Issue 14249009: Change the NSS and NSPR source tree to the new directory structure to be (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/deps/third_party/nss/
Patch Set: Created 7 years, 8 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
(Empty)
1 /* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4 #include "nspr.h"
5 #include "secerr.h"
6 #include "secport.h"
7 #include "seccomon.h"
8 #include "secoid.h"
9 #include "sslerr.h"
10 #include "genname.h"
11 #include "keyhi.h"
12 #include "cert.h"
13 #include "certdb.h"
14 #include "certi.h"
15 #include "cryptohi.h"
16 #ifndef NSS_DISABLE_LIBPKIX
17 #include "pkix.h"
18 /*#include "pkix_sample_modules.h" */
19 #include "pkix_pl_cert.h"
20 #endif /* NSS_DISABLE_LIBPKIX */
21
22
23 #include "nsspki.h"
24 #include "pkitm.h"
25 #include "pkim.h"
26 #include "pki3hack.h"
27 #include "base.h"
28
29 #ifdef NSS_DISABLE_LIBPKIX
30 SECStatus
31 cert_VerifyCertChainPkix(
32 CERTCertificate *cert,
33 PRBool checkSig,
34 SECCertUsage requiredUsage,
35 PRTime time,
36 void *wincx,
37 CERTVerifyLog *log,
38 PRBool *pSigerror,
39 PRBool *pRevoked)
40 {
41 PORT_SetError(PR_NOT_IMPLEMENTED_ERROR);
42 return SECFailure;
43 }
44
45 SECStatus
46 CERT_SetUsePKIXForValidation(PRBool enable)
47 {
48 PORT_SetError(PR_NOT_IMPLEMENTED_ERROR);
49 return SECFailure;
50 }
51
52 PRBool
53 CERT_GetUsePKIXForValidation()
54 {
55 return PR_FALSE;
56 }
57
58 SECStatus CERT_PKIXVerifyCert(
59 CERTCertificate *cert,
60 SECCertificateUsage usages,
61 CERTValInParam *paramsIn,
62 CERTValOutParam *paramsOut,
63 void *wincx)
64 {
65 PORT_SetError(PR_NOT_IMPLEMENTED_ERROR);
66 return SECFailure;
67 }
68 #endif /* NSS_DISABLE_LIBPKIX */
69
70 /*
71 * Check the validity times of a certificate
72 */
73 SECStatus
74 CERT_CertTimesValid(CERTCertificate *c)
75 {
76 SECCertTimeValidity valid = CERT_CheckCertValidTimes(c, PR_Now(), PR_TRUE);
77 return (valid == secCertTimeValid) ? SECSuccess : SECFailure;
78 }
79
80 /*
81 * verify the signature of a signed data object with the given DER publickey
82 */
83 SECStatus
84 CERT_VerifySignedDataWithPublicKey(CERTSignedData *sd,
85 SECKEYPublicKey *pubKey,
86 void *wincx)
87 {
88 SECStatus rv;
89 SECItem sig;
90 SECOidTag hashAlg = SEC_OID_UNKNOWN;
91
92 if ( !pubKey || !sd ) {
93 PORT_SetError(PR_INVALID_ARGUMENT_ERROR);
94 return SECFailure;
95 }
96
97 /* check the signature */
98 sig = sd->signature;
99 /* convert sig->len from bit counts to byte count. */
100 DER_ConvertBitString(&sig);
101
102 rv = VFY_VerifyDataWithAlgorithmID(sd->data.data, sd->data.len, pubKey,
103 &sig, &sd->signatureAlgorithm, &hashAlg, wincx);
104 if (rv == SECSuccess) {
105 /* Are we honoring signatures for this algorithm? */
106 PRUint32 policyFlags = 0;
107 rv = NSS_GetAlgorithmPolicy(hashAlg, &policyFlags);
108 if (rv == SECSuccess &&
109 !(policyFlags & NSS_USE_ALG_IN_CERT_SIGNATURE)) {
110 PORT_SetError(SEC_ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED);
111 rv = SECFailure;
112 }
113 }
114 return rv;
115 }
116
117 /*
118 * verify the signature of a signed data object with the given DER publickey
119 */
120 SECStatus
121 CERT_VerifySignedDataWithPublicKeyInfo(CERTSignedData *sd,
122 CERTSubjectPublicKeyInfo *pubKeyInfo,
123 void *wincx)
124 {
125 SECKEYPublicKey *pubKey;
126 SECStatus rv = SECFailure;
127
128 /* get cert's public key */
129 pubKey = SECKEY_ExtractPublicKey(pubKeyInfo);
130 if (pubKey) {
131 rv = CERT_VerifySignedDataWithPublicKey(sd, pubKey, wincx);
132 SECKEY_DestroyPublicKey(pubKey);
133 }
134 return rv;
135 }
136
137 /*
138 * verify the signature of a signed data object with the given certificate
139 */
140 SECStatus
141 CERT_VerifySignedData(CERTSignedData *sd, CERTCertificate *cert,
142 int64 t, void *wincx)
143 {
144 SECKEYPublicKey *pubKey = 0;
145 SECStatus rv = SECFailure;
146 SECCertTimeValidity validity;
147
148 /* check the certificate's validity */
149 validity = CERT_CheckCertValidTimes(cert, t, PR_FALSE);
150 if ( validity != secCertTimeValid ) {
151 return rv;
152 }
153
154 /* get cert's public key */
155 pubKey = CERT_ExtractPublicKey(cert);
156 if (pubKey) {
157 rv = CERT_VerifySignedDataWithPublicKey(sd, pubKey, wincx);
158 SECKEY_DestroyPublicKey(pubKey);
159 }
160 return rv;
161 }
162
163
164 SECStatus
165 SEC_CheckCRL(CERTCertDBHandle *handle,CERTCertificate *cert,
166 CERTCertificate *caCert, int64 t, void * wincx)
167 {
168 return CERT_CheckCRL(cert, caCert, NULL, t, wincx);
169 }
170
171 /*
172 * Find the issuer of a cert. Use the authorityKeyID if it exists.
173 */
174 CERTCertificate *
175 CERT_FindCertIssuer(CERTCertificate *cert, int64 validTime, SECCertUsage usage)
176 {
177 NSSCertificate *me;
178 NSSTime *nssTime;
179 NSSTrustDomain *td;
180 NSSCryptoContext *cc;
181 NSSCertificate *chain[3];
182 NSSUsage nssUsage;
183 PRStatus status;
184
185 me = STAN_GetNSSCertificate(cert);
186 if (!me) {
187 PORT_SetError(SEC_ERROR_NO_MEMORY);
188 return NULL;
189 }
190 nssTime = NSSTime_SetPRTime(NULL, validTime);
191 nssUsage.anyUsage = PR_FALSE;
192 nssUsage.nss3usage = usage;
193 nssUsage.nss3lookingForCA = PR_TRUE;
194 memset(chain, 0, 3*sizeof(NSSCertificate *));
195 td = STAN_GetDefaultTrustDomain();
196 cc = STAN_GetDefaultCryptoContext();
197 (void)NSSCertificate_BuildChain(me, nssTime, &nssUsage, NULL,
198 chain, 2, NULL, &status, td, cc);
199 nss_ZFreeIf(nssTime);
200 if (status == PR_SUCCESS) {
201 PORT_Assert(me == chain[0]);
202 /* if it's a root, the chain will only have one cert */
203 if (!chain[1]) {
204 /* already has a reference from the call to BuildChain */
205 return cert;
206 }
207 NSSCertificate_Destroy(chain[0]); /* the first cert in the chain */
208 return STAN_GetCERTCertificate(chain[1]); /* return the 2nd */
209 }
210 if (chain[0]) {
211 PORT_Assert(me == chain[0]);
212 NSSCertificate_Destroy(chain[0]); /* the first cert in the chain */
213 }
214 PORT_SetError (SEC_ERROR_UNKNOWN_ISSUER);
215 return NULL;
216 }
217
218 /*
219 * return required trust flags for various cert usages for CAs
220 */
221 SECStatus
222 CERT_TrustFlagsForCACertUsage(SECCertUsage usage,
223 unsigned int *retFlags,
224 SECTrustType *retTrustType)
225 {
226 unsigned int requiredFlags;
227 SECTrustType trustType;
228
229 switch ( usage ) {
230 case certUsageSSLClient:
231 requiredFlags = CERTDB_TRUSTED_CLIENT_CA;
232 trustType = trustSSL;
233 break;
234 case certUsageSSLServer:
235 case certUsageSSLCA:
236 requiredFlags = CERTDB_TRUSTED_CA;
237 trustType = trustSSL;
238 break;
239 case certUsageSSLServerWithStepUp:
240 requiredFlags = CERTDB_TRUSTED_CA | CERTDB_GOVT_APPROVED_CA;
241 trustType = trustSSL;
242 break;
243 case certUsageEmailSigner:
244 case certUsageEmailRecipient:
245 requiredFlags = CERTDB_TRUSTED_CA;
246 trustType = trustEmail;
247 break;
248 case certUsageObjectSigner:
249 requiredFlags = CERTDB_TRUSTED_CA;
250 trustType = trustObjectSigning;
251 break;
252 case certUsageVerifyCA:
253 case certUsageAnyCA:
254 case certUsageStatusResponder:
255 requiredFlags = CERTDB_TRUSTED_CA;
256 trustType = trustTypeNone;
257 break;
258 default:
259 PORT_Assert(0);
260 goto loser;
261 }
262 if ( retFlags != NULL ) {
263 *retFlags = requiredFlags;
264 }
265 if ( retTrustType != NULL ) {
266 *retTrustType = trustType;
267 }
268
269 return(SECSuccess);
270 loser:
271 return(SECFailure);
272 }
273
274 void
275 cert_AddToVerifyLog(CERTVerifyLog *log, CERTCertificate *cert, long error,
276 unsigned int depth, void *arg)
277 {
278 CERTVerifyLogNode *node, *tnode;
279
280 PORT_Assert(log != NULL);
281
282 node = (CERTVerifyLogNode *)PORT_ArenaAlloc(log->arena,
283 sizeof(CERTVerifyLogNode));
284 if ( node != NULL ) {
285 node->cert = CERT_DupCertificate(cert);
286 node->error = error;
287 node->depth = depth;
288 node->arg = arg;
289
290 if ( log->tail == NULL ) {
291 /* empty list */
292 log->head = log->tail = node;
293 node->prev = NULL;
294 node->next = NULL;
295 } else if ( depth >= log->tail->depth ) {
296 /* add to tail */
297 node->prev = log->tail;
298 log->tail->next = node;
299 log->tail = node;
300 node->next = NULL;
301 } else if ( depth < log->head->depth ) {
302 /* add at head */
303 node->prev = NULL;
304 node->next = log->head;
305 log->head->prev = node;
306 log->head = node;
307 } else {
308 /* add in middle */
309 tnode = log->tail;
310 while ( tnode != NULL ) {
311 if ( depth >= tnode->depth ) {
312 /* insert after tnode */
313 node->prev = tnode;
314 node->next = tnode->next;
315 tnode->next->prev = node;
316 tnode->next = node;
317 break;
318 }
319
320 tnode = tnode->prev;
321 }
322 }
323
324 log->count++;
325 }
326 return;
327 }
328
329 #define EXIT_IF_NOT_LOGGING(log) \
330 if ( log == NULL ) { \
331 goto loser; \
332 }
333
334 #define LOG_ERROR_OR_EXIT(log,cert,depth,arg) \
335 if ( log != NULL ) { \
336 cert_AddToVerifyLog(log, cert, PORT_GetError(), depth, \
337 (void *)(PRWord)arg); \
338 } else { \
339 goto loser; \
340 }
341
342 #define LOG_ERROR(log,cert,depth,arg) \
343 if ( log != NULL ) { \
344 cert_AddToVerifyLog(log, cert, PORT_GetError(), depth, \
345 (void *)(PRWord)arg); \
346 }
347
348 static SECStatus
349 cert_VerifyCertChainOld(CERTCertDBHandle *handle, CERTCertificate *cert,
350 PRBool checkSig, PRBool* sigerror,
351 SECCertUsage certUsage, int64 t, void *wincx,
352 CERTVerifyLog *log, PRBool* revoked)
353 {
354 SECTrustType trustType;
355 CERTBasicConstraints basicConstraint;
356 CERTCertificate *issuerCert = NULL;
357 CERTCertificate *subjectCert = NULL;
358 CERTCertificate *badCert = NULL;
359 PRBool isca;
360 SECStatus rv;
361 SECStatus rvFinal = SECSuccess;
362 int count;
363 int currentPathLen = 0;
364 int pathLengthLimit = CERT_UNLIMITED_PATH_CONSTRAINT;
365 unsigned int caCertType;
366 unsigned int requiredCAKeyUsage;
367 unsigned int requiredFlags;
368 PRArenaPool *arena = NULL;
369 CERTGeneralName *namesList = NULL;
370 CERTCertificate **certsList = NULL;
371 int certsListLen = 16;
372 int namesCount = 0;
373 PRBool subjectCertIsSelfIssued;
374 CERTCertTrust issuerTrust;
375
376 if (revoked) {
377 *revoked = PR_FALSE;
378 }
379
380 if (CERT_KeyUsageAndTypeForCertUsage(certUsage, PR_TRUE,
381 &requiredCAKeyUsage,
382 &caCertType)
383 != SECSuccess ) {
384 PORT_Assert(0);
385 EXIT_IF_NOT_LOGGING(log);
386 requiredCAKeyUsage = 0;
387 caCertType = 0;
388 }
389
390 switch ( certUsage ) {
391 case certUsageSSLClient:
392 case certUsageSSLServer:
393 case certUsageSSLCA:
394 case certUsageSSLServerWithStepUp:
395 case certUsageEmailSigner:
396 case certUsageEmailRecipient:
397 case certUsageObjectSigner:
398 case certUsageVerifyCA:
399 case certUsageAnyCA:
400 case certUsageStatusResponder:
401 if ( CERT_TrustFlagsForCACertUsage(certUsage, &requiredFlags,
402 &trustType) != SECSuccess ) {
403 PORT_Assert(0);
404 EXIT_IF_NOT_LOGGING(log);
405 /* XXX continuing with requiredFlags = 0 seems wrong. It'll
406 * cause the following test to be true incorrectly:
407 * flags = SEC_GET_TRUST_FLAGS(issuerCert->trust, trustType);
408 * if (( flags & requiredFlags ) == requiredFlags) {
409 * rv = rvFinal;
410 * goto done;
411 * }
412 * There are three other instances of this problem.
413 */
414 requiredFlags = 0;
415 trustType = trustSSL;
416 }
417 break;
418 default:
419 PORT_Assert(0);
420 EXIT_IF_NOT_LOGGING(log);
421 requiredFlags = 0;
422 trustType = trustSSL;/* This used to be 0, but we need something
423 * that matches the enumeration type.
424 */
425 caCertType = 0;
426 }
427
428 subjectCert = CERT_DupCertificate(cert);
429 if ( subjectCert == NULL ) {
430 goto loser;
431 }
432
433 arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
434 if (arena == NULL) {
435 goto loser;
436 }
437
438 certsList = PORT_ZNewArray(CERTCertificate *, certsListLen);
439 if (certsList == NULL)
440 goto loser;
441
442 /* RFC 3280 says that the name constraints will apply to the names
443 ** in the leaf (EE) cert, whether it is self issued or not, so
444 ** we pretend that it is not.
445 */
446 subjectCertIsSelfIssued = PR_FALSE;
447 for ( count = 0; count < CERT_MAX_CERT_CHAIN; count++ ) {
448 PRBool validCAOverride = PR_FALSE;
449
450 /* Construct a list of names for the current and all previous
451 * certifcates (except leaf (EE) certs, root CAs, and self-issued
452 * intermediate CAs) to be verified against the name constraints
453 * extension of the issuer certificate.
454 */
455 if (subjectCertIsSelfIssued == PR_FALSE) {
456 CERTGeneralName *subjectNameList;
457 int subjectNameListLen;
458 int i;
459 PRBool getSubjectCN = (!count && certUsage == certUsageSSLServer);
460 subjectNameList =
461 CERT_GetConstrainedCertificateNames(subjectCert, arena,
462 getSubjectCN);
463 if (!subjectNameList)
464 goto loser;
465 subjectNameListLen = CERT_GetNamesLength(subjectNameList);
466 if (!subjectNameListLen)
467 goto loser;
468 if (certsListLen <= namesCount + subjectNameListLen) {
469 CERTCertificate **tmpCertsList;
470 certsListLen = (namesCount + subjectNameListLen) * 2;
471 tmpCertsList =
472 (CERTCertificate **)PORT_Realloc(certsList,
473 certsListLen * sizeof(CERTCertificate *));
474 if (tmpCertsList == NULL) {
475 goto loser;
476 }
477 certsList = tmpCertsList;
478 }
479 for (i = 0; i < subjectNameListLen; i++) {
480 certsList[namesCount + i] = subjectCert;
481 }
482 namesCount += subjectNameListLen;
483 namesList = cert_CombineNamesLists(namesList, subjectNameList);
484 }
485
486 /* check if the cert has an unsupported critical extension */
487 if ( subjectCert->options.bits.hasUnsupportedCriticalExt ) {
488 PORT_SetError(SEC_ERROR_UNKNOWN_CRITICAL_EXTENSION);
489 LOG_ERROR_OR_EXIT(log,subjectCert,count,0);
490 }
491
492 /* find the certificate of the issuer */
493 issuerCert = CERT_FindCertIssuer(subjectCert, t, certUsage);
494 if ( ! issuerCert ) {
495 PORT_SetError(SEC_ERROR_UNKNOWN_ISSUER);
496 LOG_ERROR(log,subjectCert,count,0);
497 goto loser;
498 }
499
500 /* verify the signature on the cert */
501 if ( checkSig ) {
502 rv = CERT_VerifySignedData(&subjectCert->signatureWrap,
503 issuerCert, t, wincx);
504
505 if ( rv != SECSuccess ) {
506 if (sigerror) {
507 *sigerror = PR_TRUE;
508 }
509 if ( PORT_GetError() == SEC_ERROR_EXPIRED_CERTIFICATE ) {
510 PORT_SetError(SEC_ERROR_EXPIRED_ISSUER_CERTIFICATE);
511 LOG_ERROR_OR_EXIT(log,issuerCert,count+1,0);
512 } else {
513 if (PORT_GetError() !=
514 SEC_ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED) {
515 PORT_SetError(SEC_ERROR_BAD_SIGNATURE);
516 }
517 LOG_ERROR_OR_EXIT(log,subjectCert,count,0);
518 }
519 }
520 }
521
522 /* If the basicConstraint extension is included in an immediate CA
523 * certificate, make sure that the isCA flag is on. If the
524 * pathLenConstraint component exists, it must be greater than the
525 * number of CA certificates we have seen so far. If the extension
526 * is omitted, we will assume that this is a CA certificate with
527 * an unlimited pathLenConstraint (since it already passes the
528 * netscape-cert-type extension checking).
529 */
530
531 rv = CERT_FindBasicConstraintExten(issuerCert, &basicConstraint);
532 if ( rv != SECSuccess ) {
533 if (PORT_GetError() != SEC_ERROR_EXTENSION_NOT_FOUND) {
534 LOG_ERROR_OR_EXIT(log,issuerCert,count+1,0);
535 }
536 pathLengthLimit = CERT_UNLIMITED_PATH_CONSTRAINT;
537 /* no basic constraints found, we aren't (yet) a CA. */
538 isca = PR_FALSE;
539 } else {
540 if ( basicConstraint.isCA == PR_FALSE ) {
541 PORT_SetError (SEC_ERROR_CA_CERT_INVALID);
542 LOG_ERROR_OR_EXIT(log,issuerCert,count+1,0);
543 }
544 pathLengthLimit = basicConstraint.pathLenConstraint;
545 isca = PR_TRUE;
546 }
547 /* make sure that the path len constraint is properly set.*/
548 if (pathLengthLimit >= 0 && currentPathLen > pathLengthLimit) {
549 PORT_SetError (SEC_ERROR_PATH_LEN_CONSTRAINT_INVALID);
550 LOG_ERROR_OR_EXIT(log, issuerCert, count+1, pathLengthLimit);
551 }
552
553 /* XXX - the error logging may need to go down into CRL stuff at some
554 * point
555 */
556 /* check revoked list (issuer) */
557 rv = SEC_CheckCRL(handle, subjectCert, issuerCert, t, wincx);
558 if (rv == SECFailure) {
559 if (revoked) {
560 *revoked = PR_TRUE;
561 }
562 LOG_ERROR_OR_EXIT(log,subjectCert,count,0);
563 } else if (rv == SECWouldBlock) {
564 /* We found something fishy, so we intend to issue an
565 * error to the user, but the user may wish to continue
566 * processing, in which case we better make sure nothing
567 * worse has happened... so keep cranking the loop */
568 rvFinal = SECFailure;
569 if (revoked) {
570 *revoked = PR_TRUE;
571 }
572 LOG_ERROR(log,subjectCert,count,0);
573 }
574
575 if ( CERT_GetCertTrust(issuerCert, &issuerTrust) == SECSuccess) {
576 /* we have some trust info, but this does NOT imply that this
577 * cert is actually trusted for any purpose. The cert may be
578 * explicitly UNtrusted. We won't know until we examine the
579 * trust bits.
580 */
581 unsigned int flags;
582
583 if (certUsage != certUsageAnyCA &&
584 certUsage != certUsageStatusResponder) {
585
586 /*
587 * XXX This choice of trustType seems arbitrary.
588 */
589 if ( certUsage == certUsageVerifyCA ) {
590 if ( subjectCert->nsCertType & NS_CERT_TYPE_EMAIL_CA ) {
591 trustType = trustEmail;
592 } else if ( subjectCert->nsCertType & NS_CERT_TYPE_SSL_CA ) {
593 trustType = trustSSL;
594 } else {
595 trustType = trustObjectSigning;
596 }
597 }
598
599 flags = SEC_GET_TRUST_FLAGS(&issuerTrust, trustType);
600 if (( flags & requiredFlags ) == requiredFlags) {
601 /* we found a trusted one, so return */
602 rv = rvFinal;
603 goto done;
604 }
605 if (flags & CERTDB_VALID_CA) {
606 validCAOverride = PR_TRUE;
607 }
608 /* is it explicitly distrusted? */
609 if ((flags & CERTDB_TERMINAL_RECORD) &&
610 ((flags & (CERTDB_TRUSTED|CERTDB_TRUSTED_CA)) == 0)) {
611 /* untrusted -- the cert is explicitly untrusted, not
612 * just that it doesn't chain to a trusted cert */
613 PORT_SetError(SEC_ERROR_UNTRUSTED_ISSUER);
614 LOG_ERROR_OR_EXIT(log,issuerCert,count+1,flags);
615 }
616 } else {
617 /* Check if we have any valid trust when cheching for
618 * certUsageAnyCA or certUsageStatusResponder. */
619 for (trustType = trustSSL; trustType < trustTypeNone;
620 trustType++) {
621 flags = SEC_GET_TRUST_FLAGS(&issuerTrust, trustType);
622 if ((flags & requiredFlags) == requiredFlags) {
623 rv = rvFinal;
624 goto done;
625 }
626 if (flags & CERTDB_VALID_CA)
627 validCAOverride = PR_TRUE;
628 }
629 /* We have 2 separate loops because we want any single trust
630 * bit to allow this usage to return trusted. Only if none of
631 * the trust bits are on do we check to see if the cert is
632 * untrusted */
633 for (trustType = trustSSL; trustType < trustTypeNone;
634 trustType++) {
635 flags = SEC_GET_TRUST_FLAGS(&issuerTrust, trustType);
636 /* is it explicitly distrusted? */
637 if ((flags & CERTDB_TERMINAL_RECORD) &&
638 ((flags & (CERTDB_TRUSTED|CERTDB_TRUSTED_CA)) == 0)) {
639 /* untrusted -- the cert is explicitly untrusted, not
640 * just that it doesn't chain to a trusted cert */
641 PORT_SetError(SEC_ERROR_UNTRUSTED_ISSUER);
642 LOG_ERROR_OR_EXIT(log,issuerCert,count+1,flags);
643 }
644 }
645 }
646 }
647
648 if (!validCAOverride) {
649 /*
650 * Make sure that if this is an intermediate CA in the chain that
651 * it was given permission by its signer to be a CA.
652 */
653 /*
654 * if basicConstraints says it is a ca, then we check the
655 * nsCertType. If the nsCertType has any CA bits set, then
656 * it must have the right one.
657 */
658 if (!isca || (issuerCert->nsCertType & NS_CERT_TYPE_CA)) {
659 isca = (issuerCert->nsCertType & caCertType) ? PR_TRUE : PR_FALS E;
660 }
661
662 if ( !isca ) {
663 PORT_SetError(SEC_ERROR_CA_CERT_INVALID);
664 LOG_ERROR_OR_EXIT(log,issuerCert,count+1,0);
665 }
666
667 /* make sure key usage allows cert signing */
668 if (CERT_CheckKeyUsage(issuerCert, requiredCAKeyUsage) != SECSuccess ) {
669 PORT_SetError(SEC_ERROR_INADEQUATE_KEY_USAGE);
670 LOG_ERROR_OR_EXIT(log,issuerCert,count+1,requiredCAKeyUsage);
671 }
672 }
673
674 /* make sure that the entire chain is within the name space of the
675 ** current issuer certificate.
676 */
677 rv = CERT_CompareNameSpace(issuerCert, namesList, certsList,
678 arena, &badCert);
679 if (rv != SECSuccess || badCert != NULL) {
680 PORT_SetError(SEC_ERROR_CERT_NOT_IN_NAME_SPACE);
681 LOG_ERROR_OR_EXIT(log, badCert, count + 1, 0);
682 goto loser;
683 }
684 /* make sure that the issuer is not self signed. If it is, then
685 * stop here to prevent looping.
686 */
687 if (issuerCert->isRoot) {
688 PORT_SetError(SEC_ERROR_UNTRUSTED_ISSUER);
689 LOG_ERROR(log, issuerCert, count+1, 0);
690 goto loser;
691 }
692 /* The issuer cert will be the subject cert in the next loop.
693 * A cert is self-issued if its subject and issuer are equal and
694 * both are of non-zero length.
695 */
696 subjectCertIsSelfIssued = (PRBool)
697 SECITEM_ItemsAreEqual(&issuerCert->derIssuer,
698 &issuerCert->derSubject) &&
699 issuerCert->derSubject.len > 0;
700 if (subjectCertIsSelfIssued == PR_FALSE) {
701 /* RFC 3280 says only non-self-issued intermediate CA certs
702 * count in path length.
703 */
704 ++currentPathLen;
705 }
706
707 CERT_DestroyCertificate(subjectCert);
708 subjectCert = issuerCert;
709 issuerCert = NULL;
710 }
711
712 PORT_SetError(SEC_ERROR_UNKNOWN_ISSUER);
713 LOG_ERROR(log,subjectCert,count,0);
714 loser:
715 rv = SECFailure;
716 done:
717 if (certsList != NULL) {
718 PORT_Free(certsList);
719 }
720 if ( issuerCert ) {
721 CERT_DestroyCertificate(issuerCert);
722 }
723
724 if ( subjectCert ) {
725 CERT_DestroyCertificate(subjectCert);
726 }
727
728 if ( arena != NULL ) {
729 PORT_FreeArena(arena, PR_FALSE);
730 }
731 return rv;
732 }
733
734 SECStatus
735 cert_VerifyCertChain(CERTCertDBHandle *handle, CERTCertificate *cert,
736 PRBool checkSig, PRBool* sigerror,
737 SECCertUsage certUsage, int64 t, void *wincx,
738 CERTVerifyLog *log, PRBool* revoked)
739 {
740 if (CERT_GetUsePKIXForValidation()) {
741 return cert_VerifyCertChainPkix(cert, checkSig, certUsage, t,
742 wincx, log, sigerror, revoked);
743 }
744 return cert_VerifyCertChainOld(handle, cert, checkSig, sigerror,
745 certUsage, t, wincx, log, revoked);
746 }
747
748 SECStatus
749 CERT_VerifyCertChain(CERTCertDBHandle *handle, CERTCertificate *cert,
750 PRBool checkSig, SECCertUsage certUsage, int64 t,
751 void *wincx, CERTVerifyLog *log)
752 {
753 return cert_VerifyCertChain(handle, cert, checkSig, NULL, certUsage, t,
754 wincx, log, NULL);
755 }
756
757 /*
758 * verify that a CA can sign a certificate with the requested usage.
759 */
760 SECStatus
761 CERT_VerifyCACertForUsage(CERTCertDBHandle *handle, CERTCertificate *cert,
762 PRBool checkSig, SECCertUsage certUsage, int64 t,
763 void *wincx, CERTVerifyLog *log)
764 {
765 SECTrustType trustType;
766 CERTBasicConstraints basicConstraint;
767 PRBool isca;
768 PRBool validCAOverride = PR_FALSE;
769 SECStatus rv;
770 SECStatus rvFinal = SECSuccess;
771 unsigned int flags;
772 unsigned int caCertType;
773 unsigned int requiredCAKeyUsage;
774 unsigned int requiredFlags;
775 CERTCertificate *issuerCert;
776 CERTCertTrust certTrust;
777
778
779 if (CERT_KeyUsageAndTypeForCertUsage(certUsage, PR_TRUE,
780 &requiredCAKeyUsage,
781 &caCertType) != SECSuccess ) {
782 PORT_Assert(0);
783 EXIT_IF_NOT_LOGGING(log);
784 requiredCAKeyUsage = 0;
785 caCertType = 0;
786 }
787
788 switch ( certUsage ) {
789 case certUsageSSLClient:
790 case certUsageSSLServer:
791 case certUsageSSLCA:
792 case certUsageSSLServerWithStepUp:
793 case certUsageEmailSigner:
794 case certUsageEmailRecipient:
795 case certUsageObjectSigner:
796 case certUsageVerifyCA:
797 case certUsageStatusResponder:
798 if ( CERT_TrustFlagsForCACertUsage(certUsage, &requiredFlags,
799 &trustType) != SECSuccess ) {
800 PORT_Assert(0);
801 EXIT_IF_NOT_LOGGING(log);
802 requiredFlags = 0;
803 trustType = trustSSL;
804 }
805 break;
806 default:
807 PORT_Assert(0);
808 EXIT_IF_NOT_LOGGING(log);
809 requiredFlags = 0;
810 trustType = trustSSL;/* This used to be 0, but we need something
811 * that matches the enumeration type.
812 */
813 caCertType = 0;
814 }
815
816 /* If the basicConstraint extension is included in an intermmediate CA
817 * certificate, make sure that the isCA flag is on. If the
818 * pathLenConstraint component exists, it must be greater than the
819 * number of CA certificates we have seen so far. If the extension
820 * is omitted, we will assume that this is a CA certificate with
821 * an unlimited pathLenConstraint (since it already passes the
822 * netscape-cert-type extension checking).
823 */
824
825 rv = CERT_FindBasicConstraintExten(cert, &basicConstraint);
826 if ( rv != SECSuccess ) {
827 if (PORT_GetError() != SEC_ERROR_EXTENSION_NOT_FOUND) {
828 LOG_ERROR_OR_EXIT(log,cert,0,0);
829 }
830 /* no basic constraints found, we aren't (yet) a CA. */
831 isca = PR_FALSE;
832 } else {
833 if ( basicConstraint.isCA == PR_FALSE ) {
834 PORT_SetError (SEC_ERROR_CA_CERT_INVALID);
835 LOG_ERROR_OR_EXIT(log,cert,0,0);
836 }
837
838 /* can't check path length if we don't know the previous path */
839 isca = PR_TRUE;
840 }
841
842 if ( CERT_GetCertTrust(cert, &certTrust) == SECSuccess ) {
843 /* we have some trust info, but this does NOT imply that this
844 * cert is actually trusted for any purpose. The cert may be
845 * explicitly UNtrusted. We won't know until we examine the
846 * trust bits.
847 */
848 if (certUsage == certUsageStatusResponder) {
849 /* Check the special case of certUsageStatusResponder */
850 issuerCert = CERT_FindCertIssuer(cert, t, certUsage);
851 if (issuerCert) {
852 if (SEC_CheckCRL(handle, cert, issuerCert, t, wincx)
853 != SECSuccess) {
854 PORT_SetError(SEC_ERROR_REVOKED_CERTIFICATE);
855 CERT_DestroyCertificate(issuerCert);
856 goto loser;
857 }
858 CERT_DestroyCertificate(issuerCert);
859 }
860 /* XXX We have NOT determined that this cert is trusted.
861 * For years, NSS has treated this as trusted,
862 * but it seems incorrect.
863 */
864 rv = rvFinal;
865 goto done;
866 }
867
868 /*
869 * check the trust params of the issuer
870 */
871 flags = SEC_GET_TRUST_FLAGS(&certTrust, trustType);
872 if ( ( flags & requiredFlags ) == requiredFlags) {
873 /* we found a trusted one, so return */
874 rv = rvFinal;
875 goto done;
876 }
877 if (flags & CERTDB_VALID_CA) {
878 validCAOverride = PR_TRUE;
879 }
880 /* is it explicitly distrusted? */
881 if ((flags & CERTDB_TERMINAL_RECORD) &&
882 ((flags & (CERTDB_TRUSTED|CERTDB_TRUSTED_CA)) == 0)) {
883 /* untrusted -- the cert is explicitly untrusted, not
884 * just that it doesn't chain to a trusted cert */
885 PORT_SetError(SEC_ERROR_UNTRUSTED_CERT);
886 LOG_ERROR_OR_EXIT(log,cert,0,flags);
887 }
888 }
889 if (!validCAOverride) {
890 /*
891 * Make sure that if this is an intermediate CA in the chain that
892 * it was given permission by its signer to be a CA.
893 */
894 /*
895 * if basicConstraints says it is a ca, then we check the
896 * nsCertType. If the nsCertType has any CA bits set, then
897 * it must have the right one.
898 */
899 if (!isca || (cert->nsCertType & NS_CERT_TYPE_CA)) {
900 isca = (cert->nsCertType & caCertType) ? PR_TRUE : PR_FALSE;
901 }
902
903 if (!isca) {
904 PORT_SetError(SEC_ERROR_CA_CERT_INVALID);
905 LOG_ERROR_OR_EXIT(log,cert,0,0);
906 }
907
908 /* make sure key usage allows cert signing */
909 if (CERT_CheckKeyUsage(cert, requiredCAKeyUsage) != SECSuccess) {
910 PORT_SetError(SEC_ERROR_INADEQUATE_KEY_USAGE);
911 LOG_ERROR_OR_EXIT(log,cert,0,requiredCAKeyUsage);
912 }
913 }
914 /* make sure that the issuer is not self signed. If it is, then
915 * stop here to prevent looping.
916 */
917 if (cert->isRoot) {
918 PORT_SetError(SEC_ERROR_UNTRUSTED_ISSUER);
919 LOG_ERROR(log, cert, 0, 0);
920 goto loser;
921 }
922
923 return CERT_VerifyCertChain(handle, cert, checkSig, certUsage, t,
924 wincx, log);
925 loser:
926 rv = SECFailure;
927 done:
928 return rv;
929 }
930
931 #define NEXT_USAGE() { \
932 i*=2; \
933 certUsage++; \
934 continue; \
935 }
936
937 #define VALID_USAGE() { \
938 NEXT_USAGE(); \
939 }
940
941 #define INVALID_USAGE() { \
942 if (returnedUsages) { \
943 *returnedUsages &= (~i); \
944 } \
945 if (PR_TRUE == requiredUsage) { \
946 valid = SECFailure; \
947 } \
948 NEXT_USAGE(); \
949 }
950
951 /*
952 * check the leaf cert against trust and usage.
953 * returns success if the cert is not distrusted. If the cert is
954 * trusted, then the trusted bool will be true.
955 * returns failure if the cert is distrusted. If failure, flags
956 * will return the flag bits that indicated distrust.
957 */
958 SECStatus
959 cert_CheckLeafTrust(CERTCertificate *cert, SECCertUsage certUsage,
960 unsigned int *failedFlags, PRBool *trusted)
961 {
962 unsigned int flags;
963 CERTCertTrust trust;
964
965 *failedFlags = 0;
966 *trusted = PR_FALSE;
967
968 /* check trust flags to see if this cert is directly trusted */
969 if ( CERT_GetCertTrust(cert, &trust) == SECSuccess ) {
970 switch ( certUsage ) {
971 case certUsageSSLClient:
972 case certUsageSSLServer:
973 flags = trust.sslFlags;
974
975 /* is the cert directly trusted or not trusted ? */
976 if ( flags & CERTDB_TERMINAL_RECORD) { /* the trust record is
977 * authoritative */
978 if ( flags & CERTDB_TRUSTED ) { /* trust this cert */
979 *trusted = PR_TRUE;
980 return SECSuccess;
981 } else { /* don't trust this cert */
982 *failedFlags = flags;
983 return SECFailure;
984 }
985 }
986 break;
987 case certUsageSSLServerWithStepUp:
988 /* XXX - step up certs can't be directly trusted, only distrust */
989 flags = trust.sslFlags;
990 if ( flags & CERTDB_TERMINAL_RECORD) { /* the trust record is
991 * authoritative */
992 if (( flags & CERTDB_TRUSTED ) == 0) {
993 /* don't trust this cert */
994 *failedFlags = flags;
995 return SECFailure;
996 }
997 }
998 break;
999 case certUsageSSLCA:
1000 flags = trust.sslFlags;
1001 if ( flags & CERTDB_TERMINAL_RECORD) { /* the trust record is
1002 * authoritative */
1003 if (( flags & (CERTDB_TRUSTED|CERTDB_TRUSTED_CA) ) == 0) {
1004 /* don't trust this cert */
1005 *failedFlags = flags;
1006 return SECFailure;
1007 }
1008 }
1009 break;
1010 case certUsageEmailSigner:
1011 case certUsageEmailRecipient:
1012 flags = trust.emailFlags;
1013 if ( flags & CERTDB_TERMINAL_RECORD) { /* the trust record is
1014 * authoritative */
1015 if ( flags & CERTDB_TRUSTED ) { /* trust this cert */
1016 *trusted = PR_TRUE;
1017 return SECSuccess;
1018 }
1019 else { /* don't trust this cert */
1020 *failedFlags = flags;
1021 return SECFailure;
1022 }
1023 }
1024
1025 break;
1026 case certUsageObjectSigner:
1027 flags = trust.objectSigningFlags;
1028
1029 if ( flags & CERTDB_TERMINAL_RECORD) { /* the trust record is
1030 * authoritative */
1031 if ( flags & CERTDB_TRUSTED ) { /* trust this cert */
1032 *trusted = PR_TRUE;
1033 return SECSuccess;
1034 } else { /* don't trust this cert */
1035 *failedFlags = flags;
1036 return SECFailure;
1037 }
1038 }
1039 break;
1040 case certUsageVerifyCA:
1041 case certUsageStatusResponder:
1042 flags = trust.sslFlags;
1043 /* is the cert directly trusted or not trusted ? */
1044 if ( ( flags & ( CERTDB_VALID_CA | CERTDB_TRUSTED_CA ) ) ==
1045 ( CERTDB_VALID_CA | CERTDB_TRUSTED_CA ) ) {
1046 *trusted = PR_TRUE;
1047 return SECSuccess;
1048 }
1049 flags = trust.emailFlags;
1050 /* is the cert directly trusted or not trusted ? */
1051 if ( ( flags & ( CERTDB_VALID_CA | CERTDB_TRUSTED_CA ) ) ==
1052 ( CERTDB_VALID_CA | CERTDB_TRUSTED_CA ) ) {
1053 *trusted = PR_TRUE;
1054 return SECSuccess;
1055 }
1056 flags = trust.objectSigningFlags;
1057 /* is the cert directly trusted or not trusted ? */
1058 if ( ( flags & ( CERTDB_VALID_CA | CERTDB_TRUSTED_CA ) ) ==
1059 ( CERTDB_VALID_CA | CERTDB_TRUSTED_CA ) ) {
1060 *trusted = PR_TRUE;
1061 return SECSuccess;
1062 }
1063 /* fall through to test distrust */
1064 case certUsageAnyCA:
1065 case certUsageUserCertImport:
1066 /* do we distrust these certs explicitly */
1067 flags = trust.sslFlags;
1068 if ( flags & CERTDB_TERMINAL_RECORD) { /* the trust record is
1069 * authoritative */
1070 if ((flags & (CERTDB_TRUSTED|CERTDB_TRUSTED_CA)) == 0) {
1071 *failedFlags = flags;
1072 return SECFailure;
1073 }
1074 }
1075 flags = trust.emailFlags;
1076 if ( flags & CERTDB_TERMINAL_RECORD) { /* the trust record is
1077 * authoritative */
1078 if ((flags & (CERTDB_TRUSTED|CERTDB_TRUSTED_CA)) == 0) {
1079 *failedFlags = flags;
1080 return SECFailure;
1081 }
1082 }
1083 /* fall through */
1084 case certUsageProtectedObjectSigner:
1085 flags = trust.objectSigningFlags;
1086 if ( flags & CERTDB_TERMINAL_RECORD) { /* the trust record is
1087 * authoritative */
1088 if ((flags & (CERTDB_TRUSTED|CERTDB_TRUSTED_CA)) == 0) {
1089 *failedFlags = flags;
1090 return SECFailure;
1091 }
1092 }
1093 break;
1094 }
1095 }
1096 return SECSuccess;
1097 }
1098
1099 /*
1100 * verify a certificate by checking if it's valid and that we
1101 * trust the issuer.
1102 *
1103 * certificateUsage contains a bitfield of all cert usages that are
1104 * required for verification to succeed
1105 *
1106 * a bitfield of cert usages is returned in *returnedUsages
1107 * if requiredUsages is non-zero, the returned bitmap is only
1108 * for those required usages, otherwise it is for all usages
1109 *
1110 */
1111 SECStatus
1112 CERT_VerifyCertificate(CERTCertDBHandle *handle, CERTCertificate *cert,
1113 PRBool checkSig, SECCertificateUsage requiredUsages, int64 t,
1114 void *wincx, CERTVerifyLog *log, SECCertificateUsage* returnedUs ages)
1115 {
1116 SECStatus rv;
1117 SECStatus valid;
1118 unsigned int requiredKeyUsage;
1119 unsigned int requiredCertType;
1120 unsigned int flags;
1121 unsigned int certType;
1122 PRBool allowOverride;
1123 SECCertTimeValidity validity;
1124 CERTStatusConfig *statusConfig;
1125 PRInt32 i;
1126 SECCertUsage certUsage = 0;
1127 PRBool checkedOCSP = PR_FALSE;
1128 PRBool checkAllUsages = PR_FALSE;
1129 PRBool revoked = PR_FALSE;
1130 PRBool sigerror = PR_FALSE;
1131 PRBool trusted = PR_FALSE;
1132
1133 if (!requiredUsages) {
1134 /* there are no required usages, so the user probably wants to
1135 get status for all usages */
1136 checkAllUsages = PR_TRUE;
1137 }
1138
1139 if (returnedUsages) {
1140 *returnedUsages = 0;
1141 } else {
1142 /* we don't have a place to return status for all usages,
1143 so we can skip checks for usages that aren't required */
1144 checkAllUsages = PR_FALSE;
1145 }
1146 valid = SECSuccess ; /* start off assuming cert is valid */
1147
1148 /* make sure that the cert is valid at time t */
1149 allowOverride = (PRBool)((requiredUsages & certificateUsageSSLServer) ||
1150 (requiredUsages & certificateUsageSSLServerWithStep Up));
1151 validity = CERT_CheckCertValidTimes(cert, t, allowOverride);
1152 if ( validity != secCertTimeValid ) {
1153 valid = SECFailure;
1154 LOG_ERROR_OR_EXIT(log,cert,0,validity);
1155 }
1156
1157 /* check key usage and netscape cert type */
1158 cert_GetCertType(cert);
1159 certType = cert->nsCertType;
1160
1161 for (i=1; i<=certificateUsageHighest &&
1162 (SECSuccess == valid || returnedUsages || log) ; ) {
1163 PRBool requiredUsage = (i & requiredUsages) ? PR_TRUE : PR_FALSE;
1164 if (PR_FALSE == requiredUsage && PR_FALSE == checkAllUsages) {
1165 NEXT_USAGE();
1166 }
1167 if (returnedUsages) {
1168 *returnedUsages |= i; /* start off assuming this usage is valid */
1169 }
1170 switch ( certUsage ) {
1171 case certUsageSSLClient:
1172 case certUsageSSLServer:
1173 case certUsageSSLServerWithStepUp:
1174 case certUsageSSLCA:
1175 case certUsageEmailSigner:
1176 case certUsageEmailRecipient:
1177 case certUsageObjectSigner:
1178 case certUsageStatusResponder:
1179 rv = CERT_KeyUsageAndTypeForCertUsage(certUsage, PR_FALSE,
1180 &requiredKeyUsage,
1181 &requiredCertType);
1182 if ( rv != SECSuccess ) {
1183 PORT_Assert(0);
1184 /* EXIT_IF_NOT_LOGGING(log); XXX ??? */
1185 requiredKeyUsage = 0;
1186 requiredCertType = 0;
1187 INVALID_USAGE();
1188 }
1189 break;
1190
1191 case certUsageAnyCA:
1192 case certUsageProtectedObjectSigner:
1193 case certUsageUserCertImport:
1194 case certUsageVerifyCA:
1195 /* these usages cannot be verified */
1196 NEXT_USAGE();
1197
1198 default:
1199 PORT_Assert(0);
1200 requiredKeyUsage = 0;
1201 requiredCertType = 0;
1202 INVALID_USAGE();
1203 }
1204 if ( CERT_CheckKeyUsage(cert, requiredKeyUsage) != SECSuccess ) {
1205 if (PR_TRUE == requiredUsage) {
1206 PORT_SetError(SEC_ERROR_INADEQUATE_KEY_USAGE);
1207 }
1208 LOG_ERROR(log,cert,0,requiredKeyUsage);
1209 INVALID_USAGE();
1210 }
1211 if ( !( certType & requiredCertType ) ) {
1212 if (PR_TRUE == requiredUsage) {
1213 PORT_SetError(SEC_ERROR_INADEQUATE_CERT_TYPE);
1214 }
1215 LOG_ERROR(log,cert,0,requiredCertType);
1216 INVALID_USAGE();
1217 }
1218
1219 rv = cert_CheckLeafTrust(cert, certUsage, &flags, &trusted);
1220 if (rv == SECFailure) {
1221 if (PR_TRUE == requiredUsage) {
1222 PORT_SetError(SEC_ERROR_UNTRUSTED_CERT);
1223 }
1224 LOG_ERROR(log, cert, 0, flags);
1225 INVALID_USAGE();
1226 } else if (trusted) {
1227 VALID_USAGE();
1228 }
1229
1230 if (PR_TRUE == revoked || PR_TRUE == sigerror) {
1231 INVALID_USAGE();
1232 }
1233
1234 rv = cert_VerifyCertChain(handle, cert,
1235 checkSig, &sigerror,
1236 certUsage, t, wincx, log,
1237 &revoked);
1238
1239 if (rv != SECSuccess) {
1240 /* EXIT_IF_NOT_LOGGING(log); XXX ???? */
1241 INVALID_USAGE();
1242 }
1243
1244 /*
1245 * Check OCSP revocation status, but only if the cert we are checking
1246 * is not a status reponder itself. We only do this in the case
1247 * where we checked the cert chain (above); explicit trust "wins"
1248 * (avoids status checking, just as it avoids CRL checking) by
1249 * bypassing this code.
1250 */
1251
1252 if (PR_FALSE == checkedOCSP) {
1253 checkedOCSP = PR_TRUE; /* only check OCSP once */
1254 statusConfig = CERT_GetStatusConfig(handle);
1255 if (requiredUsages != certificateUsageStatusResponder &&
1256 statusConfig != NULL) {
1257 if (statusConfig->statusChecker != NULL) {
1258 rv = (* statusConfig->statusChecker)(handle, cert,
1259 t, wincx);
1260 if (rv != SECSuccess) {
1261 LOG_ERROR(log,cert,0,0);
1262 revoked = PR_TRUE;
1263 INVALID_USAGE();
1264 }
1265 }
1266 }
1267 }
1268
1269 NEXT_USAGE();
1270 }
1271
1272 loser:
1273 return(valid);
1274 }
1275
1276 SECStatus
1277 CERT_VerifyCert(CERTCertDBHandle *handle, CERTCertificate *cert,
1278 PRBool checkSig, SECCertUsage certUsage, int64 t,
1279 void *wincx, CERTVerifyLog *log)
1280 {
1281 SECStatus rv;
1282 unsigned int requiredKeyUsage;
1283 unsigned int requiredCertType;
1284 unsigned int flags;
1285 unsigned int certType;
1286 PRBool trusted;
1287 PRBool allowOverride;
1288 SECCertTimeValidity validity;
1289 CERTStatusConfig *statusConfig;
1290
1291 #ifdef notdef
1292 /* check if this cert is in the Evil list */
1293 rv = CERT_CheckForEvilCert(cert);
1294 if ( rv != SECSuccess ) {
1295 PORT_SetError(SEC_ERROR_REVOKED_CERTIFICATE);
1296 LOG_ERROR_OR_EXIT(log,cert,0,0);
1297 }
1298 #endif
1299
1300 /* make sure that the cert is valid at time t */
1301 allowOverride = (PRBool)((certUsage == certUsageSSLServer) ||
1302 (certUsage == certUsageSSLServerWithStepUp));
1303 validity = CERT_CheckCertValidTimes(cert, t, allowOverride);
1304 if ( validity != secCertTimeValid ) {
1305 LOG_ERROR_OR_EXIT(log,cert,0,validity);
1306 }
1307
1308 /* check key usage and netscape cert type */
1309 cert_GetCertType(cert);
1310 certType = cert->nsCertType;
1311 switch ( certUsage ) {
1312 case certUsageSSLClient:
1313 case certUsageSSLServer:
1314 case certUsageSSLServerWithStepUp:
1315 case certUsageSSLCA:
1316 case certUsageEmailSigner:
1317 case certUsageEmailRecipient:
1318 case certUsageObjectSigner:
1319 case certUsageStatusResponder:
1320 rv = CERT_KeyUsageAndTypeForCertUsage(certUsage, PR_FALSE,
1321 &requiredKeyUsage,
1322 &requiredCertType);
1323 if ( rv != SECSuccess ) {
1324 PORT_Assert(0);
1325 EXIT_IF_NOT_LOGGING(log);
1326 requiredKeyUsage = 0;
1327 requiredCertType = 0;
1328 }
1329 break;
1330 case certUsageVerifyCA:
1331 case certUsageAnyCA:
1332 requiredKeyUsage = KU_KEY_CERT_SIGN;
1333 requiredCertType = NS_CERT_TYPE_CA;
1334 if ( ! ( certType & NS_CERT_TYPE_CA ) ) {
1335 certType |= NS_CERT_TYPE_CA;
1336 }
1337 break;
1338 default:
1339 PORT_Assert(0);
1340 EXIT_IF_NOT_LOGGING(log);
1341 requiredKeyUsage = 0;
1342 requiredCertType = 0;
1343 }
1344 if ( CERT_CheckKeyUsage(cert, requiredKeyUsage) != SECSuccess ) {
1345 PORT_SetError(SEC_ERROR_INADEQUATE_KEY_USAGE);
1346 LOG_ERROR_OR_EXIT(log,cert,0,requiredKeyUsage);
1347 }
1348 if ( !( certType & requiredCertType ) ) {
1349 PORT_SetError(SEC_ERROR_INADEQUATE_CERT_TYPE);
1350 LOG_ERROR_OR_EXIT(log,cert,0,requiredCertType);
1351 }
1352
1353 rv = cert_CheckLeafTrust(cert,certUsage, &flags, &trusted);
1354 if (rv == SECFailure) {
1355 PORT_SetError(SEC_ERROR_UNTRUSTED_CERT);
1356 LOG_ERROR_OR_EXIT(log,cert,0,flags);
1357 } else if (trusted) {
1358 goto winner;
1359 }
1360
1361
1362 rv = CERT_VerifyCertChain(handle, cert, checkSig, certUsage,
1363 t, wincx, log);
1364 if (rv != SECSuccess) {
1365 EXIT_IF_NOT_LOGGING(log);
1366 }
1367
1368 /*
1369 * Check revocation status, but only if the cert we are checking
1370 * is not a status reponder itself. We only do this in the case
1371 * where we checked the cert chain (above); explicit trust "wins"
1372 * (avoids status checking, just as it avoids CRL checking, which
1373 * is all done inside VerifyCertChain) by bypassing this code.
1374 */
1375 statusConfig = CERT_GetStatusConfig(handle);
1376 if (certUsage != certUsageStatusResponder && statusConfig != NULL) {
1377 if (statusConfig->statusChecker != NULL) {
1378 rv = (* statusConfig->statusChecker)(handle, cert,
1379 t, wincx);
1380 if (rv != SECSuccess) {
1381 LOG_ERROR_OR_EXIT(log,cert,0,0);
1382 }
1383 }
1384 }
1385
1386 winner:
1387 return(SECSuccess);
1388
1389 loser:
1390 rv = SECFailure;
1391
1392 return(rv);
1393 }
1394
1395 /*
1396 * verify a certificate by checking if its valid and that we
1397 * trust the issuer. Verify time against now.
1398 */
1399 SECStatus
1400 CERT_VerifyCertificateNow(CERTCertDBHandle *handle, CERTCertificate *cert,
1401 PRBool checkSig, SECCertificateUsage requiredUsages,
1402 void *wincx, SECCertificateUsage* returnedUsages)
1403 {
1404 return(CERT_VerifyCertificate(handle, cert, checkSig,
1405 requiredUsages, PR_Now(), wincx, NULL, returnedUsages));
1406 }
1407
1408 /* obsolete, do not use for new code */
1409 SECStatus
1410 CERT_VerifyCertNow(CERTCertDBHandle *handle, CERTCertificate *cert,
1411 PRBool checkSig, SECCertUsage certUsage, void *wincx)
1412 {
1413 return(CERT_VerifyCert(handle, cert, checkSig,
1414 certUsage, PR_Now(), wincx, NULL));
1415 }
1416
1417
1418 /* [ FROM pcertdb.c ] */
1419 /*
1420 * Supported usage values and types:
1421 * certUsageSSLClient
1422 * certUsageSSLServer
1423 * certUsageSSLServerWithStepUp
1424 * certUsageEmailSigner
1425 * certUsageEmailRecipient
1426 * certUsageObjectSigner
1427 */
1428
1429 CERTCertificate *
1430 CERT_FindMatchingCert(CERTCertDBHandle *handle, SECItem *derName,
1431 CERTCertOwner owner, SECCertUsage usage,
1432 PRBool preferTrusted, int64 validTime, PRBool validOnly)
1433 {
1434 CERTCertList *certList = NULL;
1435 CERTCertificate *cert = NULL;
1436 CERTCertTrust certTrust;
1437 unsigned int requiredTrustFlags;
1438 SECTrustType requiredTrustType;
1439 unsigned int flags;
1440
1441 PRBool lookingForCA = PR_FALSE;
1442 SECStatus rv;
1443 CERTCertListNode *node;
1444 CERTCertificate *saveUntrustedCA = NULL;
1445
1446 /* if preferTrusted is set, must be a CA cert */
1447 PORT_Assert( ! ( preferTrusted && ( owner != certOwnerCA ) ) );
1448
1449 if ( owner == certOwnerCA ) {
1450 lookingForCA = PR_TRUE;
1451 if ( preferTrusted ) {
1452 rv = CERT_TrustFlagsForCACertUsage(usage, &requiredTrustFlags,
1453 &requiredTrustType);
1454 if ( rv != SECSuccess ) {
1455 goto loser;
1456 }
1457 requiredTrustFlags |= CERTDB_VALID_CA;
1458 }
1459 }
1460
1461 certList = CERT_CreateSubjectCertList(NULL, handle, derName, validTime,
1462 validOnly);
1463 if ( certList != NULL ) {
1464 rv = CERT_FilterCertListByUsage(certList, usage, lookingForCA);
1465 if ( rv != SECSuccess ) {
1466 goto loser;
1467 }
1468
1469 node = CERT_LIST_HEAD(certList);
1470
1471 while ( !CERT_LIST_END(node, certList) ) {
1472 cert = node->cert;
1473
1474 /* looking for a trusted CA cert */
1475 if ( ( owner == certOwnerCA ) && preferTrusted &&
1476 ( requiredTrustType != trustTypeNone ) ) {
1477
1478 if ( CERT_GetCertTrust(cert, &certTrust) != SECSuccess ) {
1479 flags = 0;
1480 } else {
1481 flags = SEC_GET_TRUST_FLAGS(&certTrust, requiredTrustType);
1482 }
1483
1484 if ( ( flags & requiredTrustFlags ) != requiredTrustFlags ) {
1485 /* cert is not trusted */
1486 /* if this is the first cert to get this far, then save
1487 * it, so we can use it if we can't find a trusted one
1488 */
1489 if ( saveUntrustedCA == NULL ) {
1490 saveUntrustedCA = cert;
1491 }
1492 goto endloop;
1493 }
1494 }
1495 /* if we got this far, then this cert meets all criteria */
1496 break;
1497
1498 endloop:
1499 node = CERT_LIST_NEXT(node);
1500 cert = NULL;
1501 }
1502
1503 /* use the saved one if we have it */
1504 if ( cert == NULL ) {
1505 cert = saveUntrustedCA;
1506 }
1507
1508 /* if we found one then bump the ref count before freeing the list */
1509 if ( cert != NULL ) {
1510 /* bump the ref count */
1511 cert = CERT_DupCertificate(cert);
1512 }
1513
1514 CERT_DestroyCertList(certList);
1515 }
1516
1517 return(cert);
1518
1519 loser:
1520 if ( certList != NULL ) {
1521 CERT_DestroyCertList(certList);
1522 }
1523
1524 return(NULL);
1525 }
1526
1527
1528 /* [ From certdb.c ] */
1529 /*
1530 * Filter a list of certificates, removing those certs that do not have
1531 * one of the named CA certs somewhere in their cert chain.
1532 *
1533 * "certList" - the list of certificates to filter
1534 * "nCANames" - number of CA names
1535 * "caNames" - array of CA names in string(rfc 1485) form
1536 * "usage" - what use the certs are for, this is used when
1537 * selecting CA certs
1538 */
1539 SECStatus
1540 CERT_FilterCertListByCANames(CERTCertList *certList, int nCANames,
1541 char **caNames, SECCertUsage usage)
1542 {
1543 CERTCertificate *issuerCert = NULL;
1544 CERTCertificate *subjectCert;
1545 CERTCertListNode *node, *freenode;
1546 CERTCertificate *cert;
1547 int n;
1548 char **names;
1549 PRBool found;
1550 int64 time;
1551
1552 if ( nCANames <= 0 ) {
1553 return(SECSuccess);
1554 }
1555
1556 time = PR_Now();
1557
1558 node = CERT_LIST_HEAD(certList);
1559
1560 while ( ! CERT_LIST_END(node, certList) ) {
1561 cert = node->cert;
1562
1563 subjectCert = CERT_DupCertificate(cert);
1564
1565 /* traverse the CA certs for this cert */
1566 found = PR_FALSE;
1567 while ( subjectCert != NULL ) {
1568 n = nCANames;
1569 names = caNames;
1570
1571 if (subjectCert->issuerName != NULL) {
1572 while ( n > 0 ) {
1573 if ( PORT_Strcmp(*names, subjectCert->issuerName) == 0 ) {
1574 found = PR_TRUE;
1575 break;
1576 }
1577
1578 n--;
1579 names++;
1580 }
1581 }
1582
1583 if ( found ) {
1584 break;
1585 }
1586
1587 issuerCert = CERT_FindCertIssuer(subjectCert, time, usage);
1588 if ( issuerCert == subjectCert ) {
1589 CERT_DestroyCertificate(issuerCert);
1590 issuerCert = NULL;
1591 break;
1592 }
1593 CERT_DestroyCertificate(subjectCert);
1594 subjectCert = issuerCert;
1595
1596 }
1597 CERT_DestroyCertificate(subjectCert);
1598 if ( !found ) {
1599 /* CA was not found, so remove this cert from the list */
1600 freenode = node;
1601 node = CERT_LIST_NEXT(node);
1602 CERT_RemoveCertListNode(freenode);
1603 } else {
1604 /* CA was found, so leave it in the list */
1605 node = CERT_LIST_NEXT(node);
1606 }
1607 }
1608
1609 return(SECSuccess);
1610 }
1611
1612 /*
1613 * Given a certificate, return a string containing the nickname, and possibly
1614 * one of the validity strings, based on the current validity state of the
1615 * certificate.
1616 *
1617 * "arena" - arena to allocate returned string from. If NULL, then heap
1618 * is used.
1619 * "cert" - the cert to get nickname from
1620 * "expiredString" - the string to append to the nickname if the cert is
1621 * expired.
1622 * "notYetGoodString" - the string to append to the nickname if the cert is
1623 * not yet good.
1624 */
1625 char *
1626 CERT_GetCertNicknameWithValidity(PRArenaPool *arena, CERTCertificate *cert,
1627 char *expiredString, char *notYetGoodString)
1628 {
1629 SECCertTimeValidity validity;
1630 char *nickname = NULL, *tmpstr = NULL;
1631
1632 validity = CERT_CheckCertValidTimes(cert, PR_Now(), PR_FALSE);
1633
1634 /* if the cert is good, then just use the nickname directly */
1635 if ( validity == secCertTimeValid ) {
1636 if ( arena == NULL ) {
1637 nickname = PORT_Strdup(cert->nickname);
1638 } else {
1639 nickname = PORT_ArenaStrdup(arena, cert->nickname);
1640 }
1641
1642 if ( nickname == NULL ) {
1643 goto loser;
1644 }
1645 } else {
1646
1647 /* if the cert is not valid, then tack one of the strings on the
1648 * end
1649 */
1650 if ( validity == secCertTimeExpired ) {
1651 tmpstr = PR_smprintf("%s%s", cert->nickname,
1652 expiredString);
1653 } else if ( validity == secCertTimeNotValidYet ) {
1654 /* not yet valid */
1655 tmpstr = PR_smprintf("%s%s", cert->nickname,
1656 notYetGoodString);
1657 } else {
1658 /* undetermined */
1659 tmpstr = PR_smprintf("%s",
1660 "(NULL) (Validity Unknown)");
1661 }
1662
1663 if ( tmpstr == NULL ) {
1664 goto loser;
1665 }
1666
1667 if ( arena ) {
1668 /* copy the string into the arena and free the malloc'd one */
1669 nickname = PORT_ArenaStrdup(arena, tmpstr);
1670 PORT_Free(tmpstr);
1671 } else {
1672 nickname = tmpstr;
1673 }
1674 if ( nickname == NULL ) {
1675 goto loser;
1676 }
1677 }
1678 return(nickname);
1679
1680 loser:
1681 return(NULL);
1682 }
1683
1684 /*
1685 * Collect the nicknames from all certs in a CertList. If the cert is not
1686 * valid, append a string to that nickname.
1687 *
1688 * "certList" - the list of certificates
1689 * "expiredString" - the string to append to the nickname of any expired cert
1690 * "notYetGoodString" - the string to append to the nickname of any cert
1691 * that is not yet valid
1692 */
1693 CERTCertNicknames *
1694 CERT_NicknameStringsFromCertList(CERTCertList *certList, char *expiredString,
1695 char *notYetGoodString)
1696 {
1697 CERTCertNicknames *names;
1698 PRArenaPool *arena;
1699 CERTCertListNode *node;
1700 char **nn;
1701
1702 /* allocate an arena */
1703 arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
1704 if ( arena == NULL ) {
1705 return(NULL);
1706 }
1707
1708 /* allocate the structure */
1709 names = PORT_ArenaAlloc(arena, sizeof(CERTCertNicknames));
1710 if ( names == NULL ) {
1711 goto loser;
1712 }
1713
1714 /* init the structure */
1715 names->arena = arena;
1716 names->head = NULL;
1717 names->numnicknames = 0;
1718 names->nicknames = NULL;
1719 names->totallen = 0;
1720
1721 /* count the certs in the list */
1722 node = CERT_LIST_HEAD(certList);
1723 while ( ! CERT_LIST_END(node, certList) ) {
1724 names->numnicknames++;
1725 node = CERT_LIST_NEXT(node);
1726 }
1727
1728 /* allocate nicknames array */
1729 names->nicknames = PORT_ArenaAlloc(arena,
1730 sizeof(char *) * names->numnicknames);
1731 if ( names->nicknames == NULL ) {
1732 goto loser;
1733 }
1734
1735 /* just in case printf can't deal with null strings */
1736 if (expiredString == NULL ) {
1737 expiredString = "";
1738 }
1739
1740 if ( notYetGoodString == NULL ) {
1741 notYetGoodString = "";
1742 }
1743
1744 /* traverse the list of certs and collect the nicknames */
1745 nn = names->nicknames;
1746 node = CERT_LIST_HEAD(certList);
1747 while ( ! CERT_LIST_END(node, certList) ) {
1748 *nn = CERT_GetCertNicknameWithValidity(arena, node->cert,
1749 expiredString,
1750 notYetGoodString);
1751 if ( *nn == NULL ) {
1752 goto loser;
1753 }
1754
1755 names->totallen += PORT_Strlen(*nn);
1756
1757 nn++;
1758 node = CERT_LIST_NEXT(node);
1759 }
1760
1761 return(names);
1762
1763 loser:
1764 PORT_FreeArena(arena, PR_FALSE);
1765 return(NULL);
1766 }
1767
1768 /*
1769 * Extract the nickname from a nickmake string that may have either
1770 * expiredString or notYetGoodString appended.
1771 *
1772 * Args:
1773 * "namestring" - the string containing the nickname, and possibly
1774 * one of the validity label strings
1775 * "expiredString" - the expired validity label string
1776 * "notYetGoodString" - the not yet good validity label string
1777 *
1778 * Returns the raw nickname
1779 */
1780 char *
1781 CERT_ExtractNicknameString(char *namestring, char *expiredString,
1782 char *notYetGoodString)
1783 {
1784 int explen, nyglen, namelen;
1785 int retlen;
1786 char *retstr;
1787
1788 namelen = PORT_Strlen(namestring);
1789 explen = PORT_Strlen(expiredString);
1790 nyglen = PORT_Strlen(notYetGoodString);
1791
1792 if ( namelen > explen ) {
1793 if ( PORT_Strcmp(expiredString, &namestring[namelen-explen]) == 0 ) {
1794 retlen = namelen - explen;
1795 retstr = (char *)PORT_Alloc(retlen+1);
1796 if ( retstr == NULL ) {
1797 goto loser;
1798 }
1799
1800 PORT_Memcpy(retstr, namestring, retlen);
1801 retstr[retlen] = '\0';
1802 goto done;
1803 }
1804 }
1805
1806 if ( namelen > nyglen ) {
1807 if ( PORT_Strcmp(notYetGoodString, &namestring[namelen-nyglen]) == 0) {
1808 retlen = namelen - nyglen;
1809 retstr = (char *)PORT_Alloc(retlen+1);
1810 if ( retstr == NULL ) {
1811 goto loser;
1812 }
1813
1814 PORT_Memcpy(retstr, namestring, retlen);
1815 retstr[retlen] = '\0';
1816 goto done;
1817 }
1818 }
1819
1820 /* if name string is shorter than either invalid string, then it must
1821 * be a raw nickname
1822 */
1823 retstr = PORT_Strdup(namestring);
1824
1825 done:
1826 return(retstr);
1827
1828 loser:
1829 return(NULL);
1830 }
1831
1832 CERTCertList *
1833 CERT_GetCertChainFromCert(CERTCertificate *cert, int64 time, SECCertUsage usage)
1834 {
1835 CERTCertList *chain = NULL;
1836 int count = 0;
1837
1838 if (NULL == cert) {
1839 return NULL;
1840 }
1841
1842 cert = CERT_DupCertificate(cert);
1843 if (NULL == cert) {
1844 PORT_SetError(SEC_ERROR_NO_MEMORY);
1845 return NULL;
1846 }
1847
1848 chain = CERT_NewCertList();
1849 if (NULL == chain) {
1850 PORT_SetError(SEC_ERROR_NO_MEMORY);
1851 return NULL;
1852 }
1853
1854 while (cert != NULL && ++count <= CERT_MAX_CERT_CHAIN) {
1855 if (SECSuccess != CERT_AddCertToListTail(chain, cert)) {
1856 /* return partial chain */
1857 PORT_SetError(SEC_ERROR_NO_MEMORY);
1858 return chain;
1859 }
1860
1861 if (cert->isRoot) {
1862 /* return complete chain */
1863 return chain;
1864 }
1865
1866 cert = CERT_FindCertIssuer(cert, time, usage);
1867 }
1868
1869 /* return partial chain */
1870 PORT_SetError(SEC_ERROR_UNKNOWN_ISSUER);
1871 return chain;
1872 }
OLDNEW
« no previous file with comments | « mozilla/security/nss/lib/certhigh/certreq.c ('k') | mozilla/security/nss/lib/certhigh/certvfypkix.c » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698