Import from 1.9a8 tarball
[mozilla-nss.git] / security / nss / lib / certhigh / certvfy.c
blob554d88486c94239a8acb7d9fbe4655dae041224d
1 /* ***** BEGIN LICENSE BLOCK *****
2 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4 * The contents of this file are subject to the Mozilla Public License Version
5 * 1.1 (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 * http://www.mozilla.org/MPL/
9 * Software distributed under the License is distributed on an "AS IS" basis,
10 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
11 * for the specific language governing rights and limitations under the
12 * License.
14 * The Original Code is the Netscape security libraries.
16 * The Initial Developer of the Original Code is
17 * Netscape Communications Corporation.
18 * Portions created by the Initial Developer are Copyright (C) 1994-2000
19 * the Initial Developer. All Rights Reserved.
21 * Contributor(s):
23 * Alternatively, the contents of this file may be used under the terms of
24 * either the GNU General Public License Version 2 or later (the "GPL"), or
25 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
26 * in which case the provisions of the GPL or the LGPL are applicable instead
27 * of those above. If you wish to allow use of your version of this file only
28 * under the terms of either the GPL or the LGPL, and not to allow others to
29 * use your version of this file under the terms of the MPL, indicate your
30 * decision by deleting the provisions above and replace them with the notice
31 * and other provisions required by the GPL or the LGPL. If you do not delete
32 * the provisions above, a recipient may use your version of this file under
33 * the terms of any one of the MPL, the GPL or the LGPL.
35 * ***** END LICENSE BLOCK ***** */
36 #include "nspr.h"
37 #include "secerr.h"
38 #include "secport.h"
39 #include "seccomon.h"
40 #include "secoid.h"
41 #include "sslerr.h"
42 #include "genname.h"
43 #include "keyhi.h"
44 #include "cert.h"
45 #include "certdb.h"
46 #include "cryptohi.h"
48 #ifndef NSS_3_4_CODE
49 #define NSS_3_4_CODE
50 #endif /* NSS_3_4_CODE */
51 #include "nsspki.h"
52 #include "pkitm.h"
53 #include "pkim.h"
54 #include "pki3hack.h"
55 #include "base.h"
59 * Check the validity times of a certificate
61 SECStatus
62 CERT_CertTimesValid(CERTCertificate *c)
64 SECCertTimeValidity valid = CERT_CheckCertValidTimes(c, PR_Now(), PR_TRUE);
65 return (valid == secCertTimeValid) ? SECSuccess : SECFailure;
69 * verify the signature of a signed data object with the given DER publickey
71 SECStatus
72 CERT_VerifySignedDataWithPublicKey(CERTSignedData *sd,
73 SECKEYPublicKey *pubKey,
74 void *wincx)
76 SECStatus rv;
77 SECItem sig;
79 if ( !pubKey || !sd ) {
80 PORT_SetError(PR_INVALID_ARGUMENT_ERROR);
81 return SECFailure;
84 /* check the signature */
85 sig = sd->signature;
86 /* convert sig->len from bit counts to byte count. */
87 DER_ConvertBitString(&sig);
89 rv = VFY_VerifyDataWithAlgorithmID(sd->data.data, sd->data.len, pubKey,
90 &sig, &sd->signatureAlgorithm, NULL, wincx);
92 return rv ? SECFailure : SECSuccess;
96 * verify the signature of a signed data object with the given DER publickey
98 SECStatus
99 CERT_VerifySignedDataWithPublicKeyInfo(CERTSignedData *sd,
100 CERTSubjectPublicKeyInfo *pubKeyInfo,
101 void *wincx)
103 SECKEYPublicKey *pubKey;
104 SECStatus rv = SECFailure;
106 /* get cert's public key */
107 pubKey = SECKEY_ExtractPublicKey(pubKeyInfo);
108 if (pubKey) {
109 rv = CERT_VerifySignedDataWithPublicKey(sd, pubKey, wincx);
110 SECKEY_DestroyPublicKey(pubKey);
112 return rv;
116 * verify the signature of a signed data object with the given certificate
118 SECStatus
119 CERT_VerifySignedData(CERTSignedData *sd, CERTCertificate *cert,
120 int64 t, void *wincx)
122 SECKEYPublicKey *pubKey = 0;
123 SECStatus rv = SECFailure;
124 SECCertTimeValidity validity;
126 /* check the certificate's validity */
127 validity = CERT_CheckCertValidTimes(cert, t, PR_FALSE);
128 if ( validity != secCertTimeValid ) {
129 return rv;
132 /* get cert's public key */
133 pubKey = CERT_ExtractPublicKey(cert);
134 if (pubKey) {
135 rv = CERT_VerifySignedDataWithPublicKey(sd, pubKey, wincx);
136 SECKEY_DestroyPublicKey(pubKey);
138 return rv;
142 /* Software FORTEZZA installation hack. The software fortezza installer does
143 * not have access to the krl and cert.db file. Accept FORTEZZA Certs without
144 * KRL's in this case.
146 static int dont_use_krl = 0;
147 /* not a public exposed function... */
148 void sec_SetCheckKRLState(int value) { dont_use_krl = value; }
150 SECStatus
151 SEC_CheckKRL(CERTCertDBHandle *handle,SECKEYPublicKey *key,
152 CERTCertificate *rootCert, int64 t, void * wincx)
154 CERTSignedCrl *crl = NULL;
155 SECStatus rv = SECFailure;
156 SECStatus rv2;
157 CERTCrlEntry **crlEntry;
158 SECCertTimeValidity validity;
159 CERTCertificate *issuerCert = NULL;
161 if (dont_use_krl) return SECSuccess;
163 /* first look up the KRL */
164 crl = SEC_FindCrlByName(handle,&rootCert->derSubject, SEC_KRL_TYPE);
165 if (crl == NULL) {
166 PORT_SetError(SEC_ERROR_NO_KRL);
167 goto done;
170 /* get the issuing certificate */
171 issuerCert = CERT_FindCertByName(handle, &crl->crl.derName);
172 if (issuerCert == NULL) {
173 PORT_SetError(SEC_ERROR_KRL_BAD_SIGNATURE);
174 goto done;
178 /* now verify the KRL signature */
179 rv2 = CERT_VerifySignedData(&crl->signatureWrap, issuerCert, t, wincx);
180 if (rv2 != SECSuccess) {
181 PORT_SetError(SEC_ERROR_KRL_BAD_SIGNATURE);
182 goto done;
185 /* Verify the date validity of the KRL */
186 validity = SEC_CheckCrlTimes(&crl->crl, t);
187 if (validity == secCertTimeExpired) {
188 PORT_SetError(SEC_ERROR_KRL_EXPIRED);
189 goto done;
192 /* now make sure the key in this cert is still valid */
193 if (key->keyType != fortezzaKey) {
194 PORT_SetError(SSL_ERROR_BAD_CERT_DOMAIN);
195 goto done; /* This should be an assert? */
198 /* now make sure the key is not on the revocation list */
199 for (crlEntry = crl->crl.entries; crlEntry && *crlEntry; crlEntry++) {
200 if (PORT_Memcmp((*crlEntry)->serialNumber.data,
201 key->u.fortezza.KMID,
202 (*crlEntry)->serialNumber.len) == 0) {
203 PORT_SetError(SEC_ERROR_REVOKED_KEY);
204 goto done;
207 rv = SECSuccess;
209 done:
210 if (issuerCert) CERT_DestroyCertificate(issuerCert);
211 if (crl) SEC_DestroyCrl(crl);
212 return rv;
215 SECStatus
216 SEC_CheckCRL(CERTCertDBHandle *handle,CERTCertificate *cert,
217 CERTCertificate *caCert, int64 t, void * wincx)
219 return CERT_CheckCRL(cert, caCert, NULL, t, wincx);
223 * Find the issuer of a cert. Use the authorityKeyID if it exists.
225 CERTCertificate *
226 CERT_FindCertIssuer(CERTCertificate *cert, int64 validTime, SECCertUsage usage)
228 #ifdef NSS_CLASSIC
229 CERTAuthKeyID * authorityKeyID = NULL;
230 CERTCertificate * issuerCert = NULL;
231 SECItem * caName;
232 PRArenaPool *tmpArena = NULL;
234 tmpArena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
236 if ( !tmpArena ) {
237 goto loser;
239 authorityKeyID = CERT_FindAuthKeyIDExten(tmpArena,cert);
241 if ( authorityKeyID != NULL ) {
242 /* has the authority key ID extension */
243 if ( authorityKeyID->keyID.data != NULL ) {
244 /* extension contains a key ID, so lookup based on it */
245 issuerCert = CERT_FindCertByKeyID(cert->dbhandle, &cert->derIssuer,
246 &authorityKeyID->keyID);
247 if ( issuerCert == NULL ) {
248 PORT_SetError (SEC_ERROR_UNKNOWN_ISSUER);
249 goto loser;
252 } else if ( authorityKeyID->authCertIssuer != NULL ) {
253 /* no key ID, so try issuer and serial number */
254 caName = (SECItem*)CERT_GetGeneralNameByType(authorityKeyID->authCertIssuer,
255 certDirectoryName, PR_TRUE);
258 * caName is NULL when the authCertIssuer field is not
259 * being used, or other name form is used instead.
260 * If the directoryName format and serialNumber fields are
261 * used, we use them to find the CA cert.
262 * Note:
263 * By the time it gets here, we known for sure that if the
264 * authCertIssuer exists, then the authCertSerialNumber
265 * must also exists (CERT_DecodeAuthKeyID() ensures this).
266 * We don't need to check again.
269 if (caName != NULL) {
270 CERTIssuerAndSN issuerSN;
272 issuerSN.derIssuer.data = caName->data;
273 issuerSN.derIssuer.len = caName->len;
274 issuerSN.serialNumber.data =
275 authorityKeyID->authCertSerialNumber.data;
276 issuerSN.serialNumber.len =
277 authorityKeyID->authCertSerialNumber.len;
278 issuerCert = CERT_FindCertByIssuerAndSN(cert->dbhandle,
279 &issuerSN);
280 if ( issuerCert == NULL ) {
281 PORT_SetError (SEC_ERROR_UNKNOWN_ISSUER);
282 goto loser;
287 if ( issuerCert == NULL ) {
288 /* if there is not authorityKeyID, then try to find the issuer */
289 /* find a valid CA cert with correct usage */
290 issuerCert = CERT_FindMatchingCert(cert->dbhandle,
291 &cert->derIssuer,
292 certOwnerCA, usage, PR_TRUE,
293 validTime, PR_TRUE);
295 /* if that fails, then fall back to grabbing any cert with right name*/
296 if ( issuerCert == NULL ) {
297 issuerCert = CERT_FindCertByName(cert->dbhandle, &cert->derIssuer);
298 if ( issuerCert == NULL ) {
299 PORT_SetError (SEC_ERROR_UNKNOWN_ISSUER);
304 loser:
305 if (tmpArena != NULL) {
306 PORT_FreeArena(tmpArena, PR_FALSE);
307 tmpArena = NULL;
310 return(issuerCert);
311 #else
312 NSSCertificate *me;
313 NSSTime *nssTime;
314 NSSTrustDomain *td;
315 NSSCryptoContext *cc;
316 NSSCertificate *chain[3];
317 NSSUsage nssUsage;
318 PRStatus status;
320 me = STAN_GetNSSCertificate(cert);
321 if (!me) {
322 PORT_SetError(SEC_ERROR_NO_MEMORY);
323 return NULL;
325 nssTime = NSSTime_SetPRTime(NULL, validTime);
326 nssUsage.anyUsage = PR_FALSE;
327 nssUsage.nss3usage = usage;
328 nssUsage.nss3lookingForCA = PR_TRUE;
329 memset(chain, 0, 3*sizeof(NSSCertificate *));
330 td = STAN_GetDefaultTrustDomain();
331 cc = STAN_GetDefaultCryptoContext();
332 (void)NSSCertificate_BuildChain(me, nssTime, &nssUsage, NULL,
333 chain, 2, NULL, &status, td, cc);
334 nss_ZFreeIf(nssTime);
335 if (status == PR_SUCCESS) {
336 PORT_Assert(me == chain[0]);
337 /* if it's a root, the chain will only have one cert */
338 if (!chain[1]) {
339 /* already has a reference from the call to BuildChain */
340 return cert;
342 NSSCertificate_Destroy(chain[0]); /* the first cert in the chain */
343 return STAN_GetCERTCertificate(chain[1]); /* return the 2nd */
345 if (chain[0]) {
346 PORT_Assert(me == chain[0]);
347 NSSCertificate_Destroy(chain[0]); /* the first cert in the chain */
349 PORT_SetError (SEC_ERROR_UNKNOWN_ISSUER);
350 return NULL;
351 #endif
355 * return required trust flags for various cert usages for CAs
357 SECStatus
358 CERT_TrustFlagsForCACertUsage(SECCertUsage usage,
359 unsigned int *retFlags,
360 SECTrustType *retTrustType)
362 unsigned int requiredFlags;
363 SECTrustType trustType;
365 switch ( usage ) {
366 case certUsageSSLClient:
367 requiredFlags = CERTDB_TRUSTED_CLIENT_CA;
368 trustType = trustSSL;
369 break;
370 case certUsageSSLServer:
371 case certUsageSSLCA:
372 requiredFlags = CERTDB_TRUSTED_CA;
373 trustType = trustSSL;
374 break;
375 case certUsageSSLServerWithStepUp:
376 requiredFlags = CERTDB_TRUSTED_CA | CERTDB_GOVT_APPROVED_CA;
377 trustType = trustSSL;
378 break;
379 case certUsageEmailSigner:
380 case certUsageEmailRecipient:
381 requiredFlags = CERTDB_TRUSTED_CA;
382 trustType = trustEmail;
383 break;
384 case certUsageObjectSigner:
385 requiredFlags = CERTDB_TRUSTED_CA;
386 trustType = trustObjectSigning;
387 break;
388 case certUsageVerifyCA:
389 case certUsageAnyCA:
390 case certUsageStatusResponder:
391 requiredFlags = CERTDB_TRUSTED_CA;
392 trustType = trustTypeNone;
393 break;
394 default:
395 PORT_Assert(0);
396 goto loser;
398 if ( retFlags != NULL ) {
399 *retFlags = requiredFlags;
401 if ( retTrustType != NULL ) {
402 *retTrustType = trustType;
405 return(SECSuccess);
406 loser:
407 return(SECFailure);
414 static void
415 AddToVerifyLog(CERTVerifyLog *log, CERTCertificate *cert, unsigned long error,
416 unsigned int depth, void *arg)
418 CERTVerifyLogNode *node, *tnode;
420 PORT_Assert(log != NULL);
422 node = (CERTVerifyLogNode *)PORT_ArenaAlloc(log->arena,
423 sizeof(CERTVerifyLogNode));
424 if ( node != NULL ) {
425 node->cert = CERT_DupCertificate(cert);
426 node->error = error;
427 node->depth = depth;
428 node->arg = arg;
430 if ( log->tail == NULL ) {
431 /* empty list */
432 log->head = log->tail = node;
433 node->prev = NULL;
434 node->next = NULL;
435 } else if ( depth >= log->tail->depth ) {
436 /* add to tail */
437 node->prev = log->tail;
438 log->tail->next = node;
439 log->tail = node;
440 node->next = NULL;
441 } else if ( depth < log->head->depth ) {
442 /* add at head */
443 node->prev = NULL;
444 node->next = log->head;
445 log->head->prev = node;
446 log->head = node;
447 } else {
448 /* add in middle */
449 tnode = log->tail;
450 while ( tnode != NULL ) {
451 if ( depth >= tnode->depth ) {
452 /* insert after tnode */
453 node->prev = tnode;
454 node->next = tnode->next;
455 tnode->next->prev = node;
456 tnode->next = node;
457 break;
460 tnode = tnode->prev;
464 log->count++;
466 return;
469 #define EXIT_IF_NOT_LOGGING(log) \
470 if ( log == NULL ) { \
471 goto loser; \
474 #define LOG_ERROR_OR_EXIT(log,cert,depth,arg) \
475 if ( log != NULL ) { \
476 AddToVerifyLog(log, cert, PORT_GetError(), depth, (void *)arg); \
477 } else { \
478 goto loser; \
481 #define LOG_ERROR(log,cert,depth,arg) \
482 if ( log != NULL ) { \
483 AddToVerifyLog(log, cert, PORT_GetError(), depth, (void *)arg); \
487 typedef enum { cbd_None, cbd_User, cbd_CA } cbd_FortezzaType;
489 static SECStatus
490 cert_VerifyFortezzaV1Cert(CERTCertDBHandle *handle, CERTCertificate *cert,
491 cbd_FortezzaType *next_type, cbd_FortezzaType last_type,
492 int64 t, void *wincx)
494 unsigned char priv = 0;
495 SECKEYPublicKey *key;
496 SECStatus rv;
498 *next_type = cbd_CA;
500 /* read the key */
501 key = CERT_ExtractPublicKey(cert);
503 /* Cant' get Key? fail. */
504 if (key == NULL) {
505 PORT_SetError(SEC_ERROR_BAD_KEY);
506 return SECFailure;
510 /* if the issuer is not an old fortezza cert, we bail */
511 if (key->keyType != fortezzaKey) {
512 SECKEY_DestroyPublicKey(key);
513 /* CA Cert not fortezza */
514 PORT_SetError(SEC_ERROR_NOT_FORTEZZA_ISSUER);
515 return SECFailure;
518 /* get the privilege mask */
519 if (key->u.fortezza.DSSpriviledge.len > 0) {
520 priv = key->u.fortezza.DSSpriviledge.data[0];
524 * make sure the CA's keys are OK
527 rv = SEC_CheckKRL(handle, key, NULL, t, wincx);
528 SECKEY_DestroyPublicKey(key);
529 if (rv != SECSuccess) {
530 return rv;
533 switch (last_type) {
534 case cbd_User:
535 /* first check for subordination */
536 /*rv = FortezzaSubordinateCheck(cert,issuerCert);*/
537 rv = SECSuccess;
539 /* now check for issuer privilege */
540 if ((rv != SECSuccess) || ((priv & 0x10) == 0)) {
541 /* bail */
542 PORT_SetError (SEC_ERROR_CA_CERT_INVALID);
543 return SECFailure;
545 break;
546 case cbd_CA:
547 if ((priv & 0x20) == 0) {
548 /* bail */
549 PORT_SetError (SEC_ERROR_CA_CERT_INVALID);
550 return SECFailure;
552 break;
553 case cbd_None:
554 *next_type = (priv & 0x30) ? cbd_CA : cbd_User;
555 break;
556 default:
557 /* bail */ /* shouldn't ever happen */
558 PORT_SetError(SEC_ERROR_UNKNOWN_ISSUER);
559 return SECFailure;
561 return SECSuccess;
565 static SECStatus
566 cert_VerifyCertChain(CERTCertDBHandle *handle, CERTCertificate *cert,
567 PRBool checkSig, PRBool* sigerror,
568 SECCertUsage certUsage, int64 t, void *wincx,
569 CERTVerifyLog *log, PRBool* revoked)
571 SECTrustType trustType;
572 CERTBasicConstraints basicConstraint;
573 CERTCertificate *issuerCert = NULL;
574 CERTCertificate *subjectCert = NULL;
575 CERTCertificate *badCert = NULL;
576 PRBool isca;
577 PRBool isFortezzaV1 = PR_FALSE;
578 SECStatus rv;
579 SECStatus rvFinal = SECSuccess;
580 int count;
581 int currentPathLen = 0;
582 int pathLengthLimit = CERT_UNLIMITED_PATH_CONSTRAINT;
583 int flags;
584 unsigned int caCertType;
585 unsigned int requiredCAKeyUsage;
586 unsigned int requiredFlags;
587 PRArenaPool *arena = NULL;
588 CERTGeneralName *namesList = NULL;
589 CERTCertificate **certsList = NULL;
590 int certsListLen = 16;
591 int namesCount = 0;
592 PRBool subjectCertIsSelfIssued;
594 cbd_FortezzaType last_type = cbd_None;
596 if (revoked) {
597 *revoked = PR_FALSE;
600 if (CERT_KeyUsageAndTypeForCertUsage(certUsage, PR_TRUE,
601 &requiredCAKeyUsage,
602 &caCertType)
603 != SECSuccess ) {
604 PORT_Assert(0);
605 EXIT_IF_NOT_LOGGING(log);
606 requiredCAKeyUsage = 0;
607 caCertType = 0;
610 switch ( certUsage ) {
611 case certUsageSSLClient:
612 case certUsageSSLServer:
613 case certUsageSSLCA:
614 case certUsageSSLServerWithStepUp:
615 case certUsageEmailSigner:
616 case certUsageEmailRecipient:
617 case certUsageObjectSigner:
618 case certUsageVerifyCA:
619 case certUsageStatusResponder:
620 if ( CERT_TrustFlagsForCACertUsage(certUsage, &requiredFlags,
621 &trustType) != SECSuccess ) {
622 PORT_Assert(0);
623 EXIT_IF_NOT_LOGGING(log);
624 requiredFlags = 0;
625 trustType = trustSSL;
627 break;
628 default:
629 PORT_Assert(0);
630 EXIT_IF_NOT_LOGGING(log);
631 requiredFlags = 0;
632 trustType = trustSSL;/* This used to be 0, but we need something
633 * that matches the enumeration type.
635 caCertType = 0;
638 subjectCert = CERT_DupCertificate(cert);
639 if ( subjectCert == NULL ) {
640 goto loser;
643 /* determine if the cert is fortezza.
645 isFortezzaV1 = (PRBool)
646 (CERT_GetCertKeyType(&subjectCert->subjectPublicKeyInfo)
647 == fortezzaKey);
649 if (isFortezzaV1) {
650 rv = cert_VerifyFortezzaV1Cert(handle, subjectCert, &last_type,
651 cbd_None, t, wincx);
652 if (rv == SECFailure) {
653 /**** PORT_SetError is already set by cert_VerifyFortezzaV1Cert **/
654 LOG_ERROR_OR_EXIT(log,subjectCert,0,0);
658 arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
659 if (arena == NULL) {
660 goto loser;
663 certsList = PORT_ZNewArray(CERTCertificate *, certsListLen);
664 if (certsList == NULL)
665 goto loser;
667 /* RFC 3280 says that the name constraints will apply to the names
668 ** in the leaf (EE) cert, whether it is self issued or not, so
669 ** we pretend that it is not.
671 subjectCertIsSelfIssued = PR_FALSE;
672 for ( count = 0; count < CERT_MAX_CERT_CHAIN; count++ ) {
673 PRBool validCAOverride = PR_FALSE;
675 /* Construct a list of names for the current and all previous
676 * certifcates (except leaf (EE) certs, root CAs, and self-issued
677 * intermediate CAs) to be verified against the name constraints
678 * extension of the issuer certificate.
680 if (subjectCertIsSelfIssued == PR_FALSE) {
681 CERTGeneralName *subjectNameList;
682 int subjectNameListLen;
683 int i;
684 subjectNameList = CERT_GetCertificateNames(subjectCert, arena);
685 subjectNameListLen = CERT_GetNamesLength(subjectNameList);
686 if (certsListLen <= namesCount + subjectNameListLen) {
687 CERTCertificate **tmpCertsList;
688 certsListLen = (namesCount + subjectNameListLen) * 2;
689 tmpCertsList =
690 (CERTCertificate **)PORT_Realloc(certsList,
691 certsListLen * sizeof(CERTCertificate *));
692 if (tmpCertsList == NULL) {
693 goto loser;
695 certsList = tmpCertsList;
697 for (i = 0; i < subjectNameListLen; i++) {
698 certsList[namesCount + i] = subjectCert;
700 namesCount += subjectNameListLen;
701 namesList = cert_CombineNamesLists(namesList, subjectNameList);
704 /* check if the cert has an unsupported critical extension */
705 if ( subjectCert->options.bits.hasUnsupportedCriticalExt ) {
706 PORT_SetError(SEC_ERROR_UNKNOWN_CRITICAL_EXTENSION);
707 LOG_ERROR_OR_EXIT(log,subjectCert,count,0);
710 /* find the certificate of the issuer */
711 issuerCert = CERT_FindCertIssuer(subjectCert, t, certUsage);
712 if ( ! issuerCert ) {
713 PORT_SetError(SEC_ERROR_UNKNOWN_ISSUER);
714 LOG_ERROR(log,subjectCert,count,0);
715 goto loser;
718 /* verify the signature on the cert */
719 if ( checkSig ) {
720 rv = CERT_VerifySignedData(&subjectCert->signatureWrap,
721 issuerCert, t, wincx);
723 if ( rv != SECSuccess ) {
724 if (sigerror) {
725 *sigerror = PR_TRUE;
727 if ( PORT_GetError() == SEC_ERROR_EXPIRED_CERTIFICATE ) {
728 PORT_SetError(SEC_ERROR_EXPIRED_ISSUER_CERTIFICATE);
729 LOG_ERROR_OR_EXIT(log,issuerCert,count+1,0);
730 } else {
731 PORT_SetError(SEC_ERROR_BAD_SIGNATURE);
732 LOG_ERROR_OR_EXIT(log,subjectCert,count,0);
738 * XXX - fortezza may need error logging stuff added
740 if (isFortezzaV1) {
741 rv = cert_VerifyFortezzaV1Cert(handle, issuerCert, &last_type,
742 last_type, t, wincx);
743 if (rv == SECFailure) {
744 /**** PORT_SetError is already set by *
745 * cert_VerifyFortezzaV1Cert **/
746 LOG_ERROR_OR_EXIT(log,subjectCert,0,0);
750 /* If the basicConstraint extension is included in an immediate CA
751 * certificate, make sure that the isCA flag is on. If the
752 * pathLenConstraint component exists, it must be greater than the
753 * number of CA certificates we have seen so far. If the extension
754 * is omitted, we will assume that this is a CA certificate with
755 * an unlimited pathLenConstraint (since it already passes the
756 * netscape-cert-type extension checking).
758 * In the fortezza (V1) case, we've already checked the CA bits
759 * in the key, so we're presumed to be a CA; however we really don't
760 * want to bypass Basic constraint or netscape extension parsing.
762 * In Fortezza V2, basicConstraint will be set for every CA,PCA,PAA
765 rv = CERT_FindBasicConstraintExten(issuerCert, &basicConstraint);
766 if ( rv != SECSuccess ) {
767 if (PORT_GetError() != SEC_ERROR_EXTENSION_NOT_FOUND) {
768 LOG_ERROR_OR_EXIT(log,issuerCert,count+1,0);
770 pathLengthLimit = CERT_UNLIMITED_PATH_CONSTRAINT;
771 /* no basic constraints found, if we're fortezza, CA bit is already
772 * verified (isca = PR_TRUE). otherwise, we aren't (yet) a ca
773 * isca = PR_FALSE */
774 isca = isFortezzaV1;
775 } else {
776 if ( basicConstraint.isCA == PR_FALSE ) {
777 PORT_SetError (SEC_ERROR_CA_CERT_INVALID);
778 LOG_ERROR_OR_EXIT(log,issuerCert,count+1,0);
780 pathLengthLimit = basicConstraint.pathLenConstraint;
781 isca = PR_TRUE;
783 /* make sure that the path len constraint is properly set.*/
784 if (pathLengthLimit >= 0 && currentPathLen > pathLengthLimit) {
785 PORT_SetError (SEC_ERROR_PATH_LEN_CONSTRAINT_INVALID);
786 LOG_ERROR_OR_EXIT(log, issuerCert, count+1, pathLengthLimit);
789 /* XXX - the error logging may need to go down into CRL stuff at some
790 * point
792 /* check revoked list (issuer) */
793 rv = SEC_CheckCRL(handle, subjectCert, issuerCert, t, wincx);
794 if (rv == SECFailure) {
795 if (revoked) {
796 *revoked = PR_TRUE;
798 LOG_ERROR_OR_EXIT(log,subjectCert,count,0);
799 } else if (rv == SECWouldBlock) {
800 /* We found something fishy, so we intend to issue an
801 * error to the user, but the user may wish to continue
802 * processing, in which case we better make sure nothing
803 * worse has happened... so keep cranking the loop */
804 rvFinal = SECFailure;
805 if (revoked) {
806 *revoked = PR_TRUE;
808 LOG_ERROR(log,subjectCert,count,0);
811 if ( issuerCert->trust ) {
812 /* we have some trust info, but this does NOT imply that this
813 * cert is actually trusted for any purpose. The cert may be
814 * explicitly UNtrusted. We won't know until we examine the
815 * trust bits.
817 if (certUsage == certUsageStatusResponder) {
818 /* XXX NSS has done this for years, but it seems incorrect. */
819 rv = rvFinal;
820 goto done;
824 * check the trust parms of the issuer
826 if ( certUsage == certUsageVerifyCA ) {
827 if ( subjectCert->nsCertType & NS_CERT_TYPE_EMAIL_CA ) {
828 trustType = trustEmail;
829 } else if ( subjectCert->nsCertType & NS_CERT_TYPE_SSL_CA ) {
830 trustType = trustSSL;
831 } else {
832 trustType = trustObjectSigning;
836 flags = SEC_GET_TRUST_FLAGS(issuerCert->trust, trustType);
838 if (flags & CERTDB_VALID_CA) {
839 if ( ( flags & requiredFlags ) == requiredFlags) {
840 /* we found a trusted one, so return */
841 rv = rvFinal;
842 goto done;
844 validCAOverride = PR_TRUE;
848 if (!validCAOverride) {
850 * Make sure that if this is an intermediate CA in the chain that
851 * it was given permission by its signer to be a CA.
854 * if basicConstraints says it is a ca, then we check the
855 * nsCertType. If the nsCertType has any CA bits set, then
856 * it must have the right one.
858 if (!isca || (issuerCert->nsCertType & NS_CERT_TYPE_CA)) {
859 isca = (issuerCert->nsCertType & caCertType) ? PR_TRUE : PR_FALSE;
862 if ( !isca ) {
863 PORT_SetError(SEC_ERROR_CA_CERT_INVALID);
864 LOG_ERROR_OR_EXIT(log,issuerCert,count+1,0);
867 /* make sure key usage allows cert signing */
868 if (CERT_CheckKeyUsage(issuerCert, requiredCAKeyUsage) != SECSuccess) {
869 PORT_SetError(SEC_ERROR_INADEQUATE_KEY_USAGE);
870 LOG_ERROR_OR_EXIT(log,issuerCert,count+1,requiredCAKeyUsage);
874 /* make sure that the entire chain is within the name space of the
875 ** current issuer certificate.
877 rv = CERT_CompareNameSpace(issuerCert, namesList, certsList,
878 arena, &badCert);
879 if (rv != SECSuccess || badCert != NULL) {
880 PORT_SetError(SEC_ERROR_CERT_NOT_IN_NAME_SPACE);
881 LOG_ERROR_OR_EXIT(log, badCert, count + 1, 0);
882 goto loser;
884 /* make sure that the issuer is not self signed. If it is, then
885 * stop here to prevent looping.
887 if (issuerCert->isRoot) {
888 PORT_SetError(SEC_ERROR_UNTRUSTED_ISSUER);
889 LOG_ERROR(log, issuerCert, count+1, 0);
890 goto loser;
892 /* The issuer cert will be the subject cert in the next loop.
893 * A cert is self-issued if its subject and issuer are equal and
894 * both are of non-zero length.
896 subjectCertIsSelfIssued = (PRBool)
897 SECITEM_ItemsAreEqual(&issuerCert->derIssuer,
898 &issuerCert->derSubject) &&
899 issuerCert->derSubject.len > 0;
900 if (subjectCertIsSelfIssued == PR_FALSE) {
901 /* RFC 3280 says only non-self-issued intermediate CA certs
902 * count in path length.
904 ++currentPathLen;
907 CERT_DestroyCertificate(subjectCert);
908 subjectCert = issuerCert;
909 issuerCert = NULL;
912 PORT_SetError(SEC_ERROR_UNKNOWN_ISSUER);
913 LOG_ERROR(log,subjectCert,count,0);
914 loser:
915 rv = SECFailure;
916 done:
917 if (certsList != NULL) {
918 PORT_Free(certsList);
920 if ( issuerCert ) {
921 CERT_DestroyCertificate(issuerCert);
924 if ( subjectCert ) {
925 CERT_DestroyCertificate(subjectCert);
928 if ( arena != NULL ) {
929 PORT_FreeArena(arena, PR_FALSE);
931 return rv;
934 SECStatus
935 CERT_VerifyCertChain(CERTCertDBHandle *handle, CERTCertificate *cert,
936 PRBool checkSig, SECCertUsage certUsage, int64 t,
937 void *wincx, CERTVerifyLog *log)
939 return cert_VerifyCertChain(handle, cert, checkSig, NULL, certUsage, t,
940 wincx, log, NULL);
944 * verify that a CA can sign a certificate with the requested usage.
945 * XXX This function completely ignores cert path length constraints!
947 SECStatus
948 CERT_VerifyCACertForUsage(CERTCertDBHandle *handle, CERTCertificate *cert,
949 PRBool checkSig, SECCertUsage certUsage, int64 t,
950 void *wincx, CERTVerifyLog *log)
952 SECTrustType trustType;
953 CERTBasicConstraints basicConstraint;
954 PRBool isca;
955 PRBool validCAOverride = PR_FALSE;
956 SECStatus rv;
957 SECComparison rvCompare;
958 SECStatus rvFinal = SECSuccess;
959 int flags;
960 unsigned int caCertType;
961 unsigned int requiredCAKeyUsage;
962 unsigned int requiredFlags;
963 CERTCertificate *issuerCert;
966 if (CERT_KeyUsageAndTypeForCertUsage(certUsage, PR_TRUE,
967 &requiredCAKeyUsage,
968 &caCertType) != SECSuccess ) {
969 PORT_Assert(0);
970 EXIT_IF_NOT_LOGGING(log);
971 requiredCAKeyUsage = 0;
972 caCertType = 0;
975 switch ( certUsage ) {
976 case certUsageSSLClient:
977 case certUsageSSLServer:
978 case certUsageSSLCA:
979 case certUsageSSLServerWithStepUp:
980 case certUsageEmailSigner:
981 case certUsageEmailRecipient:
982 case certUsageObjectSigner:
983 case certUsageVerifyCA:
984 case certUsageStatusResponder:
985 if ( CERT_TrustFlagsForCACertUsage(certUsage, &requiredFlags,
986 &trustType) != SECSuccess ) {
987 PORT_Assert(0);
988 EXIT_IF_NOT_LOGGING(log);
989 requiredFlags = 0;
990 trustType = trustSSL;
992 break;
993 default:
994 PORT_Assert(0);
995 EXIT_IF_NOT_LOGGING(log);
996 requiredFlags = 0;
997 trustType = trustSSL;/* This used to be 0, but we need something
998 * that matches the enumeration type.
1000 caCertType = 0;
1003 /* If the basicConstraint extension is included in an intermmediate CA
1004 * certificate, make sure that the isCA flag is on. If the
1005 * pathLenConstraint component exists, it must be greater than the
1006 * number of CA certificates we have seen so far. If the extension
1007 * is omitted, we will assume that this is a CA certificate with
1008 * an unlimited pathLenConstraint (since it already passes the
1009 * netscape-cert-type extension checking).
1011 * In the fortezza (V1) case, we've already checked the CA bits
1012 * in the key, so we're presumed to be a CA; however we really don't
1013 * want to bypass Basic constraint or netscape extension parsing.
1015 * In Fortezza V2, basicConstraint will be set for every CA,PCA,PAA
1018 rv = CERT_FindBasicConstraintExten(cert, &basicConstraint);
1019 if ( rv != SECSuccess ) {
1020 if (PORT_GetError() != SEC_ERROR_EXTENSION_NOT_FOUND) {
1021 LOG_ERROR_OR_EXIT(log,cert,0,0);
1023 /* no basic constraints found, if we're fortezza, CA bit is already
1024 * verified (isca = PR_TRUE). otherwise, we aren't (yet) a ca
1025 * isca = PR_FALSE */
1026 isca = PR_FALSE;
1027 } else {
1028 if ( basicConstraint.isCA == PR_FALSE ) {
1029 PORT_SetError (SEC_ERROR_CA_CERT_INVALID);
1030 LOG_ERROR_OR_EXIT(log,cert,0,0);
1033 /* can't check path length if we don't know the previous path */
1034 isca = PR_TRUE;
1037 if ( cert->trust ) {
1038 /* we have some trust info, but this does NOT imply that this
1039 * cert is actually trusted for any purpose. The cert may be
1040 * explicitly UNtrusted. We won't know until we examine the
1041 * trust bits.
1043 if (certUsage == certUsageStatusResponder) {
1044 /* Check the special case of certUsageStatusResponder */
1045 issuerCert = CERT_FindCertIssuer(cert, t, certUsage);
1046 if (issuerCert) {
1047 if (SEC_CheckCRL(handle, cert, issuerCert, t, wincx)
1048 != SECSuccess) {
1049 PORT_SetError(SEC_ERROR_REVOKED_CERTIFICATE);
1050 CERT_DestroyCertificate(issuerCert);
1051 goto loser;
1053 CERT_DestroyCertificate(issuerCert);
1055 /* XXX We have NOT determined that this cert is trusted.
1056 * For years, NSS has treated this as trusted,
1057 * but it seems incorrect.
1059 rv = rvFinal;
1060 goto done;
1064 * check the trust parms of the issuer
1066 flags = SEC_GET_TRUST_FLAGS(cert->trust, trustType);
1068 if (flags & CERTDB_VALID_CA) {
1069 if ( ( flags & requiredFlags ) == requiredFlags) {
1070 /* we found a trusted one, so return */
1071 rv = rvFinal;
1072 goto done;
1074 validCAOverride = PR_TRUE;
1077 if (!validCAOverride) {
1079 * Make sure that if this is an intermediate CA in the chain that
1080 * it was given permission by its signer to be a CA.
1083 * if basicConstraints says it is a ca, then we check the
1084 * nsCertType. If the nsCertType has any CA bits set, then
1085 * it must have the right one.
1087 if (!isca || (cert->nsCertType & NS_CERT_TYPE_CA)) {
1088 isca = (cert->nsCertType & caCertType) ? PR_TRUE : PR_FALSE;
1091 if (!isca) {
1092 PORT_SetError(SEC_ERROR_CA_CERT_INVALID);
1093 LOG_ERROR_OR_EXIT(log,cert,0,0);
1096 /* make sure key usage allows cert signing */
1097 if (CERT_CheckKeyUsage(cert, requiredCAKeyUsage) != SECSuccess) {
1098 PORT_SetError(SEC_ERROR_INADEQUATE_KEY_USAGE);
1099 LOG_ERROR_OR_EXIT(log,cert,0,requiredCAKeyUsage);
1102 /* make sure that the issuer is not self signed. If it is, then
1103 * stop here to prevent looping.
1105 rvCompare = SECITEM_CompareItem(&cert->derSubject, &cert->derIssuer);
1106 if (rvCompare == SECEqual) {
1107 PORT_SetError(SEC_ERROR_UNTRUSTED_ISSUER);
1108 LOG_ERROR(log, cert, 0, 0);
1109 goto loser;
1112 return CERT_VerifyCertChain(handle, cert, checkSig, certUsage, t,
1113 wincx, log);
1114 loser:
1115 rv = SECFailure;
1116 done:
1117 return rv;
1120 #define NEXT_USAGE() { \
1121 i*=2; \
1122 certUsage++; \
1123 continue; \
1126 #define VALID_USAGE() { \
1127 NEXT_USAGE(); \
1130 #define INVALID_USAGE() { \
1131 if (returnedUsages) { \
1132 *returnedUsages &= (~i); \
1134 if (PR_TRUE == requiredUsage) { \
1135 valid = SECFailure; \
1137 NEXT_USAGE(); \
1141 * verify a certificate by checking if it's valid and that we
1142 * trust the issuer.
1144 * certificateUsage contains a bitfield of all cert usages that are
1145 * required for verification to succeed
1147 * a bitfield of cert usages is returned in *returnedUsages
1148 * if requiredUsages is non-zero, the returned bitmap is only
1149 * for those required usages, otherwise it is for all usages
1152 SECStatus
1153 CERT_VerifyCertificate(CERTCertDBHandle *handle, CERTCertificate *cert,
1154 PRBool checkSig, SECCertificateUsage requiredUsages, int64 t,
1155 void *wincx, CERTVerifyLog *log, SECCertificateUsage* returnedUsages)
1157 SECStatus rv;
1158 SECStatus valid;
1159 unsigned int requiredKeyUsage;
1160 unsigned int requiredCertType;
1161 unsigned int flags;
1162 unsigned int certType;
1163 PRBool allowOverride;
1164 SECCertTimeValidity validity;
1165 CERTStatusConfig *statusConfig;
1166 PRInt32 i;
1167 SECCertUsage certUsage = 0;
1168 PRBool checkedOCSP = PR_FALSE;
1169 PRBool checkAllUsages = PR_FALSE;
1170 PRBool revoked = PR_FALSE;
1171 PRBool sigerror = PR_FALSE;
1173 if (!requiredUsages) {
1174 /* there are no required usages, so the user probably wants to
1175 get status for all usages */
1176 checkAllUsages = PR_TRUE;
1179 if (returnedUsages) {
1180 *returnedUsages = 0;
1181 } else {
1182 /* we don't have a place to return status for all usages,
1183 so we can skip checks for usages that aren't required */
1184 checkAllUsages = PR_FALSE;
1186 valid = SECSuccess ; /* start off assuming cert is valid */
1188 /* make sure that the cert is valid at time t */
1189 allowOverride = (PRBool)((requiredUsages & certificateUsageSSLServer) ||
1190 (requiredUsages & certificateUsageSSLServerWithStepUp));
1191 validity = CERT_CheckCertValidTimes(cert, t, allowOverride);
1192 if ( validity != secCertTimeValid ) {
1193 valid = SECFailure;
1194 LOG_ERROR_OR_EXIT(log,cert,0,validity);
1197 /* check key usage and netscape cert type */
1198 cert_GetCertType(cert);
1199 certType = cert->nsCertType;
1201 for (i=1; i<=certificateUsageHighest &&
1202 (SECSuccess == valid || returnedUsages || log) ; ) {
1203 PRBool requiredUsage = (i & requiredUsages) ? PR_TRUE : PR_FALSE;
1204 if (PR_FALSE == requiredUsage && PR_FALSE == checkAllUsages) {
1205 NEXT_USAGE();
1207 if (returnedUsages) {
1208 *returnedUsages |= i; /* start off assuming this usage is valid */
1210 switch ( certUsage ) {
1211 case certUsageSSLClient:
1212 case certUsageSSLServer:
1213 case certUsageSSLServerWithStepUp:
1214 case certUsageSSLCA:
1215 case certUsageEmailSigner:
1216 case certUsageEmailRecipient:
1217 case certUsageObjectSigner:
1218 case certUsageStatusResponder:
1219 rv = CERT_KeyUsageAndTypeForCertUsage(certUsage, PR_FALSE,
1220 &requiredKeyUsage,
1221 &requiredCertType);
1222 if ( rv != SECSuccess ) {
1223 PORT_Assert(0);
1224 /* EXIT_IF_NOT_LOGGING(log); XXX ??? */
1225 requiredKeyUsage = 0;
1226 requiredCertType = 0;
1227 INVALID_USAGE();
1229 break;
1231 case certUsageAnyCA:
1232 case certUsageProtectedObjectSigner:
1233 case certUsageUserCertImport:
1234 case certUsageVerifyCA:
1235 /* these usages cannot be verified */
1236 NEXT_USAGE();
1238 default:
1239 PORT_Assert(0);
1240 requiredKeyUsage = 0;
1241 requiredCertType = 0;
1242 INVALID_USAGE();
1244 if ( CERT_CheckKeyUsage(cert, requiredKeyUsage) != SECSuccess ) {
1245 if (PR_TRUE == requiredUsage) {
1246 PORT_SetError(SEC_ERROR_INADEQUATE_KEY_USAGE);
1248 LOG_ERROR(log,cert,0,requiredKeyUsage);
1249 INVALID_USAGE();
1251 if ( !( certType & requiredCertType ) ) {
1252 if (PR_TRUE == requiredUsage) {
1253 PORT_SetError(SEC_ERROR_INADEQUATE_CERT_TYPE);
1255 LOG_ERROR(log,cert,0,requiredCertType);
1256 INVALID_USAGE();
1259 /* check trust flags to see if this cert is directly trusted */
1260 if ( cert->trust ) { /* the cert is in the DB */
1261 switch ( certUsage ) {
1262 case certUsageSSLClient:
1263 case certUsageSSLServer:
1264 flags = cert->trust->sslFlags;
1266 /* is the cert directly trusted or not trusted ? */
1267 if ( flags & CERTDB_VALID_PEER ) {/*the trust record is valid*/
1268 if ( flags & CERTDB_TRUSTED ) { /* trust this cert */
1269 VALID_USAGE();
1270 } else { /* don't trust this cert */
1271 if (PR_TRUE == requiredUsage) {
1272 PORT_SetError(SEC_ERROR_UNTRUSTED_CERT);
1274 LOG_ERROR(log,cert,0,flags);
1275 INVALID_USAGE();
1278 break;
1279 case certUsageSSLServerWithStepUp:
1280 /* XXX - step up certs can't be directly trusted */
1281 break;
1282 case certUsageSSLCA:
1283 break;
1284 case certUsageEmailSigner:
1285 case certUsageEmailRecipient:
1286 flags = cert->trust->emailFlags;
1288 /* is the cert directly trusted or not trusted ? */
1289 if ( ( flags & ( CERTDB_VALID_PEER | CERTDB_TRUSTED ) ) ==
1290 ( CERTDB_VALID_PEER | CERTDB_TRUSTED ) ) {
1291 VALID_USAGE();
1293 break;
1294 case certUsageObjectSigner:
1295 flags = cert->trust->objectSigningFlags;
1297 /* is the cert directly trusted or not trusted ? */
1298 if ( flags & CERTDB_VALID_PEER ) {/*the trust record is valid*/
1299 if ( flags & CERTDB_TRUSTED ) { /* trust this cert */
1300 VALID_USAGE();
1301 } else { /* don't trust this cert */
1302 if (PR_TRUE == requiredUsage) {
1303 PORT_SetError(SEC_ERROR_UNTRUSTED_CERT);
1305 LOG_ERROR(log,cert,0,flags);
1306 INVALID_USAGE();
1309 break;
1310 case certUsageVerifyCA:
1311 case certUsageStatusResponder:
1312 flags = cert->trust->sslFlags;
1313 /* is the cert directly trusted or not trusted ? */
1314 if ( ( flags & ( CERTDB_VALID_CA | CERTDB_TRUSTED_CA ) ) ==
1315 ( CERTDB_VALID_CA | CERTDB_TRUSTED_CA ) ) {
1316 VALID_USAGE();
1318 flags = cert->trust->emailFlags;
1319 /* is the cert directly trusted or not trusted ? */
1320 if ( ( flags & ( CERTDB_VALID_CA | CERTDB_TRUSTED_CA ) ) ==
1321 ( CERTDB_VALID_CA | CERTDB_TRUSTED_CA ) ) {
1322 VALID_USAGE();
1324 flags = cert->trust->objectSigningFlags;
1325 /* is the cert directly trusted or not trusted ? */
1326 if ( ( flags & ( CERTDB_VALID_CA | CERTDB_TRUSTED_CA ) ) ==
1327 ( CERTDB_VALID_CA | CERTDB_TRUSTED_CA ) ) {
1328 VALID_USAGE();
1330 break;
1331 case certUsageAnyCA:
1332 case certUsageProtectedObjectSigner:
1333 case certUsageUserCertImport:
1334 /* XXX to make the compiler happy. Should these be
1335 * explicitly handled?
1337 break;
1341 if (PR_TRUE == revoked || PR_TRUE == sigerror) {
1342 INVALID_USAGE();
1345 rv = cert_VerifyCertChain(handle, cert,
1346 checkSig, &sigerror,
1347 certUsage, t, wincx, log,
1348 &revoked);
1350 if (rv != SECSuccess) {
1351 /* EXIT_IF_NOT_LOGGING(log); XXX ???? */
1352 INVALID_USAGE();
1356 * Check OCSP revocation status, but only if the cert we are checking
1357 * is not a status reponder itself. We only do this in the case
1358 * where we checked the cert chain (above); explicit trust "wins"
1359 * (avoids status checking, just as it avoids CRL checking) by
1360 * bypassing this code.
1363 if (PR_FALSE == checkedOCSP) {
1364 checkedOCSP = PR_TRUE; /* only check OCSP once */
1365 statusConfig = CERT_GetStatusConfig(handle);
1366 if (requiredUsages != certificateUsageStatusResponder &&
1367 statusConfig != NULL) {
1368 if (statusConfig->statusChecker != NULL) {
1369 rv = (* statusConfig->statusChecker)(handle, cert,
1370 t, wincx);
1371 if (rv != SECSuccess) {
1372 LOG_ERROR(log,cert,0,0);
1373 revoked = PR_TRUE;
1374 INVALID_USAGE();
1380 NEXT_USAGE();
1383 loser:
1384 return(valid);
1387 /* obsolete, do not use for new code */
1388 SECStatus
1389 CERT_VerifyCert(CERTCertDBHandle *handle, CERTCertificate *cert,
1390 PRBool checkSig, SECCertUsage certUsage, int64 t,
1391 void *wincx, CERTVerifyLog *log)
1393 SECStatus rv;
1394 unsigned int requiredKeyUsage;
1395 unsigned int requiredCertType;
1396 unsigned int flags;
1397 unsigned int certType;
1398 PRBool allowOverride;
1399 SECCertTimeValidity validity;
1400 CERTStatusConfig *statusConfig;
1402 #ifdef notdef
1403 /* check if this cert is in the Evil list */
1404 rv = CERT_CheckForEvilCert(cert);
1405 if ( rv != SECSuccess ) {
1406 PORT_SetError(SEC_ERROR_REVOKED_CERTIFICATE);
1407 LOG_ERROR_OR_EXIT(log,cert,0,0);
1409 #endif
1411 /* make sure that the cert is valid at time t */
1412 allowOverride = (PRBool)((certUsage == certUsageSSLServer) ||
1413 (certUsage == certUsageSSLServerWithStepUp));
1414 validity = CERT_CheckCertValidTimes(cert, t, allowOverride);
1415 if ( validity != secCertTimeValid ) {
1416 LOG_ERROR_OR_EXIT(log,cert,0,validity);
1419 /* check key usage and netscape cert type */
1420 cert_GetCertType(cert);
1421 certType = cert->nsCertType;
1422 switch ( certUsage ) {
1423 case certUsageSSLClient:
1424 case certUsageSSLServer:
1425 case certUsageSSLServerWithStepUp:
1426 case certUsageSSLCA:
1427 case certUsageEmailSigner:
1428 case certUsageEmailRecipient:
1429 case certUsageObjectSigner:
1430 case certUsageStatusResponder:
1431 rv = CERT_KeyUsageAndTypeForCertUsage(certUsage, PR_FALSE,
1432 &requiredKeyUsage,
1433 &requiredCertType);
1434 if ( rv != SECSuccess ) {
1435 PORT_Assert(0);
1436 EXIT_IF_NOT_LOGGING(log);
1437 requiredKeyUsage = 0;
1438 requiredCertType = 0;
1440 break;
1441 case certUsageVerifyCA:
1442 requiredKeyUsage = KU_KEY_CERT_SIGN;
1443 requiredCertType = NS_CERT_TYPE_CA;
1444 if ( ! ( certType & NS_CERT_TYPE_CA ) ) {
1445 certType |= NS_CERT_TYPE_CA;
1447 break;
1448 default:
1449 PORT_Assert(0);
1450 EXIT_IF_NOT_LOGGING(log);
1451 requiredKeyUsage = 0;
1452 requiredCertType = 0;
1454 if ( CERT_CheckKeyUsage(cert, requiredKeyUsage) != SECSuccess ) {
1455 PORT_SetError(SEC_ERROR_INADEQUATE_KEY_USAGE);
1456 LOG_ERROR_OR_EXIT(log,cert,0,requiredKeyUsage);
1458 if ( !( certType & requiredCertType ) ) {
1459 PORT_SetError(SEC_ERROR_INADEQUATE_CERT_TYPE);
1460 LOG_ERROR_OR_EXIT(log,cert,0,requiredCertType);
1463 /* check trust flags to see if this cert is directly trusted */
1464 if ( cert->trust ) { /* the cert is in the DB */
1465 switch ( certUsage ) {
1466 case certUsageSSLClient:
1467 case certUsageSSLServer:
1468 flags = cert->trust->sslFlags;
1470 /* is the cert directly trusted or not trusted ? */
1471 if ( flags & CERTDB_VALID_PEER ) {/*the trust record is valid*/
1472 if ( flags & CERTDB_TRUSTED ) { /* trust this cert */
1473 goto winner;
1474 } else { /* don't trust this cert */
1475 PORT_SetError(SEC_ERROR_UNTRUSTED_CERT);
1476 LOG_ERROR_OR_EXIT(log,cert,0,flags);
1479 break;
1480 case certUsageSSLServerWithStepUp:
1481 /* XXX - step up certs can't be directly trusted */
1482 break;
1483 case certUsageSSLCA:
1484 break;
1485 case certUsageEmailSigner:
1486 case certUsageEmailRecipient:
1487 flags = cert->trust->emailFlags;
1489 /* is the cert directly trusted or not trusted ? */
1490 if ( ( flags & ( CERTDB_VALID_PEER | CERTDB_TRUSTED ) ) ==
1491 ( CERTDB_VALID_PEER | CERTDB_TRUSTED ) ) {
1492 goto winner;
1494 break;
1495 case certUsageObjectSigner:
1496 flags = cert->trust->objectSigningFlags;
1498 /* is the cert directly trusted or not trusted ? */
1499 if ( flags & CERTDB_VALID_PEER ) {/*the trust record is valid*/
1500 if ( flags & CERTDB_TRUSTED ) { /* trust this cert */
1501 goto winner;
1502 } else { /* don't trust this cert */
1503 PORT_SetError(SEC_ERROR_UNTRUSTED_CERT);
1504 LOG_ERROR_OR_EXIT(log,cert,0,flags);
1507 break;
1508 case certUsageVerifyCA:
1509 case certUsageStatusResponder:
1510 flags = cert->trust->sslFlags;
1511 /* is the cert directly trusted or not trusted ? */
1512 if ( ( flags & ( CERTDB_VALID_CA | CERTDB_TRUSTED_CA ) ) ==
1513 ( CERTDB_VALID_CA | CERTDB_TRUSTED_CA ) ) {
1514 goto winner;
1516 flags = cert->trust->emailFlags;
1517 /* is the cert directly trusted or not trusted ? */
1518 if ( ( flags & ( CERTDB_VALID_CA | CERTDB_TRUSTED_CA ) ) ==
1519 ( CERTDB_VALID_CA | CERTDB_TRUSTED_CA ) ) {
1520 goto winner;
1522 flags = cert->trust->objectSigningFlags;
1523 /* is the cert directly trusted or not trusted ? */
1524 if ( ( flags & ( CERTDB_VALID_CA | CERTDB_TRUSTED_CA ) ) ==
1525 ( CERTDB_VALID_CA | CERTDB_TRUSTED_CA ) ) {
1526 goto winner;
1528 break;
1529 case certUsageAnyCA:
1530 case certUsageProtectedObjectSigner:
1531 case certUsageUserCertImport:
1532 /* XXX to make the compiler happy. Should these be
1533 * explicitly handled?
1535 break;
1539 rv = CERT_VerifyCertChain(handle, cert, checkSig, certUsage,
1540 t, wincx, log);
1541 if (rv != SECSuccess) {
1542 EXIT_IF_NOT_LOGGING(log);
1546 * Check revocation status, but only if the cert we are checking
1547 * is not a status reponder itself. We only do this in the case
1548 * where we checked the cert chain (above); explicit trust "wins"
1549 * (avoids status checking, just as it avoids CRL checking, which
1550 * is all done inside VerifyCertChain) by bypassing this code.
1552 statusConfig = CERT_GetStatusConfig(handle);
1553 if (certUsage != certUsageStatusResponder && statusConfig != NULL) {
1554 if (statusConfig->statusChecker != NULL) {
1555 rv = (* statusConfig->statusChecker)(handle, cert,
1556 t, wincx);
1557 if (rv != SECSuccess) {
1558 LOG_ERROR_OR_EXIT(log,cert,0,0);
1563 winner:
1564 return(SECSuccess);
1566 loser:
1567 rv = SECFailure;
1569 return(rv);
1573 * verify a certificate by checking if its valid and that we
1574 * trust the issuer. Verify time against now.
1576 SECStatus
1577 CERT_VerifyCertificateNow(CERTCertDBHandle *handle, CERTCertificate *cert,
1578 PRBool checkSig, SECCertificateUsage requiredUsages,
1579 void *wincx, SECCertificateUsage* returnedUsages)
1581 return(CERT_VerifyCertificate(handle, cert, checkSig,
1582 requiredUsages, PR_Now(), wincx, NULL, returnedUsages));
1585 /* obsolete, do not use for new code */
1586 SECStatus
1587 CERT_VerifyCertNow(CERTCertDBHandle *handle, CERTCertificate *cert,
1588 PRBool checkSig, SECCertUsage certUsage, void *wincx)
1590 return(CERT_VerifyCert(handle, cert, checkSig,
1591 certUsage, PR_Now(), wincx, NULL));
1595 /* [ FROM pcertdb.c ] */
1597 * Supported usage values and types:
1598 * certUsageSSLClient
1599 * certUsageSSLServer
1600 * certUsageSSLServerWithStepUp
1601 * certUsageEmailSigner
1602 * certUsageEmailRecipient
1603 * certUsageObjectSigner
1606 CERTCertificate *
1607 CERT_FindMatchingCert(CERTCertDBHandle *handle, SECItem *derName,
1608 CERTCertOwner owner, SECCertUsage usage,
1609 PRBool preferTrusted, int64 validTime, PRBool validOnly)
1611 CERTCertList *certList = NULL;
1612 CERTCertificate *cert = NULL;
1613 unsigned int requiredTrustFlags;
1614 SECTrustType requiredTrustType;
1615 unsigned int flags;
1617 PRBool lookingForCA = PR_FALSE;
1618 SECStatus rv;
1619 CERTCertListNode *node;
1620 CERTCertificate *saveUntrustedCA = NULL;
1622 /* if preferTrusted is set, must be a CA cert */
1623 PORT_Assert( ! ( preferTrusted && ( owner != certOwnerCA ) ) );
1625 if ( owner == certOwnerCA ) {
1626 lookingForCA = PR_TRUE;
1627 if ( preferTrusted ) {
1628 rv = CERT_TrustFlagsForCACertUsage(usage, &requiredTrustFlags,
1629 &requiredTrustType);
1630 if ( rv != SECSuccess ) {
1631 goto loser;
1633 requiredTrustFlags |= CERTDB_VALID_CA;
1637 certList = CERT_CreateSubjectCertList(NULL, handle, derName, validTime,
1638 validOnly);
1639 if ( certList != NULL ) {
1640 rv = CERT_FilterCertListByUsage(certList, usage, lookingForCA);
1641 if ( rv != SECSuccess ) {
1642 goto loser;
1645 node = CERT_LIST_HEAD(certList);
1647 while ( !CERT_LIST_END(node, certList) ) {
1648 cert = node->cert;
1650 /* looking for a trusted CA cert */
1651 if ( ( owner == certOwnerCA ) && preferTrusted &&
1652 ( requiredTrustType != trustTypeNone ) ) {
1654 if ( cert->trust == NULL ) {
1655 flags = 0;
1656 } else {
1657 flags = SEC_GET_TRUST_FLAGS(cert->trust, requiredTrustType);
1660 if ( ( flags & requiredTrustFlags ) != requiredTrustFlags ) {
1661 /* cert is not trusted */
1662 /* if this is the first cert to get this far, then save
1663 * it, so we can use it if we can't find a trusted one
1665 if ( saveUntrustedCA == NULL ) {
1666 saveUntrustedCA = cert;
1668 goto endloop;
1671 /* if we got this far, then this cert meets all criteria */
1672 break;
1674 endloop:
1675 node = CERT_LIST_NEXT(node);
1676 cert = NULL;
1679 /* use the saved one if we have it */
1680 if ( cert == NULL ) {
1681 cert = saveUntrustedCA;
1684 /* if we found one then bump the ref count before freeing the list */
1685 if ( cert != NULL ) {
1686 /* bump the ref count */
1687 cert = CERT_DupCertificate(cert);
1690 CERT_DestroyCertList(certList);
1693 return(cert);
1695 loser:
1696 if ( certList != NULL ) {
1697 CERT_DestroyCertList(certList);
1700 return(NULL);
1704 /* [ From certdb.c ] */
1706 * Filter a list of certificates, removing those certs that do not have
1707 * one of the named CA certs somewhere in their cert chain.
1709 * "certList" - the list of certificates to filter
1710 * "nCANames" - number of CA names
1711 * "caNames" - array of CA names in string(rfc 1485) form
1712 * "usage" - what use the certs are for, this is used when
1713 * selecting CA certs
1715 SECStatus
1716 CERT_FilterCertListByCANames(CERTCertList *certList, int nCANames,
1717 char **caNames, SECCertUsage usage)
1719 CERTCertificate *issuerCert = NULL;
1720 CERTCertificate *subjectCert;
1721 CERTCertListNode *node, *freenode;
1722 CERTCertificate *cert;
1723 int n;
1724 char **names;
1725 PRBool found;
1726 int64 time;
1728 if ( nCANames <= 0 ) {
1729 return(SECSuccess);
1732 time = PR_Now();
1734 node = CERT_LIST_HEAD(certList);
1736 while ( ! CERT_LIST_END(node, certList) ) {
1737 cert = node->cert;
1739 subjectCert = CERT_DupCertificate(cert);
1741 /* traverse the CA certs for this cert */
1742 found = PR_FALSE;
1743 while ( subjectCert != NULL ) {
1744 n = nCANames;
1745 names = caNames;
1747 if (subjectCert->issuerName != NULL) {
1748 while ( n > 0 ) {
1749 if ( PORT_Strcmp(*names, subjectCert->issuerName) == 0 ) {
1750 found = PR_TRUE;
1751 break;
1754 n--;
1755 names++;
1759 if ( found ) {
1760 break;
1763 issuerCert = CERT_FindCertIssuer(subjectCert, time, usage);
1764 if ( issuerCert == subjectCert ) {
1765 CERT_DestroyCertificate(issuerCert);
1766 issuerCert = NULL;
1767 break;
1769 CERT_DestroyCertificate(subjectCert);
1770 subjectCert = issuerCert;
1773 CERT_DestroyCertificate(subjectCert);
1774 if ( !found ) {
1775 /* CA was not found, so remove this cert from the list */
1776 freenode = node;
1777 node = CERT_LIST_NEXT(node);
1778 CERT_RemoveCertListNode(freenode);
1779 } else {
1780 /* CA was found, so leave it in the list */
1781 node = CERT_LIST_NEXT(node);
1785 return(SECSuccess);
1789 * Given a certificate, return a string containing the nickname, and possibly
1790 * one of the validity strings, based on the current validity state of the
1791 * certificate.
1793 * "arena" - arena to allocate returned string from. If NULL, then heap
1794 * is used.
1795 * "cert" - the cert to get nickname from
1796 * "expiredString" - the string to append to the nickname if the cert is
1797 * expired.
1798 * "notYetGoodString" - the string to append to the nickname if the cert is
1799 * not yet good.
1801 char *
1802 CERT_GetCertNicknameWithValidity(PRArenaPool *arena, CERTCertificate *cert,
1803 char *expiredString, char *notYetGoodString)
1805 SECCertTimeValidity validity;
1806 char *nickname = NULL, *tmpstr = NULL;
1808 validity = CERT_CheckCertValidTimes(cert, PR_Now(), PR_FALSE);
1810 /* if the cert is good, then just use the nickname directly */
1811 if ( validity == secCertTimeValid ) {
1812 if ( arena == NULL ) {
1813 nickname = PORT_Strdup(cert->nickname);
1814 } else {
1815 nickname = PORT_ArenaStrdup(arena, cert->nickname);
1818 if ( nickname == NULL ) {
1819 goto loser;
1821 } else {
1823 /* if the cert is not valid, then tack one of the strings on the
1824 * end
1826 if ( validity == secCertTimeExpired ) {
1827 tmpstr = PR_smprintf("%s%s", cert->nickname,
1828 expiredString);
1829 } else if ( validity == secCertTimeNotValidYet ) {
1830 /* not yet valid */
1831 tmpstr = PR_smprintf("%s%s", cert->nickname,
1832 notYetGoodString);
1833 } else {
1834 /* undetermined */
1835 tmpstr = PR_smprintf("%s",
1836 "(NULL) (Validity Unknown)");
1839 if ( tmpstr == NULL ) {
1840 goto loser;
1843 if ( arena ) {
1844 /* copy the string into the arena and free the malloc'd one */
1845 nickname = PORT_ArenaStrdup(arena, tmpstr);
1846 PORT_Free(tmpstr);
1847 } else {
1848 nickname = tmpstr;
1850 if ( nickname == NULL ) {
1851 goto loser;
1854 return(nickname);
1856 loser:
1857 return(NULL);
1861 * Collect the nicknames from all certs in a CertList. If the cert is not
1862 * valid, append a string to that nickname.
1864 * "certList" - the list of certificates
1865 * "expiredString" - the string to append to the nickname of any expired cert
1866 * "notYetGoodString" - the string to append to the nickname of any cert
1867 * that is not yet valid
1869 CERTCertNicknames *
1870 CERT_NicknameStringsFromCertList(CERTCertList *certList, char *expiredString,
1871 char *notYetGoodString)
1873 CERTCertNicknames *names;
1874 PRArenaPool *arena;
1875 CERTCertListNode *node;
1876 char **nn;
1878 /* allocate an arena */
1879 arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
1880 if ( arena == NULL ) {
1881 return(NULL);
1884 /* allocate the structure */
1885 names = PORT_ArenaAlloc(arena, sizeof(CERTCertNicknames));
1886 if ( names == NULL ) {
1887 goto loser;
1890 /* init the structure */
1891 names->arena = arena;
1892 names->head = NULL;
1893 names->numnicknames = 0;
1894 names->nicknames = NULL;
1895 names->totallen = 0;
1897 /* count the certs in the list */
1898 node = CERT_LIST_HEAD(certList);
1899 while ( ! CERT_LIST_END(node, certList) ) {
1900 names->numnicknames++;
1901 node = CERT_LIST_NEXT(node);
1904 /* allocate nicknames array */
1905 names->nicknames = PORT_ArenaAlloc(arena,
1906 sizeof(char *) * names->numnicknames);
1907 if ( names->nicknames == NULL ) {
1908 goto loser;
1911 /* just in case printf can't deal with null strings */
1912 if (expiredString == NULL ) {
1913 expiredString = "";
1916 if ( notYetGoodString == NULL ) {
1917 notYetGoodString = "";
1920 /* traverse the list of certs and collect the nicknames */
1921 nn = names->nicknames;
1922 node = CERT_LIST_HEAD(certList);
1923 while ( ! CERT_LIST_END(node, certList) ) {
1924 *nn = CERT_GetCertNicknameWithValidity(arena, node->cert,
1925 expiredString,
1926 notYetGoodString);
1927 if ( *nn == NULL ) {
1928 goto loser;
1931 names->totallen += PORT_Strlen(*nn);
1933 nn++;
1934 node = CERT_LIST_NEXT(node);
1937 return(names);
1939 loser:
1940 PORT_FreeArena(arena, PR_FALSE);
1941 return(NULL);
1945 * Extract the nickname from a nickmake string that may have either
1946 * expiredString or notYetGoodString appended.
1948 * Args:
1949 * "namestring" - the string containing the nickname, and possibly
1950 * one of the validity label strings
1951 * "expiredString" - the expired validity label string
1952 * "notYetGoodString" - the not yet good validity label string
1954 * Returns the raw nickname
1956 char *
1957 CERT_ExtractNicknameString(char *namestring, char *expiredString,
1958 char *notYetGoodString)
1960 int explen, nyglen, namelen;
1961 int retlen;
1962 char *retstr;
1964 namelen = PORT_Strlen(namestring);
1965 explen = PORT_Strlen(expiredString);
1966 nyglen = PORT_Strlen(notYetGoodString);
1968 if ( namelen > explen ) {
1969 if ( PORT_Strcmp(expiredString, &namestring[namelen-explen]) == 0 ) {
1970 retlen = namelen - explen;
1971 retstr = (char *)PORT_Alloc(retlen+1);
1972 if ( retstr == NULL ) {
1973 goto loser;
1976 PORT_Memcpy(retstr, namestring, retlen);
1977 retstr[retlen] = '\0';
1978 goto done;
1982 if ( namelen > nyglen ) {
1983 if ( PORT_Strcmp(notYetGoodString, &namestring[namelen-nyglen]) == 0) {
1984 retlen = namelen - nyglen;
1985 retstr = (char *)PORT_Alloc(retlen+1);
1986 if ( retstr == NULL ) {
1987 goto loser;
1990 PORT_Memcpy(retstr, namestring, retlen);
1991 retstr[retlen] = '\0';
1992 goto done;
1996 /* if name string is shorter than either invalid string, then it must
1997 * be a raw nickname
1999 retstr = PORT_Strdup(namestring);
2001 done:
2002 return(retstr);
2004 loser:
2005 return(NULL);
2008 CERTCertList *
2009 CERT_GetCertChainFromCert(CERTCertificate *cert, int64 time, SECCertUsage usage)
2011 CERTCertList *chain = NULL;
2013 if (NULL == cert) {
2014 return NULL;
2017 cert = CERT_DupCertificate(cert);
2018 if (NULL == cert) {
2019 PORT_SetError(SEC_ERROR_NO_MEMORY);
2020 return NULL;
2023 chain = CERT_NewCertList();
2024 if (NULL == chain) {
2025 PORT_SetError(SEC_ERROR_NO_MEMORY);
2026 return NULL;
2029 while (cert != NULL) {
2030 if (SECSuccess != CERT_AddCertToListTail(chain, cert)) {
2031 /* return partial chain */
2032 PORT_SetError(SEC_ERROR_NO_MEMORY);
2033 return chain;
2036 if (SECITEM_CompareItem(&cert->derIssuer, &cert->derSubject)
2037 == SECEqual) {
2038 /* return complete chain */
2039 return chain;
2042 cert = CERT_FindCertIssuer(cert, time, usage);
2045 /* return partial chain */
2046 PORT_SetError(SEC_ERROR_UNKNOWN_ISSUER);
2047 return chain;