Mercurial > trustbridge > nss-cmake-static
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 } |