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