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