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 /* | |
5 * pkix_pl_pk11certstore.c | |
6 * | |
7 * PKCS11CertStore Function Definitions | |
8 * | |
9 */ | |
10 | |
11 #include "pkix_pl_pk11certstore.h" | |
12 | |
13 /* | |
14 * PKIX_DEFAULT_MAX_RESPONSE_LENGTH (64 * 1024) is too small for downloading | |
15 * CRLs. We observed CRLs of sizes 338759 and 439035 in practice. So we | |
16 * need to use a higher max response length for CRLs. | |
17 */ | |
18 #define PKIX_DEFAULT_MAX_CRL_RESPONSE_LENGTH (512 * 1024) | |
19 | |
20 /* --Private-Pk11CertStore-Functions---------------------------------- */ | |
21 | |
22 /* | |
23 * FUNCTION: pkix_pl_Pk11CertStore_CheckTrust | |
24 * DESCRIPTION: | |
25 * This function checks the trust status of this "cert" that was retrieved | |
26 * from the CertStore "store" and returns its trust status at "pTrusted". | |
27 * | |
28 * PARAMETERS: | |
29 * "store" | |
30 * Address of the CertStore. Must be non-NULL. | |
31 * "cert" | |
32 * Address of the Cert. Must be non-NULL. | |
33 * "pTrusted" | |
34 * Address of PKIX_Boolean where the "cert" trust status is returned. | |
35 * Must be non-NULL. | |
36 * "plContext" | |
37 * Platform-specific context pointer | |
38 * THREAD SAFETY: | |
39 * Thread Safe (see Thread Safety Definitions in Programmer's Guide) | |
40 * RETURNS: | |
41 * Returns NULL if the function succeeds. | |
42 * Returns a CertStore Error if the function fails in a non-fatal way. | |
43 * Returns a Fatal Error if the function fails in an unrecoverable way. | |
44 */ | |
45 static PKIX_Error * | |
46 pkix_pl_Pk11CertStore_CheckTrust( | |
47 PKIX_CertStore *store, | |
48 PKIX_PL_Cert *cert, | |
49 PKIX_Boolean *pTrusted, | |
50 void *plContext) | |
51 { | |
52 SECStatus rv = SECFailure; | |
53 PKIX_Boolean trusted = PKIX_FALSE; | |
54 SECCertUsage certUsage = 0; | |
55 SECCertificateUsage certificateUsage; | |
56 unsigned int requiredFlags; | |
57 SECTrustType trustType; | |
58 CERTCertTrust trust; | |
59 | |
60 PKIX_ENTER(CERTSTORE, "pkix_pl_Pk11CertStore_CheckTrust"); | |
61 PKIX_NULLCHECK_THREE(store, cert, pTrusted); | |
62 PKIX_NULLCHECK_ONE(cert->nssCert); | |
63 | |
64 certificateUsage = ((PKIX_PL_NssContext*)plContext)->certificateUsage; | |
65 | |
66 /* ensure we obtained a single usage bit only */ | |
67 PORT_Assert(!(certificateUsage & (certificateUsage - 1))); | |
68 | |
69 /* convert SECertificateUsage (bit mask) to SECCertUsage (enum) */ | |
70 while (0 != (certificateUsage = certificateUsage >> 1)) { certUsage++; } | |
71 | |
72 rv = CERT_TrustFlagsForCACertUsage(certUsage, &requiredFlags, &trustType
); | |
73 if (rv == SECSuccess) { | |
74 rv = CERT_GetCertTrust(cert->nssCert, &trust); | |
75 } | |
76 | |
77 if (rv == SECSuccess) { | |
78 unsigned int certFlags; | |
79 | |
80 if (certUsage != certUsageAnyCA && | |
81 certUsage != certUsageStatusResponder) { | |
82 CERTCertificate *nssCert = cert->nssCert; | |
83 | |
84 if (certUsage == certUsageVerifyCA) { | |
85 if (nssCert->nsCertType & NS_CERT_TYPE_EMAIL_CA) { | |
86 trustType = trustEmail; | |
87 } else if (nssCert->nsCertType & NS_CERT_TYPE_SSL_CA) { | |
88 trustType = trustSSL; | |
89 } else { | |
90 trustType = trustObjectSigning; | |
91 } | |
92 } | |
93 | |
94 certFlags = SEC_GET_TRUST_FLAGS((&trust), trustType); | |
95 if ((certFlags & requiredFlags) == requiredFlags) { | |
96 trusted = PKIX_TRUE; | |
97 } | |
98 } else { | |
99 for (trustType = trustSSL; trustType < trustTypeNone; | |
100 trustType++) { | |
101 certFlags = | |
102 SEC_GET_TRUST_FLAGS((&trust), trustType); | |
103 if ((certFlags & requiredFlags) == requiredFlags) { | |
104 trusted = PKIX_TRUE; | |
105 break; | |
106 } | |
107 } | |
108 } | |
109 } | |
110 | |
111 *pTrusted = trusted; | |
112 | |
113 PKIX_RETURN(CERTSTORE); | |
114 } | |
115 | |
116 /* | |
117 * FUNCTION: pkix_pl_Pk11CertStore_CertQuery | |
118 * DESCRIPTION: | |
119 * | |
120 * This function obtains from the database the Certs specified by the | |
121 * ComCertSelParams pointed to by "params" and stores the resulting | |
122 * List at "pSelected". If no matching Certs are found, a NULL pointer | |
123 * will be stored. | |
124 * | |
125 * This function uses a "smart" database query if the Subject has been set | |
126 * in ComCertSelParams. Otherwise, it uses a very inefficient call to | |
127 * retrieve all Certs in the database (and run them through the selector). | |
128 * | |
129 * PARAMETERS: | |
130 * "params" | |
131 * Address of the ComCertSelParams. Must be non-NULL. | |
132 * "pSelected" | |
133 * Address at which List will be stored. Must be non-NULL. | |
134 * "plContext" | |
135 * Platform-specific context pointer | |
136 * THREAD SAFETY: | |
137 * Thread Safe (see Thread Safety Definitions in Programmer's Guide) | |
138 * RETURNS: | |
139 * Returns NULL if the function succeeds. | |
140 * Returns a CertStore Error if the function fails in a non-fatal way. | |
141 * Returns a Fatal Error if the function fails in an unrecoverable way. | |
142 */ | |
143 static PKIX_Error * | |
144 pkix_pl_Pk11CertStore_CertQuery( | |
145 PKIX_ComCertSelParams *params, | |
146 PKIX_List **pSelected, | |
147 void *plContext) | |
148 { | |
149 PRBool validOnly = PR_FALSE; | |
150 PRTime prtime = 0; | |
151 PKIX_PL_X500Name *subjectName = NULL; | |
152 PKIX_PL_Date *certValid = NULL; | |
153 PKIX_List *certList = NULL; | |
154 PKIX_PL_Cert *cert = NULL; | |
155 CERTCertList *pk11CertList = NULL; | |
156 CERTCertListNode *node = NULL; | |
157 CERTCertificate *nssCert = NULL; | |
158 CERTCertDBHandle *dbHandle = NULL; | |
159 | |
160 PLArenaPool *arena = NULL; | |
161 SECItem *nameItem = NULL; | |
162 void *wincx = NULL; | |
163 | |
164 PKIX_ENTER(CERTSTORE, "pkix_pl_Pk11CertStore_CertQuery"); | |
165 PKIX_NULLCHECK_TWO(params, pSelected); | |
166 | |
167 /* avoid multiple calls to retrieve a constant */ | |
168 PKIX_PL_NSSCALLRV(CERTSTORE, dbHandle, CERT_GetDefaultCertDB, ()); | |
169 | |
170 /* | |
171 * Any of the ComCertSelParams may be obtained and used to constrain | |
172 * the database query, to allow the use of a "smart" query. See | |
173 * pkix_certsel.h for a list of the PKIX_ComCertSelParams_Get* | |
174 * calls available. No corresponding "smart" queries exist at present, | |
175 * except for CERT_CreateSubjectCertList based on Subject. When others | |
176 * are added, corresponding code should be added to | |
177 * pkix_pl_Pk11CertStore_CertQuery to use them when appropriate | |
178 * selector parameters have been set. | |
179 */ | |
180 | |
181 PKIX_CHECK(PKIX_ComCertSelParams_GetSubject | |
182 (params, &subjectName, plContext), | |
183 PKIX_COMCERTSELPARAMSGETSUBJECTFAILED); | |
184 | |
185 PKIX_CHECK(PKIX_ComCertSelParams_GetCertificateValid | |
186 (params, &certValid, plContext), | |
187 PKIX_COMCERTSELPARAMSGETCERTIFICATEVALIDFAILED); | |
188 | |
189 /* If caller specified a Date, convert it to PRTime */ | |
190 if (certValid) { | |
191 PKIX_CHECK(pkix_pl_Date_GetPRTime | |
192 (certValid, &prtime, plContext), | |
193 PKIX_DATEGETPRTIMEFAILED); | |
194 validOnly = PR_TRUE; | |
195 } | |
196 | |
197 /* | |
198 * If we have the subject name for the desired subject, | |
199 * ask the database for Certs with that subject. Otherwise | |
200 * ask the database for all Certs. | |
201 */ | |
202 if (subjectName) { | |
203 arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); | |
204 if (arena) { | |
205 | |
206 PKIX_CHECK(pkix_pl_X500Name_GetDERName | |
207 (subjectName, arena, &nameItem, plContext), | |
208 PKIX_X500NAMEGETSECNAMEFAILED); | |
209 | |
210 if (nameItem) { | |
211 | |
212 PKIX_PL_NSSCALLRV | |
213 (CERTSTORE, | |
214 pk11CertList, | |
215 CERT_CreateSubjectCertList, | |
216 (NULL, dbHandle, nameItem, prtime, validOnly)); | |
217 } | |
218 PKIX_PL_NSSCALL | |
219 (CERTSTORE, PORT_FreeArena, (arena, PR_FALSE)); | |
220 arena = NULL; | |
221 } | |
222 | |
223 } else { | |
224 | |
225 PKIX_CHECK(pkix_pl_NssContext_GetWincx | |
226 ((PKIX_PL_NssContext *)plContext, &wincx), | |
227 PKIX_NSSCONTEXTGETWINCXFAILED); | |
228 | |
229 PKIX_PL_NSSCALLRV | |
230 (CERTSTORE, | |
231 pk11CertList, | |
232 PK11_ListCerts, | |
233 (PK11CertListAll, wincx)); | |
234 } | |
235 | |
236 if (pk11CertList) { | |
237 | |
238 PKIX_CHECK(PKIX_List_Create(&certList, plContext), | |
239 PKIX_LISTCREATEFAILED); | |
240 | |
241 for (node = CERT_LIST_HEAD(pk11CertList); | |
242 !(CERT_LIST_END(node, pk11CertList)); | |
243 node = CERT_LIST_NEXT(node)) { | |
244 | |
245 PKIX_PL_NSSCALLRV | |
246 (CERTSTORE, | |
247 nssCert, | |
248 CERT_DupCertificate, | |
249 (node->cert)); | |
250 | |
251 if (!nssCert) { | |
252 continue; /* just skip bad certs */ | |
253 } | |
254 | |
255 PKIX_CHECK_ONLY_FATAL(pkix_pl_Cert_CreateWithNSSCert | |
256 (nssCert, &cert, plContext), | |
257 PKIX_CERTCREATEWITHNSSCERTFAILED); | |
258 | |
259 if (PKIX_ERROR_RECEIVED) { | |
260 CERT_DestroyCertificate(nssCert); | |
261 nssCert = NULL; | |
262 continue; /* just skip bad certs */ | |
263 } | |
264 | |
265 PKIX_CHECK_ONLY_FATAL(PKIX_List_AppendItem | |
266 (certList, (PKIX_PL_Object *)cert, plContext), | |
267 PKIX_LISTAPPENDITEMFAILED); | |
268 | |
269 PKIX_DECREF(cert); | |
270 | |
271 } | |
272 | |
273 /* Don't throw away the list if one cert was bad! */ | |
274 pkixTempErrorReceived = PKIX_FALSE; | |
275 } | |
276 | |
277 *pSelected = certList; | |
278 certList = NULL; | |
279 | |
280 cleanup: | |
281 | |
282 if (pk11CertList) { | |
283 CERT_DestroyCertList(pk11CertList); | |
284 } | |
285 if (arena) { | |
286 PORT_FreeArena(arena, PR_FALSE); | |
287 } | |
288 | |
289 PKIX_DECREF(subjectName); | |
290 PKIX_DECREF(certValid); | |
291 PKIX_DECREF(cert); | |
292 PKIX_DECREF(certList); | |
293 | |
294 PKIX_RETURN(CERTSTORE); | |
295 } | |
296 | |
297 /* | |
298 * FUNCTION: pkix_pl_Pk11CertStore_ImportCrl | |
299 * DESCRIPTION: | |
300 * | |
301 * PARAMETERS: | |
302 * "params" | |
303 * Address of the ComCRLSelParams. Must be non-NULL. | |
304 * "pSelected" | |
305 * Address at which List will be stored. Must be non-NULL. | |
306 * "plContext" | |
307 * Platform-specific context pointer | |
308 * THREAD SAFETY: | |
309 * Thread Safe (see Thread Safety Definitions in Programmer's Guide) | |
310 * RETURNS: | |
311 * Returns NULL if the function succeeds. | |
312 * Returns a CertStore Error if the function fails in a non-fatal way. | |
313 * Returns a Fatal Error if the function fails in an unrecoverable way. | |
314 */ | |
315 static PKIX_Error * | |
316 pkix_pl_Pk11CertStore_ImportCrl( | |
317 PKIX_CertStore *store, | |
318 PKIX_PL_X500Name *issuerName, | |
319 PKIX_List *crlList, | |
320 void *plContext) | |
321 { | |
322 CERTCertDBHandle *certHandle = CERT_GetDefaultCertDB(); | |
323 PKIX_PL_CRL *crl = NULL; | |
324 SECItem *derCrl = NULL; | |
325 | |
326 PKIX_ENTER(CERTSTORE, "pkix_pl_Pk11CertStore_ImportCrl"); | |
327 PKIX_NULLCHECK_TWO(store, plContext); | |
328 | |
329 if (!crlList) { | |
330 goto cleanup; | |
331 } | |
332 while (crlList->length > 0) { | |
333 PKIX_CHECK( | |
334 PKIX_List_GetItem(crlList, 0, (PKIX_PL_Object**)&crl, | |
335 plContext), | |
336 PKIX_LISTGETITEMFAILED); | |
337 | |
338 /* Delete crl from the list to keep controll of the | |
339 * last reference. crl need to be destroyed right after | |
340 * it released the ownership of the crl der. */ | |
341 PKIX_CHECK( | |
342 PKIX_List_DeleteItem(crlList, 0, plContext), | |
343 PKIX_LISTDELETEITEMFAILED); | |
344 | |
345 /* acquire the crlder ownership */ | |
346 pkixErrorResult = | |
347 PKIX_PL_CRL_ReleaseDerCrl(crl, &derCrl, plContext); | |
348 PORT_Assert(!pkixErrorResult && derCrl); | |
349 if (pkixErrorResult || !derCrl) { | |
350 /* All pkix delivered crls should be able to | |
351 * release their ders. */ | |
352 PKIX_DECREF(pkixErrorResult); | |
353 PKIX_DECREF(crl); | |
354 continue; | |
355 } | |
356 cert_CacheCRLByGeneralName(certHandle, derCrl, | |
357 crl->derGenName); | |
358 /* Do not check the status. If it is a SECFailure, | |
359 * derCrl is already destroyed. */ | |
360 derCrl = NULL; | |
361 PKIX_DECREF(crl); | |
362 } | |
363 | |
364 cleanup: | |
365 PKIX_DECREF(crl); | |
366 | |
367 PKIX_RETURN(CERTSTORE); | |
368 } | |
369 | |
370 static PKIX_Error * | |
371 NameCacheHasFetchedCrlInfo(PKIX_PL_Cert *pkixCert, | |
372 PRTime time, | |
373 PKIX_Boolean *pHasFetchedCrlInCache, | |
374 void *plContext) | |
375 { | |
376 /* Returning true result in this case will mean, that case info | |
377 * is currect and should used as is. */ | |
378 NamedCRLCache* nameCrlCache = NULL; | |
379 PKIX_Boolean hasFetchedCrlInCache = PKIX_TRUE; | |
380 PKIX_List *dpList = NULL; | |
381 pkix_pl_CrlDp *dp = NULL; | |
382 PKIX_UInt32 dpIndex = 0; | |
383 SECStatus rv = SECSuccess; | |
384 PRTime reloadDelay = 0, badCrlInvalDelay = 0; | |
385 | |
386 PKIX_ENTER(CERTSTORE, "ChechCacheHasFetchedCrl"); | |
387 | |
388 reloadDelay = | |
389 ((PKIX_PL_NssContext*)plContext)->crlReloadDelay * | |
390 PR_USEC_PER_SEC; | |
391 badCrlInvalDelay = | |
392 ((PKIX_PL_NssContext*)plContext)->badDerCrlReloadDelay * | |
393 PR_USEC_PER_SEC; | |
394 if (!time) { | |
395 time = PR_Now(); | |
396 } | |
397 /* If we already download the crl and inserted into the cache, then | |
398 * there is no need to check for fetched crl. We have what we have. */ | |
399 PKIX_CHECK( | |
400 PKIX_PL_Cert_GetCrlDp(pkixCert, &dpList, plContext), | |
401 PKIX_CERTGETCRLDPFAILED); | |
402 if (dpList && dpList->length) { | |
403 hasFetchedCrlInCache = PKIX_FALSE; | |
404 rv = cert_AcquireNamedCRLCache(&nameCrlCache); | |
405 if (rv != SECSuccess) { | |
406 PKIX_DECREF(dpList); | |
407 } | |
408 } else { | |
409 /* If no dp then treat it as if we already have | |
410 * a fetched crl. */ | |
411 PKIX_DECREF(dpList); | |
412 } | |
413 for (;!hasFetchedCrlInCache && | |
414 dpList && dpIndex < dpList->length;dpIndex++) { | |
415 SECItem **derDpNames = NULL; | |
416 pkixErrorResult = | |
417 PKIX_List_GetItem(dpList, dpIndex, (PKIX_PL_Object **)&dp, | |
418 plContext); | |
419 if (pkixErrorResult) { | |
420 PKIX_DECREF(pkixErrorResult); | |
421 continue; | |
422 } | |
423 if (dp->nssdp->distPointType == generalName) { | |
424 /* dp can only be created from nssdp. */ | |
425 derDpNames = dp->nssdp->derFullName; | |
426 } | |
427 while (derDpNames && *derDpNames != NULL) { | |
428 NamedCRLCacheEntry* cacheEntry = NULL; | |
429 const SECItem *derDpName = *derDpNames++; | |
430 rv = cert_FindCRLByGeneralName(nameCrlCache, derDpName, | |
431 &cacheEntry); | |
432 if (rv == SECSuccess && cacheEntry) { | |
433 if ((cacheEntry->inCRLCache && | |
434 (cacheEntry->successfulInsertionTime + reloadDelay > time || | |
435 (cacheEntry->dupe && | |
436 cacheEntry->lastAttemptTime + reloadDelay > time))) || | |
437 (cacheEntry->badDER && | |
438 cacheEntry->lastAttemptTime + badCrlInvalDelay > time)) { | |
439 hasFetchedCrlInCache = PKIX_TRUE; | |
440 break; | |
441 } | |
442 } | |
443 } | |
444 PKIX_DECREF(dp); | |
445 } | |
446 cleanup: | |
447 *pHasFetchedCrlInCache = hasFetchedCrlInCache; | |
448 if (nameCrlCache) { | |
449 cert_ReleaseNamedCRLCache(nameCrlCache); | |
450 } | |
451 PKIX_DECREF(dpList); | |
452 | |
453 PKIX_RETURN(CERTSTORE); | |
454 } | |
455 | |
456 /* | |
457 * FUNCTION: pkix_pl_Pk11CertStore_CheckCrl | |
458 * DESCRIPTION: | |
459 * | |
460 * PARAMETERS: | |
461 * "params" | |
462 * Address of the ComCRLSelParams. Must be non-NULL. | |
463 * "pSelected" | |
464 * Address at which List will be stored. Must be non-NULL. | |
465 * "plContext" | |
466 * Platform-specific context pointer | |
467 * THREAD SAFETY: | |
468 * Thread Safe (see Thread Safety Definitions in Programmer's Guide) | |
469 * RETURNS: | |
470 * Returns NULL if the function succeeds. | |
471 * Returns a CertStore Error if the function fails in a non-fatal way. | |
472 * Returns a Fatal Error if the function fails in an unrecoverable way. | |
473 */ | |
474 static PKIX_Error * | |
475 pkix_pl_Pk11CertStore_CheckRevByCrl( | |
476 PKIX_CertStore *store, | |
477 PKIX_PL_Cert *pkixCert, | |
478 PKIX_PL_Cert *pkixIssuer, | |
479 PKIX_PL_Date *date, | |
480 PKIX_Boolean crlDownloadDone, | |
481 CERTCRLEntryReasonCode *pReasonCode, | |
482 PKIX_RevocationStatus *pStatus, | |
483 void *plContext) | |
484 { | |
485 PKIX_RevocationStatus pkixRevStatus = PKIX_RevStatus_NoInfo; | |
486 CERTRevocationStatus revStatus = certRevocationStatusUnknown; | |
487 PKIX_Boolean hasFetchedCrlInCache = PKIX_TRUE; | |
488 CERTCertificate *cert = NULL, *issuer = NULL; | |
489 SECStatus rv = SECSuccess; | |
490 void *wincx = NULL; | |
491 PRTime time = 0; | |
492 | |
493 PKIX_ENTER(CERTSTORE, "pkix_pl_Pk11CertStore_CheckRevByCrl"); | |
494 PKIX_NULLCHECK_FOUR(store, pkixCert, pkixIssuer, plContext); | |
495 | |
496 cert = pkixCert->nssCert; | |
497 issuer = pkixIssuer->nssCert; | |
498 if (date) { | |
499 PKIX_CHECK( | |
500 pkix_pl_Date_GetPRTime(date, &time, plContext), | |
501 PKIX_DATEGETPRTIMEFAILED); | |
502 } | |
503 PKIX_CHECK( | |
504 pkix_pl_NssContext_GetWincx((PKIX_PL_NssContext*)plContext, | |
505 &wincx), | |
506 PKIX_NSSCONTEXTGETWINCXFAILED); | |
507 /* No need to check any cDPs, since partitioned crls are not | |
508 * supported. If a ds does not point to partitioned crl, then | |
509 * the crl should be in issuer cache that is unrelated to any | |
510 * dp. Using NULL as a dp pointer to check it.*/ | |
511 rv = cert_CheckCertRevocationStatus(cert, issuer, NULL, | |
512 /* Will not validate the signature | |
513 * on the crl if time is not specified.*
/ | |
514 time, wincx, &revStatus, pReasonCode); | |
515 if (rv == SECFailure) { | |
516 pkixRevStatus = PKIX_RevStatus_Revoked; | |
517 goto cleanup; | |
518 } | |
519 if (crlDownloadDone) { | |
520 if (revStatus == certRevocationStatusRevoked) { | |
521 pkixRevStatus = PKIX_RevStatus_Revoked; | |
522 } else if (revStatus == certRevocationStatusValid) { | |
523 pkixRevStatus = PKIX_RevStatus_Success; | |
524 } | |
525 } else { | |
526 pkixErrorResult = | |
527 NameCacheHasFetchedCrlInfo(pkixCert, time, &hasFetchedCrlInCache, | |
528 plContext); | |
529 if (pkixErrorResult) { | |
530 goto cleanup; | |
531 } | |
532 if (revStatus == certRevocationStatusRevoked && | |
533 (hasFetchedCrlInCache || | |
534 *pReasonCode != crlEntryReasoncertificatedHold)) { | |
535 pkixRevStatus = PKIX_RevStatus_Revoked; | |
536 } else if (revStatus == certRevocationStatusValid && | |
537 hasFetchedCrlInCache) { | |
538 pkixRevStatus = PKIX_RevStatus_Success; | |
539 } | |
540 } | |
541 cleanup: | |
542 *pStatus = pkixRevStatus; | |
543 | |
544 PKIX_RETURN(CERTSTORE); | |
545 } | |
546 | |
547 | |
548 /* | |
549 * FUNCTION: pkix_pl_Pk11CertStore_GetCert | |
550 * (see description of PKIX_CertStore_CertCallback in pkix_certstore.h) | |
551 */ | |
552 PKIX_Error * | |
553 pkix_pl_Pk11CertStore_GetCert( | |
554 PKIX_CertStore *store, | |
555 PKIX_CertSelector *selector, | |
556 PKIX_VerifyNode *parentVerifyNode, | |
557 void **pNBIOContext, | |
558 PKIX_List **pCertList, | |
559 void *plContext) | |
560 { | |
561 PKIX_UInt32 i = 0; | |
562 PKIX_UInt32 numFound = 0; | |
563 PKIX_PL_Cert *candidate = NULL; | |
564 PKIX_List *selected = NULL; | |
565 PKIX_List *filtered = NULL; | |
566 PKIX_CertSelector_MatchCallback selectorCallback = NULL; | |
567 PKIX_CertStore_CheckTrustCallback trustCallback = NULL; | |
568 PKIX_ComCertSelParams *params = NULL; | |
569 PKIX_Boolean cacheFlag = PKIX_FALSE; | |
570 PKIX_VerifyNode *verifyNode = NULL; | |
571 PKIX_Error *selectorError = NULL; | |
572 | |
573 PKIX_ENTER(CERTSTORE, "pkix_pl_Pk11CertStore_GetCert"); | |
574 PKIX_NULLCHECK_FOUR(store, selector, pNBIOContext, pCertList); | |
575 | |
576 *pNBIOContext = NULL; /* We don't use non-blocking I/O */ | |
577 | |
578 PKIX_CHECK(PKIX_CertSelector_GetMatchCallback | |
579 (selector, &selectorCallback, plContext), | |
580 PKIX_CERTSELECTORGETMATCHCALLBACKFAILED); | |
581 | |
582 PKIX_CHECK(PKIX_CertSelector_GetCommonCertSelectorParams | |
583 (selector, ¶ms, plContext), | |
584 PKIX_CERTSELECTORGETCOMCERTSELPARAMSFAILED); | |
585 | |
586 PKIX_CHECK(pkix_pl_Pk11CertStore_CertQuery | |
587 (params, &selected, plContext), | |
588 PKIX_PK11CERTSTORECERTQUERYFAILED); | |
589 | |
590 if (selected) { | |
591 PKIX_CHECK(PKIX_List_GetLength(selected, &numFound, plContext), | |
592 PKIX_LISTGETLENGTHFAILED); | |
593 } | |
594 | |
595 PKIX_CHECK(PKIX_CertStore_GetCertStoreCacheFlag | |
596 (store, &cacheFlag, plContext), | |
597 PKIX_CERTSTOREGETCERTSTORECACHEFLAGFAILED); | |
598 | |
599 PKIX_CHECK(PKIX_CertStore_GetTrustCallback | |
600 (store, &trustCallback, plContext), | |
601 PKIX_CERTSTOREGETTRUSTCALLBACKFAILED); | |
602 | |
603 PKIX_CHECK(PKIX_List_Create(&filtered, plContext), | |
604 PKIX_LISTCREATEFAILED); | |
605 | |
606 for (i = 0; i < numFound; i++) { | |
607 PKIX_CHECK_ONLY_FATAL(PKIX_List_GetItem | |
608 (selected, | |
609 i, | |
610 (PKIX_PL_Object **)&candidate, | |
611 plContext), | |
612 PKIX_LISTGETITEMFAILED); | |
613 | |
614 if (PKIX_ERROR_RECEIVED) { | |
615 continue; /* just skip bad certs */ | |
616 } | |
617 | |
618 selectorError = | |
619 selectorCallback(selector, candidate, plContext); | |
620 if (!selectorError) { | |
621 PKIX_CHECK(PKIX_PL_Cert_SetCacheFlag | |
622 (candidate, cacheFlag, plContext), | |
623 PKIX_CERTSETCACHEFLAGFAILED); | |
624 | |
625 if (trustCallback) { | |
626 PKIX_CHECK(PKIX_PL_Cert_SetTrustCertStore | |
627 (candidate, store, plContext), | |
628 PKIX_CERTSETTRUSTCERTSTOREFAILED); | |
629 } | |
630 | |
631 PKIX_CHECK_ONLY_FATAL(PKIX_List_AppendItem | |
632 (filtered, | |
633 (PKIX_PL_Object *)candidate, | |
634 plContext), | |
635 PKIX_LISTAPPENDITEMFAILED); | |
636 } else if (parentVerifyNode) { | |
637 PKIX_CHECK_FATAL( | |
638 pkix_VerifyNode_Create(candidate, 0, selectorError, | |
639 &verifyNode, plContext), | |
640 PKIX_VERIFYNODECREATEFAILED); | |
641 PKIX_CHECK_FATAL( | |
642 pkix_VerifyNode_AddToTree(parentVerifyNode, | |
643 verifyNode, | |
644 plContext), | |
645 PKIX_VERIFYNODEADDTOTREEFAILED); | |
646 PKIX_DECREF(verifyNode); | |
647 } | |
648 PKIX_DECREF(selectorError); | |
649 PKIX_DECREF(candidate); | |
650 } | |
651 | |
652 /* Don't throw away the list if one cert was bad! */ | |
653 pkixTempErrorReceived = PKIX_FALSE; | |
654 | |
655 *pCertList = filtered; | |
656 filtered = NULL; | |
657 | |
658 cleanup: | |
659 fatal: | |
660 PKIX_DECREF(filtered); | |
661 PKIX_DECREF(candidate); | |
662 PKIX_DECREF(selected); | |
663 PKIX_DECREF(params); | |
664 PKIX_DECREF(verifyNode); | |
665 PKIX_DECREF(selectorError); | |
666 | |
667 PKIX_RETURN(CERTSTORE); | |
668 } | |
669 | |
670 static PKIX_Error * | |
671 RemovePartitionedDpsFromList(PKIX_List *dpList, PKIX_PL_Date *date, | |
672 void *plContext) | |
673 { | |
674 NamedCRLCache* nameCrlCache = NULL; | |
675 pkix_pl_CrlDp *dp = NULL; | |
676 unsigned int dpIndex = 0; | |
677 PRTime time; | |
678 PRTime reloadDelay = 0, badCrlInvalDelay = 0; | |
679 SECStatus rv; | |
680 | |
681 PKIX_ENTER(CERTSTORE, "pkix_pl_Pk11CertStore_ListRemovePrtDp"); | |
682 | |
683 if (!dpList || !dpList->length) { | |
684 PKIX_RETURN(CERTSTORE); | |
685 } | |
686 reloadDelay = | |
687 ((PKIX_PL_NssContext*)plContext)->crlReloadDelay * | |
688 PR_USEC_PER_SEC; | |
689 badCrlInvalDelay = | |
690 ((PKIX_PL_NssContext*)plContext)->badDerCrlReloadDelay * | |
691 PR_USEC_PER_SEC; | |
692 PKIX_CHECK(pkix_pl_Date_GetPRTime(date, &time, plContext), | |
693 PKIX_DATEGETPRTIMEFAILED); | |
694 rv = cert_AcquireNamedCRLCache(&nameCrlCache); | |
695 if (rv == SECFailure) { | |
696 /* Baling out. Wont find out any thing useful. */ | |
697 PKIX_RETURN(CERTSTORE); | |
698 } | |
699 while (dpIndex < dpList->length) { | |
700 SECItem **derDpNames = NULL; | |
701 PKIX_Boolean removeDp = PKIX_FALSE; | |
702 | |
703 PKIX_CHECK( | |
704 PKIX_List_GetItem(dpList, dpIndex, (PKIX_PL_Object **)&dp, | |
705 plContext), | |
706 PKIX_LISTGETITEMFAILED); | |
707 if (!dp->isPartitionedByReasonCode) { | |
708 /* See if we know about this dp anything why we should | |
709 * not use it to download a crl. */ | |
710 if (dp->nssdp->distPointType == generalName) { | |
711 /* dp can only be created from nssdp. */ | |
712 derDpNames = dp->nssdp->derFullName; | |
713 } else { | |
714 removeDp = PKIX_TRUE; | |
715 } | |
716 while (derDpNames && *derDpNames != NULL) { | |
717 NamedCRLCacheEntry* cacheEntry = NULL; | |
718 const SECItem *derDpName = *derDpNames++; | |
719 /* Removing from the list all dps that we know about. */ | |
720 rv = cert_FindCRLByGeneralName(nameCrlCache, derDpName, | |
721 &cacheEntry); | |
722 if (rv && cacheEntry) { | |
723 if (cacheEntry->unsupported || | |
724 (cacheEntry->inCRLCache && | |
725 (cacheEntry->successfulInsertionTime + reloadDelay > ti
me || | |
726 (cacheEntry->dupe && | |
727 cacheEntry->lastAttemptTime + reloadDelay > time))) |
| | |
728 (cacheEntry->badDER && | |
729 cacheEntry->lastAttemptTime + badCrlInvalDelay > time
)) { | |
730 removeDp = PKIX_TRUE; | |
731 } | |
732 } | |
733 } | |
734 } else { | |
735 /* Remove dp that point to a partitioned crl . RFC 5280 | |
736 * recommends against crl partitioned by reason code. | |
737 * Will skip such crls */ | |
738 removeDp = PKIX_TRUE; | |
739 } | |
740 if (removeDp) { | |
741 PKIX_CHECK_ONLY_FATAL( | |
742 pkix_List_Remove(dpList,(PKIX_PL_Object*)dp, | |
743 plContext), | |
744 PKIX_LISTGETITEMFAILED); | |
745 } else { | |
746 dpIndex += 1; | |
747 } | |
748 PKIX_DECREF(dp); | |
749 } | |
750 | |
751 cleanup: | |
752 if (nameCrlCache) { | |
753 cert_ReleaseNamedCRLCache(nameCrlCache); | |
754 } | |
755 PKIX_DECREF(dp); | |
756 | |
757 PKIX_RETURN(CERTSTORE); | |
758 } | |
759 | |
760 /* | |
761 * FUNCTION: pkix_pl_Pk11CertStore_DownloadCrl | |
762 */ | |
763 static PKIX_Error * | |
764 DownloadCrl(pkix_pl_CrlDp *dp, PKIX_PL_CRL **crl, | |
765 const SEC_HttpClientFcnV1 *hcv1, void *plContext) | |
766 { | |
767 char *location = NULL; | |
768 char *hostname = NULL; | |
769 char *path = NULL; | |
770 PRUint16 port; | |
771 SEC_HTTP_SERVER_SESSION pServerSession = NULL; | |
772 SEC_HTTP_REQUEST_SESSION pRequestSession = NULL; | |
773 PRUint16 myHttpResponseCode; | |
774 const char *myHttpResponseData = NULL; | |
775 PRUint32 myHttpResponseDataLen; | |
776 SECItem *uri = NULL; | |
777 SECItem *derCrlCopy = NULL; | |
778 CERTSignedCrl *nssCrl = NULL; | |
779 CERTGeneralName *genName = NULL; | |
780 SECItem **derGenNames = NULL; | |
781 SECItem *derGenName = NULL; | |
782 | |
783 PKIX_ENTER(CERTSTORE, "pkix_pl_Pk11CertStore_DownloadCrl"); | |
784 | |
785 /* Do not support dps others than a one with GeneralName | |
786 * name type. */ | |
787 if (dp->distPointType != generalName || | |
788 !dp->nssdp->derFullName) { | |
789 PKIX_ERROR(PKIX_UNSUPPORTEDCRLDPTYPE); | |
790 } | |
791 genName = dp->name.fullName; | |
792 derGenNames = dp->nssdp->derFullName; | |
793 do { | |
794 derGenName = *derGenNames; | |
795 do { | |
796 if (!derGenName || | |
797 !genName->name.other.data) { | |
798 /* get to next name if no data. */ | |
799 break; | |
800 } | |
801 uri = &genName->name.other; | |
802 location = (char*)PR_Malloc(1 + uri->len); | |
803 if (!location) { | |
804 break; | |
805 } | |
806 PORT_Memcpy(location, uri->data, uri->len); | |
807 location[uri->len] = 0; | |
808 if (CERT_ParseURL(location, &hostname, | |
809 &port, &path) != SECSuccess) { | |
810 PORT_SetError(SEC_ERROR_BAD_CRL_DP_URL); | |
811 break; | |
812 } | |
813 | |
814 PORT_Assert(hostname != NULL); | |
815 PORT_Assert(path != NULL); | |
816 | |
817 if ((*hcv1->createSessionFcn)(hostname, port, | |
818 &pServerSession) != SECSuccess) { | |
819 PORT_SetError(SEC_ERROR_BAD_CRL_DP_URL); | |
820 break; | |
821 } | |
822 | |
823 if ((*hcv1->createFcn)(pServerSession, "http", path, "GET", | |
824 /* Users with slow connections might not get CRL revocation | |
825 checking for certs that use big CRLs because of the timeout | |
826 We absolutely need code that limits our retry attempts. | |
827 */ | |
828 PR_SecondsToInterval( | |
829 ((PKIX_PL_NssContext*)plContext)->timeoutSeconds), | |
830 &pRequestSession) != SECSuccess) { | |
831 break; | |
832 } | |
833 | |
834 myHttpResponseDataLen = | |
835 ((PKIX_PL_NssContext*)plContext)->maxResponseLength; | |
836 if (myHttpResponseDataLen < PKIX_DEFAULT_MAX_CRL_RESPONSE_LENGTH) | |
837 myHttpResponseDataLen = PKIX_DEFAULT_MAX_CRL_RESPONSE_LENGTH; | |
838 | |
839 /* We use a non-zero timeout, which means: | |
840 - the client will use blocking I/O | |
841 - TryFcn will not return WOULD_BLOCK nor a poll descriptor | |
842 - it's sufficient to call TryFcn once | |
843 */ | |
844 /* we don't want result objects larger than this: */ | |
845 if ((*hcv1->trySendAndReceiveFcn)( | |
846 pRequestSession, | |
847 NULL, | |
848 &myHttpResponseCode, | |
849 NULL, | |
850 NULL, | |
851 &myHttpResponseData, | |
852 &myHttpResponseDataLen) != SECSuccess) { | |
853 break; | |
854 } | |
855 | |
856 if (myHttpResponseCode != 200) { | |
857 break; | |
858 } | |
859 } while(0); | |
860 if (!myHttpResponseData) { | |
861 /* Going to the next one. */ | |
862 genName = CERT_GetNextGeneralName(genName); | |
863 derGenNames++; | |
864 } | |
865 /* Staing in the loop through all the names until | |
866 * we have a successful download. */ | |
867 } while (!myHttpResponseData && *derGenNames && | |
868 genName != dp->name.fullName); | |
869 /* Need this name to track the crl source location. */ | |
870 PORT_Assert(derGenName); | |
871 | |
872 if (!myHttpResponseData) { | |
873 /* Generating fake bad CRL to keep track of this dp */ | |
874 SECItem derCrl = {siBuffer, (void*)"BadCrl", 6 }; | |
875 | |
876 derCrlCopy = SECITEM_DupItem(&derCrl); | |
877 if (!derCrlCopy) { | |
878 PKIX_ERROR(PKIX_ALLOCERROR); | |
879 } | |
880 derGenName = *dp->nssdp->derFullName; | |
881 } else { | |
882 SECItem derCrl = { siBuffer, | |
883 (void*)myHttpResponseData, | |
884 myHttpResponseDataLen }; | |
885 derCrlCopy = SECITEM_DupItem(&derCrl); | |
886 if (!derCrlCopy) { | |
887 PKIX_ERROR(PKIX_ALLOCERROR); | |
888 } | |
889 /* crl will be based on derCrlCopy, but will not own the der. */ | |
890 nssCrl = | |
891 CERT_DecodeDERCrlWithFlags(NULL, derCrlCopy, SEC_CRL_TYPE, | |
892 CRL_DECODE_DONT_COPY_DER | | |
893 CRL_DECODE_SKIP_ENTRIES); | |
894 } | |
895 /* pkix crl owns the der. */ | |
896 PKIX_CHECK( | |
897 pkix_pl_CRL_CreateWithSignedCRL(nssCrl, derCrlCopy, | |
898 derGenName, | |
899 crl, plContext), | |
900 PKIX_CRLCREATEWITHSIGNEDCRLFAILED); | |
901 /* pkix crl now own both objects. */ | |
902 derCrlCopy = NULL; | |
903 nssCrl = NULL; | |
904 | |
905 cleanup: | |
906 if (derCrlCopy) | |
907 PORT_Free(derCrlCopy); | |
908 if (nssCrl) | |
909 SEC_DestroyCrl(nssCrl); | |
910 if (pRequestSession != NULL) | |
911 (*hcv1->freeFcn)(pRequestSession); | |
912 if (pServerSession != NULL) | |
913 (*hcv1->freeSessionFcn)(pServerSession); | |
914 if (path != NULL) | |
915 PORT_Free(path); | |
916 if (hostname != NULL) | |
917 PORT_Free(hostname); | |
918 if (location) { | |
919 PORT_Free(location); | |
920 } | |
921 | |
922 PKIX_RETURN(CERTSTORE); | |
923 } | |
924 | |
925 /* | |
926 * FUNCTION: pkix_pl_Pk11CertStore_GetCRL | |
927 * (see description of PKIX_CertStore_CRLCallback in pkix_certstore.h) | |
928 */ | |
929 static PKIX_Error * | |
930 pkix_pl_Pk11CertStore_GetCRL( | |
931 PKIX_CertStore *store, | |
932 PKIX_CRLSelector *selector, | |
933 void **pNBIOContext, | |
934 PKIX_List **pCrlList, | |
935 void *plContext) | |
936 { | |
937 PKIX_UInt32 dpIndex = 0; | |
938 PKIX_PL_CRL *crl = NULL; | |
939 PKIX_List *crlList = NULL; | |
940 PKIX_List *dpList = NULL; | |
941 pkix_pl_CrlDp *dp = NULL; | |
942 PKIX_PL_Date *date = NULL; | |
943 const SEC_HttpClientFcn *registeredHttpClient = NULL; | |
944 | |
945 PKIX_ENTER(CERTSTORE, "pkix_pl_Pk11CertStore_GetCRL"); | |
946 PKIX_NULLCHECK_THREE(store, pNBIOContext, pCrlList); | |
947 PKIX_NULLCHECK_TWO(selector, selector->params); | |
948 | |
949 registeredHttpClient = SEC_GetRegisteredHttpClient(); | |
950 if (!registeredHttpClient || registeredHttpClient->version != 1) { | |
951 goto cleanup; | |
952 } | |
953 dpList = selector->params->crldpList; | |
954 date = selector->params->date; | |
955 PKIX_CHECK( | |
956 RemovePartitionedDpsFromList(dpList, date, | |
957 plContext), | |
958 PKIX_FAILTOREMOVEDPFROMLIST); | |
959 for (;dpIndex < dpList->length;dpIndex++) { | |
960 PKIX_DECREF(dp); | |
961 pkixErrorResult = | |
962 PKIX_List_GetItem(dpList, dpIndex, | |
963 (PKIX_PL_Object **)&dp, | |
964 plContext); | |
965 if (pkixErrorResult) { | |
966 PKIX_DECREF(pkixErrorResult); | |
967 continue; | |
968 } | |
969 pkixErrorResult = | |
970 DownloadCrl(dp, &crl, | |
971 ®isteredHttpClient->fcnTable.ftable1, | |
972 plContext); | |
973 if (pkixErrorResult || !crl) { | |
974 /* continue to next dp in case of unsuccesfull | |
975 * download attempt. */ | |
976 PKIX_DECREF(pkixErrorResult); | |
977 continue; | |
978 } | |
979 if (!crlList) { | |
980 PKIX_CHECK(PKIX_List_Create(&crlList, plContext), | |
981 PKIX_LISTCREATEFAILED); | |
982 } | |
983 pkixErrorResult = | |
984 PKIX_List_AppendItem(crlList, (PKIX_PL_Object *)crl, | |
985 plContext); | |
986 if (pkixErrorResult) { | |
987 PKIX_DECREF(pkixErrorResult); | |
988 } | |
989 PKIX_DECREF(crl); | |
990 } | |
991 *pCrlList = crlList; | |
992 crlList = NULL; | |
993 | |
994 cleanup: | |
995 PKIX_DECREF(dp); | |
996 PKIX_DECREF(crl); | |
997 PKIX_DECREF(crlList); | |
998 | |
999 PKIX_RETURN(CERTSTORE); | |
1000 } | |
1001 | |
1002 | |
1003 /* --Public-Pk11CertStore-Functions----------------------------------- */ | |
1004 | |
1005 /* | |
1006 * FUNCTION: PKIX_PL_Pk11CertStore_Create | |
1007 * (see comments in pkix_samples_modules.h) | |
1008 */ | |
1009 PKIX_Error * | |
1010 PKIX_PL_Pk11CertStore_Create( | |
1011 PKIX_CertStore **pCertStore, | |
1012 void *plContext) | |
1013 { | |
1014 PKIX_CertStore *certStore = NULL; | |
1015 | |
1016 PKIX_ENTER(CERTSTORE, "PKIX_PL_Pk11CertStore_Create"); | |
1017 PKIX_NULLCHECK_ONE(pCertStore); | |
1018 | |
1019 PKIX_CHECK(PKIX_CertStore_Create | |
1020 (pkix_pl_Pk11CertStore_GetCert, | |
1021 pkix_pl_Pk11CertStore_GetCRL, | |
1022 NULL, /* getCertContinue */ | |
1023 NULL, /* getCrlContinue */ | |
1024 pkix_pl_Pk11CertStore_CheckTrust, | |
1025 pkix_pl_Pk11CertStore_ImportCrl, | |
1026 pkix_pl_Pk11CertStore_CheckRevByCrl, | |
1027 NULL, | |
1028 PKIX_TRUE, /* cache flag */ | |
1029 PKIX_TRUE, /* local - no network I/O */ | |
1030 &certStore, | |
1031 plContext), | |
1032 PKIX_CERTSTORECREATEFAILED); | |
1033 | |
1034 *pCertStore = certStore; | |
1035 | |
1036 cleanup: | |
1037 | |
1038 PKIX_RETURN(CERTSTORE); | |
1039 } | |
OLD | NEW |