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