comparison nss/lib/certhigh/certvfy.c @ 0:1e5118fa0cb1

This is NSS with a Cmake Buildsyste To compile a static NSS library for Windows we've used the Chromium-NSS fork and added a Cmake buildsystem to compile it statically for Windows. See README.chromium for chromium changes and README.trustbridge for our modifications.
author Andre Heinecke <andre.heinecke@intevation.de>
date Mon, 28 Jul 2014 10:47:06 +0200
parents
children
comparison
equal deleted inserted replaced
-1:000000000000 0:1e5118fa0cb1
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(const 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 PRTime 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, PRTime 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, PRTime 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, PRTime 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 PLArenaPool *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 /* make sure that the entire chain is within the name space of the
554 * current issuer certificate.
555 */
556 rv = CERT_CompareNameSpace(issuerCert, namesList, certsList,
557 arena, &badCert);
558 if (rv != SECSuccess || badCert != NULL) {
559 PORT_SetError(SEC_ERROR_CERT_NOT_IN_NAME_SPACE);
560 LOG_ERROR_OR_EXIT(log, badCert, count + 1, 0);
561 goto loser;
562 }
563
564 /* XXX - the error logging may need to go down into CRL stuff at some
565 * point
566 */
567 /* check revoked list (issuer) */
568 rv = SEC_CheckCRL(handle, subjectCert, issuerCert, t, wincx);
569 if (rv == SECFailure) {
570 if (revoked) {
571 *revoked = PR_TRUE;
572 }
573 LOG_ERROR_OR_EXIT(log,subjectCert,count,0);
574 } else if (rv == SECWouldBlock) {
575 /* We found something fishy, so we intend to issue an
576 * error to the user, but the user may wish to continue
577 * processing, in which case we better make sure nothing
578 * worse has happened... so keep cranking the loop */
579 rvFinal = SECFailure;
580 if (revoked) {
581 *revoked = PR_TRUE;
582 }
583 LOG_ERROR(log,subjectCert,count,0);
584 }
585
586 if ( CERT_GetCertTrust(issuerCert, &issuerTrust) == SECSuccess) {
587 /* we have some trust info, but this does NOT imply that this
588 * cert is actually trusted for any purpose. The cert may be
589 * explicitly UNtrusted. We won't know until we examine the
590 * trust bits.
591 */
592 unsigned int flags;
593
594 if (certUsage != certUsageAnyCA &&
595 certUsage != certUsageStatusResponder) {
596
597 /*
598 * XXX This choice of trustType seems arbitrary.
599 */
600 if ( certUsage == certUsageVerifyCA ) {
601 if ( subjectCert->nsCertType & NS_CERT_TYPE_EMAIL_CA ) {
602 trustType = trustEmail;
603 } else if ( subjectCert->nsCertType & NS_CERT_TYPE_SSL_CA ) {
604 trustType = trustSSL;
605 } else {
606 trustType = trustObjectSigning;
607 }
608 }
609
610 flags = SEC_GET_TRUST_FLAGS(&issuerTrust, trustType);
611 if (( flags & requiredFlags ) == requiredFlags) {
612 /* we found a trusted one, so return */
613 rv = rvFinal;
614 goto done;
615 }
616 if (flags & CERTDB_VALID_CA) {
617 validCAOverride = PR_TRUE;
618 }
619 /* is it explicitly distrusted? */
620 if ((flags & CERTDB_TERMINAL_RECORD) &&
621 ((flags & (CERTDB_TRUSTED|CERTDB_TRUSTED_CA)) == 0)) {
622 /* untrusted -- the cert is explicitly untrusted, not
623 * just that it doesn't chain to a trusted cert */
624 PORT_SetError(SEC_ERROR_UNTRUSTED_ISSUER);
625 LOG_ERROR_OR_EXIT(log,issuerCert,count+1,flags);
626 }
627 } else {
628 /* Check if we have any valid trust when cheching for
629 * certUsageAnyCA or certUsageStatusResponder. */
630 for (trustType = trustSSL; trustType < trustTypeNone;
631 trustType++) {
632 flags = SEC_GET_TRUST_FLAGS(&issuerTrust, trustType);
633 if ((flags & requiredFlags) == requiredFlags) {
634 rv = rvFinal;
635 goto done;
636 }
637 if (flags & CERTDB_VALID_CA)
638 validCAOverride = PR_TRUE;
639 }
640 /* We have 2 separate loops because we want any single trust
641 * bit to allow this usage to return trusted. Only if none of
642 * the trust bits are on do we check to see if the cert is
643 * untrusted */
644 for (trustType = trustSSL; trustType < trustTypeNone;
645 trustType++) {
646 flags = SEC_GET_TRUST_FLAGS(&issuerTrust, trustType);
647 /* is it explicitly distrusted? */
648 if ((flags & CERTDB_TERMINAL_RECORD) &&
649 ((flags & (CERTDB_TRUSTED|CERTDB_TRUSTED_CA)) == 0)) {
650 /* untrusted -- the cert is explicitly untrusted, not
651 * just that it doesn't chain to a trusted cert */
652 PORT_SetError(SEC_ERROR_UNTRUSTED_ISSUER);
653 LOG_ERROR_OR_EXIT(log,issuerCert,count+1,flags);
654 }
655 }
656 }
657 }
658
659 if (!validCAOverride) {
660 /*
661 * Make sure that if this is an intermediate CA in the chain that
662 * it was given permission by its signer to be a CA.
663 */
664 /*
665 * if basicConstraints says it is a ca, then we check the
666 * nsCertType. If the nsCertType has any CA bits set, then
667 * it must have the right one.
668 */
669 if (!isca || (issuerCert->nsCertType & NS_CERT_TYPE_CA)) {
670 isca = (issuerCert->nsCertType & caCertType) ? PR_TRUE : PR_FALSE;
671 }
672
673 if ( !isca ) {
674 PORT_SetError(SEC_ERROR_CA_CERT_INVALID);
675 LOG_ERROR_OR_EXIT(log,issuerCert,count+1,0);
676 }
677
678 /* make sure key usage allows cert signing */
679 if (CERT_CheckKeyUsage(issuerCert, requiredCAKeyUsage) != SECSuccess) {
680 PORT_SetError(SEC_ERROR_INADEQUATE_KEY_USAGE);
681 LOG_ERROR_OR_EXIT(log,issuerCert,count+1,requiredCAKeyUsage);
682 }
683 }
684
685 /* make sure that the issuer is not self signed. If it is, then
686 * stop here to prevent looping.
687 */
688 if (issuerCert->isRoot) {
689 PORT_SetError(SEC_ERROR_UNTRUSTED_ISSUER);
690 LOG_ERROR(log, issuerCert, count+1, 0);
691 goto loser;
692 }
693 /* The issuer cert will be the subject cert in the next loop.
694 * A cert is self-issued if its subject and issuer are equal and
695 * both are of non-zero length.
696 */
697 subjectCertIsSelfIssued = (PRBool)
698 SECITEM_ItemsAreEqual(&issuerCert->derIssuer,
699 &issuerCert->derSubject) &&
700 issuerCert->derSubject.len > 0;
701 if (subjectCertIsSelfIssued == PR_FALSE) {
702 /* RFC 3280 says only non-self-issued intermediate CA certs
703 * count in path length.
704 */
705 ++currentPathLen;
706 }
707
708 CERT_DestroyCertificate(subjectCert);
709 subjectCert = issuerCert;
710 issuerCert = NULL;
711 }
712
713 PORT_SetError(SEC_ERROR_UNKNOWN_ISSUER);
714 LOG_ERROR(log,subjectCert,count,0);
715 loser:
716 rv = SECFailure;
717 done:
718 if (certsList != NULL) {
719 PORT_Free(certsList);
720 }
721 if ( issuerCert ) {
722 CERT_DestroyCertificate(issuerCert);
723 }
724
725 if ( subjectCert ) {
726 CERT_DestroyCertificate(subjectCert);
727 }
728
729 if ( arena != NULL ) {
730 PORT_FreeArena(arena, PR_FALSE);
731 }
732 return rv;
733 }
734
735 SECStatus
736 cert_VerifyCertChain(CERTCertDBHandle *handle, CERTCertificate *cert,
737 PRBool checkSig, PRBool* sigerror,
738 SECCertUsage certUsage, PRTime t, void *wincx,
739 CERTVerifyLog *log, PRBool* revoked)
740 {
741 if (CERT_GetUsePKIXForValidation()) {
742 return cert_VerifyCertChainPkix(cert, checkSig, certUsage, t,
743 wincx, log, sigerror, revoked);
744 }
745 return cert_VerifyCertChainOld(handle, cert, checkSig, sigerror,
746 certUsage, t, wincx, log, revoked);
747 }
748
749 SECStatus
750 CERT_VerifyCertChain(CERTCertDBHandle *handle, CERTCertificate *cert,
751 PRBool checkSig, SECCertUsage certUsage, PRTime t,
752 void *wincx, CERTVerifyLog *log)
753 {
754 return cert_VerifyCertChain(handle, cert, checkSig, NULL, certUsage, t,
755 wincx, log, NULL);
756 }
757
758 /*
759 * verify that a CA can sign a certificate with the requested usage.
760 */
761 SECStatus
762 CERT_VerifyCACertForUsage(CERTCertDBHandle *handle, CERTCertificate *cert,
763 PRBool checkSig, SECCertUsage certUsage, PRTime t,
764 void *wincx, CERTVerifyLog *log)
765 {
766 SECTrustType trustType;
767 CERTBasicConstraints basicConstraint;
768 PRBool isca;
769 PRBool validCAOverride = PR_FALSE;
770 SECStatus rv;
771 SECStatus rvFinal = SECSuccess;
772 unsigned int flags;
773 unsigned int caCertType;
774 unsigned int requiredCAKeyUsage;
775 unsigned int requiredFlags;
776 CERTCertificate *issuerCert;
777 CERTCertTrust certTrust;
778
779
780 if (CERT_KeyUsageAndTypeForCertUsage(certUsage, PR_TRUE,
781 &requiredCAKeyUsage,
782 &caCertType) != SECSuccess ) {
783 PORT_Assert(0);
784 EXIT_IF_NOT_LOGGING(log);
785 requiredCAKeyUsage = 0;
786 caCertType = 0;
787 }
788
789 switch ( certUsage ) {
790 case certUsageSSLClient:
791 case certUsageSSLServer:
792 case certUsageSSLCA:
793 case certUsageSSLServerWithStepUp:
794 case certUsageEmailSigner:
795 case certUsageEmailRecipient:
796 case certUsageObjectSigner:
797 case certUsageVerifyCA:
798 case certUsageStatusResponder:
799 if ( CERT_TrustFlagsForCACertUsage(certUsage, &requiredFlags,
800 &trustType) != SECSuccess ) {
801 PORT_Assert(0);
802 EXIT_IF_NOT_LOGGING(log);
803 requiredFlags = 0;
804 trustType = trustSSL;
805 }
806 break;
807 default:
808 PORT_Assert(0);
809 EXIT_IF_NOT_LOGGING(log);
810 requiredFlags = 0;
811 trustType = trustSSL;/* This used to be 0, but we need something
812 * that matches the enumeration type.
813 */
814 caCertType = 0;
815 }
816
817 /* If the basicConstraint extension is included in an intermmediate CA
818 * certificate, make sure that the isCA flag is on. If the
819 * pathLenConstraint component exists, it must be greater than the
820 * number of CA certificates we have seen so far. If the extension
821 * is omitted, we will assume that this is a CA certificate with
822 * an unlimited pathLenConstraint (since it already passes the
823 * netscape-cert-type extension checking).
824 */
825
826 rv = CERT_FindBasicConstraintExten(cert, &basicConstraint);
827 if ( rv != SECSuccess ) {
828 if (PORT_GetError() != SEC_ERROR_EXTENSION_NOT_FOUND) {
829 LOG_ERROR_OR_EXIT(log,cert,0,0);
830 }
831 /* no basic constraints found, we aren't (yet) a CA. */
832 isca = PR_FALSE;
833 } else {
834 if ( basicConstraint.isCA == PR_FALSE ) {
835 PORT_SetError (SEC_ERROR_CA_CERT_INVALID);
836 LOG_ERROR_OR_EXIT(log,cert,0,0);
837 }
838
839 /* can't check path length if we don't know the previous path */
840 isca = PR_TRUE;
841 }
842
843 if ( CERT_GetCertTrust(cert, &certTrust) == SECSuccess ) {
844 /* we have some trust info, but this does NOT imply that this
845 * cert is actually trusted for any purpose. The cert may be
846 * explicitly UNtrusted. We won't know until we examine the
847 * trust bits.
848 */
849 if (certUsage == certUsageStatusResponder) {
850 /* Check the special case of certUsageStatusResponder */
851 issuerCert = CERT_FindCertIssuer(cert, t, certUsage);
852 if (issuerCert) {
853 if (SEC_CheckCRL(handle, cert, issuerCert, t, wincx)
854 != SECSuccess) {
855 PORT_SetError(SEC_ERROR_REVOKED_CERTIFICATE);
856 CERT_DestroyCertificate(issuerCert);
857 goto loser;
858 }
859 CERT_DestroyCertificate(issuerCert);
860 }
861 /* XXX We have NOT determined that this cert is trusted.
862 * For years, NSS has treated this as trusted,
863 * but it seems incorrect.
864 */
865 rv = rvFinal;
866 goto done;
867 }
868
869 /*
870 * check the trust params of the issuer
871 */
872 flags = SEC_GET_TRUST_FLAGS(&certTrust, trustType);
873 if ( ( flags & requiredFlags ) == requiredFlags) {
874 /* we found a trusted one, so return */
875 rv = rvFinal;
876 goto done;
877 }
878 if (flags & CERTDB_VALID_CA) {
879 validCAOverride = PR_TRUE;
880 }
881 /* is it explicitly distrusted? */
882 if ((flags & CERTDB_TERMINAL_RECORD) &&
883 ((flags & (CERTDB_TRUSTED|CERTDB_TRUSTED_CA)) == 0)) {
884 /* untrusted -- the cert is explicitly untrusted, not
885 * just that it doesn't chain to a trusted cert */
886 PORT_SetError(SEC_ERROR_UNTRUSTED_CERT);
887 LOG_ERROR_OR_EXIT(log,cert,0,flags);
888 }
889 }
890 if (!validCAOverride) {
891 /*
892 * Make sure that if this is an intermediate CA in the chain that
893 * it was given permission by its signer to be a CA.
894 */
895 /*
896 * if basicConstraints says it is a ca, then we check the
897 * nsCertType. If the nsCertType has any CA bits set, then
898 * it must have the right one.
899 */
900 if (!isca || (cert->nsCertType & NS_CERT_TYPE_CA)) {
901 isca = (cert->nsCertType & caCertType) ? PR_TRUE : PR_FALSE;
902 }
903
904 if (!isca) {
905 PORT_SetError(SEC_ERROR_CA_CERT_INVALID);
906 LOG_ERROR_OR_EXIT(log,cert,0,0);
907 }
908
909 /* make sure key usage allows cert signing */
910 if (CERT_CheckKeyUsage(cert, requiredCAKeyUsage) != SECSuccess) {
911 PORT_SetError(SEC_ERROR_INADEQUATE_KEY_USAGE);
912 LOG_ERROR_OR_EXIT(log,cert,0,requiredCAKeyUsage);
913 }
914 }
915 /* make sure that the issuer is not self signed. If it is, then
916 * stop here to prevent looping.
917 */
918 if (cert->isRoot) {
919 PORT_SetError(SEC_ERROR_UNTRUSTED_ISSUER);
920 LOG_ERROR(log, cert, 0, 0);
921 goto loser;
922 }
923
924 return CERT_VerifyCertChain(handle, cert, checkSig, certUsage, t,
925 wincx, log);
926 loser:
927 rv = SECFailure;
928 done:
929 return rv;
930 }
931
932 #define NEXT_USAGE() { \
933 i*=2; \
934 certUsage++; \
935 continue; \
936 }
937
938 #define VALID_USAGE() { \
939 NEXT_USAGE(); \
940 }
941
942 #define INVALID_USAGE() { \
943 if (returnedUsages) { \
944 *returnedUsages &= (~i); \
945 } \
946 if (PR_TRUE == requiredUsage) { \
947 valid = SECFailure; \
948 } \
949 NEXT_USAGE(); \
950 }
951
952 /*
953 * check the leaf cert against trust and usage.
954 * returns success if the cert is not distrusted. If the cert is
955 * trusted, then the trusted bool will be true.
956 * returns failure if the cert is distrusted. If failure, flags
957 * will return the flag bits that indicated distrust.
958 */
959 SECStatus
960 cert_CheckLeafTrust(CERTCertificate *cert, SECCertUsage certUsage,
961 unsigned int *failedFlags, PRBool *trusted)
962 {
963 unsigned int flags;
964 CERTCertTrust trust;
965
966 *failedFlags = 0;
967 *trusted = PR_FALSE;
968
969 /* check trust flags to see if this cert is directly trusted */
970 if ( CERT_GetCertTrust(cert, &trust) == SECSuccess ) {
971 switch ( certUsage ) {
972 case certUsageSSLClient:
973 case certUsageSSLServer:
974 flags = trust.sslFlags;
975
976 /* is the cert directly trusted or not trusted ? */
977 if ( flags & CERTDB_TERMINAL_RECORD) { /* the trust record is
978 * authoritative */
979 if ( flags & CERTDB_TRUSTED ) { /* trust this cert */
980 *trusted = PR_TRUE;
981 return SECSuccess;
982 } else { /* don't trust this cert */
983 *failedFlags = flags;
984 return SECFailure;
985 }
986 }
987 break;
988 case certUsageSSLServerWithStepUp:
989 /* XXX - step up certs can't be directly trusted, only distrust */
990 flags = trust.sslFlags;
991 if ( flags & CERTDB_TERMINAL_RECORD) { /* the trust record is
992 * authoritative */
993 if (( flags & CERTDB_TRUSTED ) == 0) {
994 /* don't trust this cert */
995 *failedFlags = flags;
996 return SECFailure;
997 }
998 }
999 break;
1000 case certUsageSSLCA:
1001 flags = trust.sslFlags;
1002 if ( flags & CERTDB_TERMINAL_RECORD) { /* the trust record is
1003 * authoritative */
1004 if (( flags & (CERTDB_TRUSTED|CERTDB_TRUSTED_CA) ) == 0) {
1005 /* don't trust this cert */
1006 *failedFlags = flags;
1007 return SECFailure;
1008 }
1009 }
1010 break;
1011 case certUsageEmailSigner:
1012 case certUsageEmailRecipient:
1013 flags = trust.emailFlags;
1014 if ( flags & CERTDB_TERMINAL_RECORD) { /* the trust record is
1015 * authoritative */
1016 if ( flags & CERTDB_TRUSTED ) { /* trust this cert */
1017 *trusted = PR_TRUE;
1018 return SECSuccess;
1019 }
1020 else { /* don't trust this cert */
1021 *failedFlags = flags;
1022 return SECFailure;
1023 }
1024 }
1025
1026 break;
1027 case certUsageObjectSigner:
1028 flags = trust.objectSigningFlags;
1029
1030 if ( flags & CERTDB_TERMINAL_RECORD) { /* the trust record is
1031 * authoritative */
1032 if ( flags & CERTDB_TRUSTED ) { /* trust this cert */
1033 *trusted = PR_TRUE;
1034 return SECSuccess;
1035 } else { /* don't trust this cert */
1036 *failedFlags = flags;
1037 return SECFailure;
1038 }
1039 }
1040 break;
1041 case certUsageVerifyCA:
1042 case certUsageStatusResponder:
1043 flags = trust.sslFlags;
1044 /* is the cert directly trusted or not trusted ? */
1045 if ( ( flags & ( CERTDB_VALID_CA | CERTDB_TRUSTED_CA ) ) ==
1046 ( CERTDB_VALID_CA | CERTDB_TRUSTED_CA ) ) {
1047 *trusted = PR_TRUE;
1048 return SECSuccess;
1049 }
1050 flags = trust.emailFlags;
1051 /* is the cert directly trusted or not trusted ? */
1052 if ( ( flags & ( CERTDB_VALID_CA | CERTDB_TRUSTED_CA ) ) ==
1053 ( CERTDB_VALID_CA | CERTDB_TRUSTED_CA ) ) {
1054 *trusted = PR_TRUE;
1055 return SECSuccess;
1056 }
1057 flags = trust.objectSigningFlags;
1058 /* is the cert directly trusted or not trusted ? */
1059 if ( ( flags & ( CERTDB_VALID_CA | CERTDB_TRUSTED_CA ) ) ==
1060 ( CERTDB_VALID_CA | CERTDB_TRUSTED_CA ) ) {
1061 *trusted = PR_TRUE;
1062 return SECSuccess;
1063 }
1064 /* fall through to test distrust */
1065 case certUsageAnyCA:
1066 case certUsageUserCertImport:
1067 /* do we distrust these certs explicitly */
1068 flags = trust.sslFlags;
1069 if ( flags & CERTDB_TERMINAL_RECORD) { /* the trust record is
1070 * authoritative */
1071 if ((flags & (CERTDB_TRUSTED|CERTDB_TRUSTED_CA)) == 0) {
1072 *failedFlags = flags;
1073 return SECFailure;
1074 }
1075 }
1076 flags = trust.emailFlags;
1077 if ( flags & CERTDB_TERMINAL_RECORD) { /* the trust record is
1078 * authoritative */
1079 if ((flags & (CERTDB_TRUSTED|CERTDB_TRUSTED_CA)) == 0) {
1080 *failedFlags = flags;
1081 return SECFailure;
1082 }
1083 }
1084 /* fall through */
1085 case certUsageProtectedObjectSigner:
1086 flags = trust.objectSigningFlags;
1087 if ( flags & CERTDB_TERMINAL_RECORD) { /* the trust record is
1088 * authoritative */
1089 if ((flags & (CERTDB_TRUSTED|CERTDB_TRUSTED_CA)) == 0) {
1090 *failedFlags = flags;
1091 return SECFailure;
1092 }
1093 }
1094 break;
1095 }
1096 }
1097 return SECSuccess;
1098 }
1099
1100 /*
1101 * verify a certificate by checking if it's valid and that we
1102 * trust the issuer.
1103 *
1104 * certificateUsage contains a bitfield of all cert usages that are
1105 * required for verification to succeed
1106 *
1107 * a bitfield of cert usages is returned in *returnedUsages
1108 * if requiredUsages is non-zero, the returned bitmap is only
1109 * for those required usages, otherwise it is for all usages
1110 *
1111 */
1112 SECStatus
1113 CERT_VerifyCertificate(CERTCertDBHandle *handle, CERTCertificate *cert,
1114 PRBool checkSig, SECCertificateUsage requiredUsages, PRTime t,
1115 void *wincx, CERTVerifyLog *log, SECCertificateUsage* returnedUsages)
1116 {
1117 SECStatus rv;
1118 SECStatus valid;
1119 unsigned int requiredKeyUsage;
1120 unsigned int requiredCertType;
1121 unsigned int flags;
1122 unsigned int certType;
1123 PRBool allowOverride;
1124 SECCertTimeValidity validity;
1125 CERTStatusConfig *statusConfig;
1126 PRInt32 i;
1127 SECCertUsage certUsage = 0;
1128 PRBool checkedOCSP = PR_FALSE;
1129 PRBool checkAllUsages = PR_FALSE;
1130 PRBool revoked = PR_FALSE;
1131 PRBool sigerror = PR_FALSE;
1132 PRBool trusted = PR_FALSE;
1133
1134 if (!requiredUsages) {
1135 /* there are no required usages, so the user probably wants to
1136 get status for all usages */
1137 checkAllUsages = PR_TRUE;
1138 }
1139
1140 if (returnedUsages) {
1141 *returnedUsages = 0;
1142 } else {
1143 /* we don't have a place to return status for all usages,
1144 so we can skip checks for usages that aren't required */
1145 checkAllUsages = PR_FALSE;
1146 }
1147 valid = SECSuccess ; /* start off assuming cert is valid */
1148
1149 /* make sure that the cert is valid at time t */
1150 allowOverride = (PRBool)((requiredUsages & certificateUsageSSLServer) ||
1151 (requiredUsages & certificateUsageSSLServerWithStepUp));
1152 validity = CERT_CheckCertValidTimes(cert, t, allowOverride);
1153 if ( validity != secCertTimeValid ) {
1154 valid = SECFailure;
1155 LOG_ERROR_OR_EXIT(log,cert,0,validity);
1156 }
1157
1158 /* check key usage and netscape cert type */
1159 cert_GetCertType(cert);
1160 certType = cert->nsCertType;
1161
1162 for (i=1; i<=certificateUsageHighest &&
1163 (SECSuccess == valid || returnedUsages || log) ; ) {
1164 PRBool requiredUsage = (i & requiredUsages) ? PR_TRUE : PR_FALSE;
1165 if (PR_FALSE == requiredUsage && PR_FALSE == checkAllUsages) {
1166 NEXT_USAGE();
1167 }
1168 if (returnedUsages) {
1169 *returnedUsages |= i; /* start off assuming this usage is valid */
1170 }
1171 switch ( certUsage ) {
1172 case certUsageSSLClient:
1173 case certUsageSSLServer:
1174 case certUsageSSLServerWithStepUp:
1175 case certUsageSSLCA:
1176 case certUsageEmailSigner:
1177 case certUsageEmailRecipient:
1178 case certUsageObjectSigner:
1179 case certUsageStatusResponder:
1180 rv = CERT_KeyUsageAndTypeForCertUsage(certUsage, PR_FALSE,
1181 &requiredKeyUsage,
1182 &requiredCertType);
1183 if ( rv != SECSuccess ) {
1184 PORT_Assert(0);
1185 /* EXIT_IF_NOT_LOGGING(log); XXX ??? */
1186 requiredKeyUsage = 0;
1187 requiredCertType = 0;
1188 INVALID_USAGE();
1189 }
1190 break;
1191
1192 case certUsageAnyCA:
1193 case certUsageProtectedObjectSigner:
1194 case certUsageUserCertImport:
1195 case certUsageVerifyCA:
1196 /* these usages cannot be verified */
1197 NEXT_USAGE();
1198
1199 default:
1200 PORT_Assert(0);
1201 requiredKeyUsage = 0;
1202 requiredCertType = 0;
1203 INVALID_USAGE();
1204 }
1205 if ( CERT_CheckKeyUsage(cert, requiredKeyUsage) != SECSuccess ) {
1206 if (PR_TRUE == requiredUsage) {
1207 PORT_SetError(SEC_ERROR_INADEQUATE_KEY_USAGE);
1208 }
1209 LOG_ERROR(log,cert,0,requiredKeyUsage);
1210 INVALID_USAGE();
1211 }
1212 if ( !( certType & requiredCertType ) ) {
1213 if (PR_TRUE == requiredUsage) {
1214 PORT_SetError(SEC_ERROR_INADEQUATE_CERT_TYPE);
1215 }
1216 LOG_ERROR(log,cert,0,requiredCertType);
1217 INVALID_USAGE();
1218 }
1219
1220 rv = cert_CheckLeafTrust(cert, certUsage, &flags, &trusted);
1221 if (rv == SECFailure) {
1222 if (PR_TRUE == requiredUsage) {
1223 PORT_SetError(SEC_ERROR_UNTRUSTED_CERT);
1224 }
1225 LOG_ERROR(log, cert, 0, flags);
1226 INVALID_USAGE();
1227 } else if (trusted) {
1228 VALID_USAGE();
1229 }
1230
1231 if (PR_TRUE == revoked || PR_TRUE == sigerror) {
1232 INVALID_USAGE();
1233 }
1234
1235 rv = cert_VerifyCertChain(handle, cert,
1236 checkSig, &sigerror,
1237 certUsage, t, wincx, log,
1238 &revoked);
1239
1240 if (rv != SECSuccess) {
1241 /* EXIT_IF_NOT_LOGGING(log); XXX ???? */
1242 INVALID_USAGE();
1243 }
1244
1245 /*
1246 * Check OCSP revocation status, but only if the cert we are checking
1247 * is not a status responder itself. We only do this in the case
1248 * where we checked the cert chain (above); explicit trust "wins"
1249 * (avoids status checking, just as it avoids CRL checking) by
1250 * bypassing this code.
1251 */
1252
1253 if (PR_FALSE == checkedOCSP) {
1254 checkedOCSP = PR_TRUE; /* only check OCSP once */
1255 statusConfig = CERT_GetStatusConfig(handle);
1256 if (requiredUsages != certificateUsageStatusResponder &&
1257 statusConfig != NULL) {
1258 if (statusConfig->statusChecker != NULL) {
1259 rv = (* statusConfig->statusChecker)(handle, cert,
1260 t, wincx);
1261 if (rv != SECSuccess) {
1262 LOG_ERROR(log,cert,0,0);
1263 revoked = PR_TRUE;
1264 INVALID_USAGE();
1265 }
1266 }
1267 }
1268 }
1269
1270 NEXT_USAGE();
1271 }
1272
1273 loser:
1274 return(valid);
1275 }
1276
1277 SECStatus
1278 CERT_VerifyCert(CERTCertDBHandle *handle, CERTCertificate *cert,
1279 PRBool checkSig, SECCertUsage certUsage, PRTime t,
1280 void *wincx, CERTVerifyLog *log)
1281 {
1282 return cert_VerifyCertWithFlags(handle, cert, checkSig, certUsage, t,
1283 CERT_VERIFYCERT_USE_DEFAULTS, wincx, log);
1284 }
1285
1286 SECStatus
1287 cert_VerifyCertWithFlags(CERTCertDBHandle *handle, CERTCertificate *cert,
1288 PRBool checkSig, SECCertUsage certUsage, PRTime t,
1289 PRUint32 flags, void *wincx, CERTVerifyLog *log)
1290 {
1291 SECStatus rv;
1292 unsigned int requiredKeyUsage;
1293 unsigned int requiredCertType;
1294 unsigned int failedFlags;
1295 unsigned int certType;
1296 PRBool trusted;
1297 PRBool allowOverride;
1298 SECCertTimeValidity validity;
1299 CERTStatusConfig *statusConfig;
1300
1301 #ifdef notdef
1302 /* check if this cert is in the Evil list */
1303 rv = CERT_CheckForEvilCert(cert);
1304 if ( rv != SECSuccess ) {
1305 PORT_SetError(SEC_ERROR_REVOKED_CERTIFICATE);
1306 LOG_ERROR_OR_EXIT(log,cert,0,0);
1307 }
1308 #endif
1309
1310 /* make sure that the cert is valid at time t */
1311 allowOverride = (PRBool)((certUsage == certUsageSSLServer) ||
1312 (certUsage == certUsageSSLServerWithStepUp));
1313 validity = CERT_CheckCertValidTimes(cert, t, allowOverride);
1314 if ( validity != secCertTimeValid ) {
1315 LOG_ERROR_OR_EXIT(log,cert,0,validity);
1316 }
1317
1318 /* check key usage and netscape cert type */
1319 cert_GetCertType(cert);
1320 certType = cert->nsCertType;
1321 switch ( certUsage ) {
1322 case certUsageSSLClient:
1323 case certUsageSSLServer:
1324 case certUsageSSLServerWithStepUp:
1325 case certUsageSSLCA:
1326 case certUsageEmailSigner:
1327 case certUsageEmailRecipient:
1328 case certUsageObjectSigner:
1329 case certUsageStatusResponder:
1330 rv = CERT_KeyUsageAndTypeForCertUsage(certUsage, PR_FALSE,
1331 &requiredKeyUsage,
1332 &requiredCertType);
1333 if ( rv != SECSuccess ) {
1334 PORT_Assert(0);
1335 EXIT_IF_NOT_LOGGING(log);
1336 requiredKeyUsage = 0;
1337 requiredCertType = 0;
1338 }
1339 break;
1340 case certUsageVerifyCA:
1341 case certUsageAnyCA:
1342 requiredKeyUsage = KU_KEY_CERT_SIGN;
1343 requiredCertType = NS_CERT_TYPE_CA;
1344 if ( ! ( certType & NS_CERT_TYPE_CA ) ) {
1345 certType |= NS_CERT_TYPE_CA;
1346 }
1347 break;
1348 default:
1349 PORT_Assert(0);
1350 EXIT_IF_NOT_LOGGING(log);
1351 requiredKeyUsage = 0;
1352 requiredCertType = 0;
1353 }
1354 if ( CERT_CheckKeyUsage(cert, requiredKeyUsage) != SECSuccess ) {
1355 PORT_SetError(SEC_ERROR_INADEQUATE_KEY_USAGE);
1356 LOG_ERROR_OR_EXIT(log,cert,0,requiredKeyUsage);
1357 }
1358 if ( !( certType & requiredCertType ) ) {
1359 PORT_SetError(SEC_ERROR_INADEQUATE_CERT_TYPE);
1360 LOG_ERROR_OR_EXIT(log,cert,0,requiredCertType);
1361 }
1362
1363 rv = cert_CheckLeafTrust(cert, certUsage, &failedFlags, &trusted);
1364 if (rv == SECFailure) {
1365 PORT_SetError(SEC_ERROR_UNTRUSTED_CERT);
1366 LOG_ERROR_OR_EXIT(log, cert, 0, failedFlags);
1367 } else if (trusted) {
1368 goto done;
1369 }
1370
1371
1372 rv = CERT_VerifyCertChain(handle, cert, checkSig, certUsage,
1373 t, wincx, log);
1374 if (rv != SECSuccess) {
1375 EXIT_IF_NOT_LOGGING(log);
1376 }
1377
1378 /*
1379 * Check revocation status, but only if the cert we are checking is not a
1380 * status responder itself and the caller did not ask us to skip the check.
1381 * We only do this in the case where we checked the cert chain (above);
1382 * explicit trust "wins" (avoids status checking, just as it avoids CRL
1383 * checking, which is all done inside VerifyCertChain) by bypassing this
1384 * code.
1385 */
1386 if (!(flags & CERT_VERIFYCERT_SKIP_OCSP) &&
1387 certUsage != certUsageStatusResponder) {
1388 statusConfig = CERT_GetStatusConfig(handle);
1389 if (statusConfig && statusConfig->statusChecker) {
1390 rv = (* statusConfig->statusChecker)(handle, cert,
1391 t, wincx);
1392 if (rv != SECSuccess) {
1393 LOG_ERROR_OR_EXIT(log,cert,0,0);
1394 }
1395 }
1396 }
1397
1398 done:
1399 if (log && log->head) {
1400 return SECFailure;
1401 }
1402 return(SECSuccess);
1403
1404 loser:
1405 rv = SECFailure;
1406
1407 return(rv);
1408 }
1409
1410 /*
1411 * verify a certificate by checking if its valid and that we
1412 * trust the issuer. Verify time against now.
1413 */
1414 SECStatus
1415 CERT_VerifyCertificateNow(CERTCertDBHandle *handle, CERTCertificate *cert,
1416 PRBool checkSig, SECCertificateUsage requiredUsages,
1417 void *wincx, SECCertificateUsage* returnedUsages)
1418 {
1419 return(CERT_VerifyCertificate(handle, cert, checkSig,
1420 requiredUsages, PR_Now(), wincx, NULL, returnedUsages));
1421 }
1422
1423 /* obsolete, do not use for new code */
1424 SECStatus
1425 CERT_VerifyCertNow(CERTCertDBHandle *handle, CERTCertificate *cert,
1426 PRBool checkSig, SECCertUsage certUsage, void *wincx)
1427 {
1428 return(CERT_VerifyCert(handle, cert, checkSig,
1429 certUsage, PR_Now(), wincx, NULL));
1430 }
1431
1432
1433 /* [ FROM pcertdb.c ] */
1434 /*
1435 * Supported usage values and types:
1436 * certUsageSSLClient
1437 * certUsageSSLServer
1438 * certUsageSSLServerWithStepUp
1439 * certUsageEmailSigner
1440 * certUsageEmailRecipient
1441 * certUsageObjectSigner
1442 */
1443
1444 CERTCertificate *
1445 CERT_FindMatchingCert(CERTCertDBHandle *handle, SECItem *derName,
1446 CERTCertOwner owner, SECCertUsage usage,
1447 PRBool preferTrusted, PRTime validTime, PRBool validOnly)
1448 {
1449 CERTCertList *certList = NULL;
1450 CERTCertificate *cert = NULL;
1451 CERTCertTrust certTrust;
1452 unsigned int requiredTrustFlags;
1453 SECTrustType requiredTrustType;
1454 unsigned int flags;
1455
1456 PRBool lookingForCA = PR_FALSE;
1457 SECStatus rv;
1458 CERTCertListNode *node;
1459 CERTCertificate *saveUntrustedCA = NULL;
1460
1461 /* if preferTrusted is set, must be a CA cert */
1462 PORT_Assert( ! ( preferTrusted && ( owner != certOwnerCA ) ) );
1463
1464 if ( owner == certOwnerCA ) {
1465 lookingForCA = PR_TRUE;
1466 if ( preferTrusted ) {
1467 rv = CERT_TrustFlagsForCACertUsage(usage, &requiredTrustFlags,
1468 &requiredTrustType);
1469 if ( rv != SECSuccess ) {
1470 goto loser;
1471 }
1472 requiredTrustFlags |= CERTDB_VALID_CA;
1473 }
1474 }
1475
1476 certList = CERT_CreateSubjectCertList(NULL, handle, derName, validTime,
1477 validOnly);
1478 if ( certList != NULL ) {
1479 rv = CERT_FilterCertListByUsage(certList, usage, lookingForCA);
1480 if ( rv != SECSuccess ) {
1481 goto loser;
1482 }
1483
1484 node = CERT_LIST_HEAD(certList);
1485
1486 while ( !CERT_LIST_END(node, certList) ) {
1487 cert = node->cert;
1488
1489 /* looking for a trusted CA cert */
1490 if ( ( owner == certOwnerCA ) && preferTrusted &&
1491 ( requiredTrustType != trustTypeNone ) ) {
1492
1493 if ( CERT_GetCertTrust(cert, &certTrust) != SECSuccess ) {
1494 flags = 0;
1495 } else {
1496 flags = SEC_GET_TRUST_FLAGS(&certTrust, requiredTrustType);
1497 }
1498
1499 if ( ( flags & requiredTrustFlags ) != requiredTrustFlags ) {
1500 /* cert is not trusted */
1501 /* if this is the first cert to get this far, then save
1502 * it, so we can use it if we can't find a trusted one
1503 */
1504 if ( saveUntrustedCA == NULL ) {
1505 saveUntrustedCA = cert;
1506 }
1507 goto endloop;
1508 }
1509 }
1510 /* if we got this far, then this cert meets all criteria */
1511 break;
1512
1513 endloop:
1514 node = CERT_LIST_NEXT(node);
1515 cert = NULL;
1516 }
1517
1518 /* use the saved one if we have it */
1519 if ( cert == NULL ) {
1520 cert = saveUntrustedCA;
1521 }
1522
1523 /* if we found one then bump the ref count before freeing the list */
1524 if ( cert != NULL ) {
1525 /* bump the ref count */
1526 cert = CERT_DupCertificate(cert);
1527 }
1528
1529 CERT_DestroyCertList(certList);
1530 }
1531
1532 return(cert);
1533
1534 loser:
1535 if ( certList != NULL ) {
1536 CERT_DestroyCertList(certList);
1537 }
1538
1539 return(NULL);
1540 }
1541
1542
1543 /* [ From certdb.c ] */
1544 /*
1545 * Filter a list of certificates, removing those certs that do not have
1546 * one of the named CA certs somewhere in their cert chain.
1547 *
1548 * "certList" - the list of certificates to filter
1549 * "nCANames" - number of CA names
1550 * "caNames" - array of CA names in string(rfc 1485) form
1551 * "usage" - what use the certs are for, this is used when
1552 * selecting CA certs
1553 */
1554 SECStatus
1555 CERT_FilterCertListByCANames(CERTCertList *certList, int nCANames,
1556 char **caNames, SECCertUsage usage)
1557 {
1558 CERTCertificate *issuerCert = NULL;
1559 CERTCertificate *subjectCert;
1560 CERTCertListNode *node, *freenode;
1561 CERTCertificate *cert;
1562 int n;
1563 char **names;
1564 PRBool found;
1565 PRTime time;
1566
1567 if ( nCANames <= 0 ) {
1568 return(SECSuccess);
1569 }
1570
1571 time = PR_Now();
1572
1573 node = CERT_LIST_HEAD(certList);
1574
1575 while ( ! CERT_LIST_END(node, certList) ) {
1576 cert = node->cert;
1577
1578 subjectCert = CERT_DupCertificate(cert);
1579
1580 /* traverse the CA certs for this cert */
1581 found = PR_FALSE;
1582 while ( subjectCert != NULL ) {
1583 n = nCANames;
1584 names = caNames;
1585
1586 if (subjectCert->issuerName != NULL) {
1587 while ( n > 0 ) {
1588 if ( PORT_Strcmp(*names, subjectCert->issuerName) == 0 ) {
1589 found = PR_TRUE;
1590 break;
1591 }
1592
1593 n--;
1594 names++;
1595 }
1596 }
1597
1598 if ( found ) {
1599 break;
1600 }
1601
1602 issuerCert = CERT_FindCertIssuer(subjectCert, time, usage);
1603 if ( issuerCert == subjectCert ) {
1604 CERT_DestroyCertificate(issuerCert);
1605 issuerCert = NULL;
1606 break;
1607 }
1608 CERT_DestroyCertificate(subjectCert);
1609 subjectCert = issuerCert;
1610
1611 }
1612 CERT_DestroyCertificate(subjectCert);
1613 if ( !found ) {
1614 /* CA was not found, so remove this cert from the list */
1615 freenode = node;
1616 node = CERT_LIST_NEXT(node);
1617 CERT_RemoveCertListNode(freenode);
1618 } else {
1619 /* CA was found, so leave it in the list */
1620 node = CERT_LIST_NEXT(node);
1621 }
1622 }
1623
1624 return(SECSuccess);
1625 }
1626
1627 /*
1628 * Given a certificate, return a string containing the nickname, and possibly
1629 * one of the validity strings, based on the current validity state of the
1630 * certificate.
1631 *
1632 * "arena" - arena to allocate returned string from. If NULL, then heap
1633 * is used.
1634 * "cert" - the cert to get nickname from
1635 * "expiredString" - the string to append to the nickname if the cert is
1636 * expired.
1637 * "notYetGoodString" - the string to append to the nickname if the cert is
1638 * not yet good.
1639 */
1640 char *
1641 CERT_GetCertNicknameWithValidity(PLArenaPool *arena, CERTCertificate *cert,
1642 char *expiredString, char *notYetGoodString)
1643 {
1644 SECCertTimeValidity validity;
1645 char *nickname = NULL, *tmpstr = NULL;
1646
1647 validity = CERT_CheckCertValidTimes(cert, PR_Now(), PR_FALSE);
1648
1649 /* if the cert is good, then just use the nickname directly */
1650 if ( validity == secCertTimeValid ) {
1651 if ( arena == NULL ) {
1652 nickname = PORT_Strdup(cert->nickname);
1653 } else {
1654 nickname = PORT_ArenaStrdup(arena, cert->nickname);
1655 }
1656
1657 if ( nickname == NULL ) {
1658 goto loser;
1659 }
1660 } else {
1661
1662 /* if the cert is not valid, then tack one of the strings on the
1663 * end
1664 */
1665 if ( validity == secCertTimeExpired ) {
1666 tmpstr = PR_smprintf("%s%s", cert->nickname,
1667 expiredString);
1668 } else if ( validity == secCertTimeNotValidYet ) {
1669 /* not yet valid */
1670 tmpstr = PR_smprintf("%s%s", cert->nickname,
1671 notYetGoodString);
1672 } else {
1673 /* undetermined */
1674 tmpstr = PR_smprintf("%s",
1675 "(NULL) (Validity Unknown)");
1676 }
1677
1678 if ( tmpstr == NULL ) {
1679 goto loser;
1680 }
1681
1682 if ( arena ) {
1683 /* copy the string into the arena and free the malloc'd one */
1684 nickname = PORT_ArenaStrdup(arena, tmpstr);
1685 PORT_Free(tmpstr);
1686 } else {
1687 nickname = tmpstr;
1688 }
1689 if ( nickname == NULL ) {
1690 goto loser;
1691 }
1692 }
1693 return(nickname);
1694
1695 loser:
1696 return(NULL);
1697 }
1698
1699 /*
1700 * Collect the nicknames from all certs in a CertList. If the cert is not
1701 * valid, append a string to that nickname.
1702 *
1703 * "certList" - the list of certificates
1704 * "expiredString" - the string to append to the nickname of any expired cert
1705 * "notYetGoodString" - the string to append to the nickname of any cert
1706 * that is not yet valid
1707 */
1708 CERTCertNicknames *
1709 CERT_NicknameStringsFromCertList(CERTCertList *certList, char *expiredString,
1710 char *notYetGoodString)
1711 {
1712 CERTCertNicknames *names;
1713 PLArenaPool *arena;
1714 CERTCertListNode *node;
1715 char **nn;
1716
1717 /* allocate an arena */
1718 arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
1719 if ( arena == NULL ) {
1720 return(NULL);
1721 }
1722
1723 /* allocate the structure */
1724 names = PORT_ArenaAlloc(arena, sizeof(CERTCertNicknames));
1725 if ( names == NULL ) {
1726 goto loser;
1727 }
1728
1729 /* init the structure */
1730 names->arena = arena;
1731 names->head = NULL;
1732 names->numnicknames = 0;
1733 names->nicknames = NULL;
1734 names->totallen = 0;
1735
1736 /* count the certs in the list */
1737 node = CERT_LIST_HEAD(certList);
1738 while ( ! CERT_LIST_END(node, certList) ) {
1739 names->numnicknames++;
1740 node = CERT_LIST_NEXT(node);
1741 }
1742
1743 /* allocate nicknames array */
1744 names->nicknames = PORT_ArenaAlloc(arena,
1745 sizeof(char *) * names->numnicknames);
1746 if ( names->nicknames == NULL ) {
1747 goto loser;
1748 }
1749
1750 /* just in case printf can't deal with null strings */
1751 if (expiredString == NULL ) {
1752 expiredString = "";
1753 }
1754
1755 if ( notYetGoodString == NULL ) {
1756 notYetGoodString = "";
1757 }
1758
1759 /* traverse the list of certs and collect the nicknames */
1760 nn = names->nicknames;
1761 node = CERT_LIST_HEAD(certList);
1762 while ( ! CERT_LIST_END(node, certList) ) {
1763 *nn = CERT_GetCertNicknameWithValidity(arena, node->cert,
1764 expiredString,
1765 notYetGoodString);
1766 if ( *nn == NULL ) {
1767 goto loser;
1768 }
1769
1770 names->totallen += PORT_Strlen(*nn);
1771
1772 nn++;
1773 node = CERT_LIST_NEXT(node);
1774 }
1775
1776 return(names);
1777
1778 loser:
1779 PORT_FreeArena(arena, PR_FALSE);
1780 return(NULL);
1781 }
1782
1783 /*
1784 * Extract the nickname from a nickmake string that may have either
1785 * expiredString or notYetGoodString appended.
1786 *
1787 * Args:
1788 * "namestring" - the string containing the nickname, and possibly
1789 * one of the validity label strings
1790 * "expiredString" - the expired validity label string
1791 * "notYetGoodString" - the not yet good validity label string
1792 *
1793 * Returns the raw nickname
1794 */
1795 char *
1796 CERT_ExtractNicknameString(char *namestring, char *expiredString,
1797 char *notYetGoodString)
1798 {
1799 int explen, nyglen, namelen;
1800 int retlen;
1801 char *retstr;
1802
1803 namelen = PORT_Strlen(namestring);
1804 explen = PORT_Strlen(expiredString);
1805 nyglen = PORT_Strlen(notYetGoodString);
1806
1807 if ( namelen > explen ) {
1808 if ( PORT_Strcmp(expiredString, &namestring[namelen-explen]) == 0 ) {
1809 retlen = namelen - explen;
1810 retstr = (char *)PORT_Alloc(retlen+1);
1811 if ( retstr == NULL ) {
1812 goto loser;
1813 }
1814
1815 PORT_Memcpy(retstr, namestring, retlen);
1816 retstr[retlen] = '\0';
1817 goto done;
1818 }
1819 }
1820
1821 if ( namelen > nyglen ) {
1822 if ( PORT_Strcmp(notYetGoodString, &namestring[namelen-nyglen]) == 0) {
1823 retlen = namelen - nyglen;
1824 retstr = (char *)PORT_Alloc(retlen+1);
1825 if ( retstr == NULL ) {
1826 goto loser;
1827 }
1828
1829 PORT_Memcpy(retstr, namestring, retlen);
1830 retstr[retlen] = '\0';
1831 goto done;
1832 }
1833 }
1834
1835 /* if name string is shorter than either invalid string, then it must
1836 * be a raw nickname
1837 */
1838 retstr = PORT_Strdup(namestring);
1839
1840 done:
1841 return(retstr);
1842
1843 loser:
1844 return(NULL);
1845 }
1846
1847 CERTCertList *
1848 CERT_GetCertChainFromCert(CERTCertificate *cert, PRTime time, SECCertUsage usage)
1849 {
1850 CERTCertList *chain = NULL;
1851 int count = 0;
1852
1853 if (NULL == cert) {
1854 return NULL;
1855 }
1856
1857 cert = CERT_DupCertificate(cert);
1858 if (NULL == cert) {
1859 PORT_SetError(SEC_ERROR_NO_MEMORY);
1860 return NULL;
1861 }
1862
1863 chain = CERT_NewCertList();
1864 if (NULL == chain) {
1865 PORT_SetError(SEC_ERROR_NO_MEMORY);
1866 return NULL;
1867 }
1868
1869 while (cert != NULL && ++count <= CERT_MAX_CERT_CHAIN) {
1870 if (SECSuccess != CERT_AddCertToListTail(chain, cert)) {
1871 /* return partial chain */
1872 PORT_SetError(SEC_ERROR_NO_MEMORY);
1873 return chain;
1874 }
1875
1876 if (cert->isRoot) {
1877 /* return complete chain */
1878 return chain;
1879 }
1880
1881 cert = CERT_FindCertIssuer(cert, time, usage);
1882 }
1883
1884 /* return partial chain */
1885 PORT_SetError(SEC_ERROR_UNKNOWN_ISSUER);
1886 return chain;
1887 }
This site is hosted by Intevation GmbH (Datenschutzerklärung und Impressum | Privacy Policy and Imprint)