comparison nss/lib/certdb/crl.c @ 0:1e5118fa0cb1

This is NSS with a Cmake Buildsyste To compile a static NSS library for Windows we've used the Chromium-NSS fork and added a Cmake buildsystem to compile it statically for Windows. See README.chromium for chromium changes and README.trustbridge for our modifications.
author Andre Heinecke <andre.heinecke@intevation.de>
date Mon, 28 Jul 2014 10:47:06 +0200
parents
children
comparison
equal deleted inserted replaced
-1:000000000000 0:1e5118fa0cb1
1 /* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4
5 /*
6 * Moved from secpkcs7.c
7 */
8
9 #include "cert.h"
10 #include "certi.h"
11 #include "secder.h"
12 #include "secasn1.h"
13 #include "secoid.h"
14 #include "certdb.h"
15 #include "certxutl.h"
16 #include "prtime.h"
17 #include "secerr.h"
18 #include "pk11func.h"
19 #include "dev.h"
20 #include "dev3hack.h"
21 #include "nssbase.h"
22 #if defined(DPC_RWLOCK) || defined(GLOBAL_RWLOCK)
23 #include "nssrwlk.h"
24 #endif
25 #include "pk11priv.h"
26
27 const SEC_ASN1Template SEC_CERTExtensionTemplate[] = {
28 { SEC_ASN1_SEQUENCE,
29 0, NULL, sizeof(CERTCertExtension) },
30 { SEC_ASN1_OBJECT_ID,
31 offsetof(CERTCertExtension,id) },
32 { SEC_ASN1_OPTIONAL | SEC_ASN1_BOOLEAN, /* XXX DER_DEFAULT */
33 offsetof(CERTCertExtension,critical), },
34 { SEC_ASN1_OCTET_STRING,
35 offsetof(CERTCertExtension,value) },
36 { 0, }
37 };
38
39 static const SEC_ASN1Template SEC_CERTExtensionsTemplate[] = {
40 { SEC_ASN1_SEQUENCE_OF, 0, SEC_CERTExtensionTemplate}
41 };
42
43 /*
44 * XXX Also, these templates need to be tested; Lisa did the obvious
45 * translation but they still should be verified.
46 */
47
48 const SEC_ASN1Template CERT_IssuerAndSNTemplate[] = {
49 { SEC_ASN1_SEQUENCE,
50 0, NULL, sizeof(CERTIssuerAndSN) },
51 { SEC_ASN1_SAVE,
52 offsetof(CERTIssuerAndSN,derIssuer) },
53 { SEC_ASN1_INLINE,
54 offsetof(CERTIssuerAndSN,issuer),
55 CERT_NameTemplate },
56 { SEC_ASN1_INTEGER,
57 offsetof(CERTIssuerAndSN,serialNumber) },
58 { 0 }
59 };
60
61 SEC_ASN1_MKSUB(SECOID_AlgorithmIDTemplate)
62 SEC_ASN1_MKSUB(CERT_TimeChoiceTemplate)
63
64 static const SEC_ASN1Template cert_CrlKeyTemplate[] = {
65 { SEC_ASN1_SEQUENCE,
66 0, NULL, sizeof(CERTCrlKey) },
67 { SEC_ASN1_INTEGER | SEC_ASN1_OPTIONAL, offsetof(CERTCrlKey,dummy) },
68 { SEC_ASN1_SKIP },
69 { SEC_ASN1_ANY, offsetof(CERTCrlKey,derName) },
70 { SEC_ASN1_SKIP_REST },
71 { 0 }
72 };
73
74 static const SEC_ASN1Template cert_CrlEntryTemplate[] = {
75 { SEC_ASN1_SEQUENCE,
76 0, NULL, sizeof(CERTCrlEntry) },
77 { SEC_ASN1_INTEGER,
78 offsetof(CERTCrlEntry,serialNumber) },
79 { SEC_ASN1_INLINE | SEC_ASN1_XTRN,
80 offsetof(CERTCrlEntry,revocationDate),
81 SEC_ASN1_SUB(CERT_TimeChoiceTemplate) },
82 { SEC_ASN1_OPTIONAL | SEC_ASN1_SEQUENCE_OF,
83 offsetof(CERTCrlEntry, extensions),
84 SEC_CERTExtensionTemplate},
85 { 0 }
86 };
87
88 const SEC_ASN1Template CERT_CrlTemplate[] = {
89 { SEC_ASN1_SEQUENCE,
90 0, NULL, sizeof(CERTCrl) },
91 { SEC_ASN1_INTEGER | SEC_ASN1_OPTIONAL, offsetof (CERTCrl, version) },
92 { SEC_ASN1_INLINE | SEC_ASN1_XTRN,
93 offsetof(CERTCrl,signatureAlg),
94 SEC_ASN1_SUB(SECOID_AlgorithmIDTemplate)},
95 { SEC_ASN1_SAVE,
96 offsetof(CERTCrl,derName) },
97 { SEC_ASN1_INLINE,
98 offsetof(CERTCrl,name),
99 CERT_NameTemplate },
100 { SEC_ASN1_INLINE | SEC_ASN1_XTRN,
101 offsetof(CERTCrl,lastUpdate),
102 SEC_ASN1_SUB(CERT_TimeChoiceTemplate) },
103 { SEC_ASN1_INLINE | SEC_ASN1_OPTIONAL | SEC_ASN1_XTRN,
104 offsetof(CERTCrl,nextUpdate),
105 SEC_ASN1_SUB(CERT_TimeChoiceTemplate) },
106 { SEC_ASN1_OPTIONAL | SEC_ASN1_SEQUENCE_OF,
107 offsetof(CERTCrl,entries),
108 cert_CrlEntryTemplate },
109 { SEC_ASN1_OPTIONAL | SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC |
110 SEC_ASN1_EXPLICIT | 0,
111 offsetof(CERTCrl,extensions),
112 SEC_CERTExtensionsTemplate},
113 { 0 }
114 };
115
116 const SEC_ASN1Template CERT_CrlTemplateNoEntries[] = {
117 { SEC_ASN1_SEQUENCE,
118 0, NULL, sizeof(CERTCrl) },
119 { SEC_ASN1_INTEGER | SEC_ASN1_OPTIONAL, offsetof (CERTCrl, version) },
120 { SEC_ASN1_INLINE | SEC_ASN1_XTRN,
121 offsetof(CERTCrl,signatureAlg),
122 SEC_ASN1_SUB(SECOID_AlgorithmIDTemplate) },
123 { SEC_ASN1_SAVE,
124 offsetof(CERTCrl,derName) },
125 { SEC_ASN1_INLINE,
126 offsetof(CERTCrl,name),
127 CERT_NameTemplate },
128 { SEC_ASN1_INLINE | SEC_ASN1_XTRN,
129 offsetof(CERTCrl,lastUpdate),
130 SEC_ASN1_SUB(CERT_TimeChoiceTemplate) },
131 { SEC_ASN1_INLINE | SEC_ASN1_OPTIONAL | SEC_ASN1_XTRN,
132 offsetof(CERTCrl,nextUpdate),
133 SEC_ASN1_SUB(CERT_TimeChoiceTemplate) },
134 { SEC_ASN1_OPTIONAL | SEC_ASN1_SEQUENCE_OF |
135 SEC_ASN1_SKIP }, /* skip entries */
136 { SEC_ASN1_OPTIONAL | SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC |
137 SEC_ASN1_EXPLICIT | 0,
138 offsetof(CERTCrl,extensions),
139 SEC_CERTExtensionsTemplate },
140 { 0 }
141 };
142
143 const SEC_ASN1Template CERT_CrlTemplateEntriesOnly[] = {
144 { SEC_ASN1_SEQUENCE,
145 0, NULL, sizeof(CERTCrl) },
146 { SEC_ASN1_SKIP | SEC_ASN1_INTEGER | SEC_ASN1_OPTIONAL },
147 { SEC_ASN1_SKIP },
148 { SEC_ASN1_SKIP },
149 { SEC_ASN1_SKIP | SEC_ASN1_INLINE | SEC_ASN1_XTRN,
150 offsetof(CERTCrl,lastUpdate),
151 SEC_ASN1_SUB(CERT_TimeChoiceTemplate) },
152 { SEC_ASN1_SKIP | SEC_ASN1_INLINE | SEC_ASN1_OPTIONAL | SEC_ASN1_XTRN,
153 offsetof(CERTCrl,nextUpdate),
154 SEC_ASN1_SUB(CERT_TimeChoiceTemplate) },
155 { SEC_ASN1_OPTIONAL | SEC_ASN1_SEQUENCE_OF,
156 offsetof(CERTCrl,entries),
157 cert_CrlEntryTemplate }, /* decode entries */
158 { SEC_ASN1_SKIP_REST },
159 { 0 }
160 };
161
162 const SEC_ASN1Template CERT_SignedCrlTemplate[] = {
163 { SEC_ASN1_SEQUENCE,
164 0, NULL, sizeof(CERTSignedCrl) },
165 { SEC_ASN1_SAVE,
166 offsetof(CERTSignedCrl,signatureWrap.data) },
167 { SEC_ASN1_INLINE,
168 offsetof(CERTSignedCrl,crl),
169 CERT_CrlTemplate },
170 { SEC_ASN1_INLINE | SEC_ASN1_XTRN ,
171 offsetof(CERTSignedCrl,signatureWrap.signatureAlgorithm),
172 SEC_ASN1_SUB(SECOID_AlgorithmIDTemplate) },
173 { SEC_ASN1_BIT_STRING,
174 offsetof(CERTSignedCrl,signatureWrap.signature) },
175 { 0 }
176 };
177
178 static const SEC_ASN1Template cert_SignedCrlTemplateNoEntries[] = {
179 { SEC_ASN1_SEQUENCE,
180 0, NULL, sizeof(CERTSignedCrl) },
181 { SEC_ASN1_SAVE,
182 offsetof(CERTSignedCrl,signatureWrap.data) },
183 { SEC_ASN1_INLINE,
184 offsetof(CERTSignedCrl,crl),
185 CERT_CrlTemplateNoEntries },
186 { SEC_ASN1_INLINE | SEC_ASN1_XTRN,
187 offsetof(CERTSignedCrl,signatureWrap.signatureAlgorithm),
188 SEC_ASN1_SUB(SECOID_AlgorithmIDTemplate) },
189 { SEC_ASN1_BIT_STRING,
190 offsetof(CERTSignedCrl,signatureWrap.signature) },
191 { 0 }
192 };
193
194 const SEC_ASN1Template CERT_SetOfSignedCrlTemplate[] = {
195 { SEC_ASN1_SET_OF, 0, CERT_SignedCrlTemplate },
196 };
197
198 /* get CRL version */
199 int cert_get_crl_version(CERTCrl * crl)
200 {
201 /* CRL version is defaulted to v1 */
202 int version = SEC_CRL_VERSION_1;
203 if (crl && crl->version.data != 0) {
204 version = (int)DER_GetUInteger (&crl->version);
205 }
206 return version;
207 }
208
209
210 /* check the entries in the CRL */
211 SECStatus cert_check_crl_entries (CERTCrl *crl)
212 {
213 CERTCrlEntry **entries;
214 CERTCrlEntry *entry;
215 PRBool hasCriticalExten = PR_FALSE;
216 SECStatus rv = SECSuccess;
217
218 if (!crl) {
219 return SECFailure;
220 }
221
222 if (crl->entries == NULL) {
223 /* CRLs with no entries are valid */
224 return (SECSuccess);
225 }
226
227 /* Look in the crl entry extensions. If there is a critical extension,
228 then the crl version must be v2; otherwise, it should be v1.
229 */
230 entries = crl->entries;
231 while (*entries) {
232 entry = *entries;
233 if (entry->extensions) {
234 /* If there is a critical extension in the entries, then the
235 CRL must be of version 2. If we already saw a critical extension,
236 there is no need to check the version again.
237 */
238 if (hasCriticalExten == PR_FALSE) {
239 hasCriticalExten = cert_HasCriticalExtension (entry->extensions);
240 if (hasCriticalExten) {
241 if (cert_get_crl_version(crl) != SEC_CRL_VERSION_2) {
242 /* only CRL v2 critical extensions are supported */
243 PORT_SetError(SEC_ERROR_CRL_V1_CRITICAL_EXTENSION);
244 rv = SECFailure;
245 break;
246 }
247 }
248 }
249
250 /* For each entry, make sure that it does not contain an unknown
251 critical extension. If it does, we must reject the CRL since
252 we don't know how to process the extension.
253 */
254 if (cert_HasUnknownCriticalExten (entry->extensions) == PR_TRUE) {
255 PORT_SetError (SEC_ERROR_CRL_UNKNOWN_CRITICAL_EXTENSION);
256 rv = SECFailure;
257 break;
258 }
259 }
260 ++entries;
261 }
262 return(rv);
263 }
264
265 /* Check the version of the CRL. If there is a critical extension in the crl
266 or crl entry, then the version must be v2. Otherwise, it should be v1. If
267 the crl contains critical extension(s), then we must recognized the
268 extension's OID.
269 */
270 SECStatus cert_check_crl_version (CERTCrl *crl)
271 {
272 PRBool hasCriticalExten = PR_FALSE;
273 int version = cert_get_crl_version(crl);
274
275 if (version > SEC_CRL_VERSION_2) {
276 PORT_SetError (SEC_ERROR_CRL_INVALID_VERSION);
277 return (SECFailure);
278 }
279
280 /* Check the crl extensions for a critial extension. If one is found,
281 and the version is not v2, then we are done.
282 */
283 if (crl->extensions) {
284 hasCriticalExten = cert_HasCriticalExtension (crl->extensions);
285 if (hasCriticalExten) {
286 if (version != SEC_CRL_VERSION_2) {
287 /* only CRL v2 critical extensions are supported */
288 PORT_SetError(SEC_ERROR_CRL_V1_CRITICAL_EXTENSION);
289 return (SECFailure);
290 }
291 /* make sure that there is no unknown critical extension */
292 if (cert_HasUnknownCriticalExten (crl->extensions) == PR_TRUE) {
293 PORT_SetError (SEC_ERROR_CRL_UNKNOWN_CRITICAL_EXTENSION);
294 return (SECFailure);
295 }
296 }
297 }
298
299 return (SECSuccess);
300 }
301
302 /*
303 * Generate a database key, based on the issuer name from a
304 * DER crl.
305 */
306 SECStatus
307 CERT_KeyFromDERCrl(PLArenaPool *arena, SECItem *derCrl, SECItem *key)
308 {
309 SECStatus rv;
310 CERTSignedData sd;
311 CERTCrlKey crlkey;
312 PLArenaPool* myArena;
313
314 if (!arena) {
315 /* arena needed for QuickDER */
316 myArena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
317 } else {
318 myArena = arena;
319 }
320 PORT_Memset (&sd, 0, sizeof (sd));
321 rv = SEC_QuickDERDecodeItem (myArena, &sd, CERT_SignedDataTemplate, derCrl);
322 if (SECSuccess == rv) {
323 PORT_Memset (&crlkey, 0, sizeof (crlkey));
324 rv = SEC_QuickDERDecodeItem(myArena, &crlkey, cert_CrlKeyTemplate, &sd.data);
325 }
326
327 /* make a copy so the data doesn't point to memory inside derCrl, which
328 may be temporary */
329 if (SECSuccess == rv) {
330 rv = SECITEM_CopyItem(arena, key, &crlkey.derName);
331 }
332
333 if (myArena != arena) {
334 PORT_FreeArena(myArena, PR_FALSE);
335 }
336
337 return rv;
338 }
339
340 #define GetOpaqueCRLFields(x) ((OpaqueCRLFields*)x->opaque)
341
342 SECStatus CERT_CompleteCRLDecodeEntries(CERTSignedCrl* crl)
343 {
344 SECStatus rv = SECSuccess;
345 SECItem* crldata = NULL;
346 OpaqueCRLFields* extended = NULL;
347
348 if ( (!crl) ||
349 (!(extended = (OpaqueCRLFields*) crl->opaque)) ||
350 (PR_TRUE == extended->decodingError) ) {
351 rv = SECFailure;
352 } else {
353 if (PR_FALSE == extended->partial) {
354 /* the CRL has already been fully decoded */
355 return SECSuccess;
356 }
357 if (PR_TRUE == extended->badEntries) {
358 /* the entries decoding already failed */
359 return SECFailure;
360 }
361 crldata = &crl->signatureWrap.data;
362 if (!crldata) {
363 rv = SECFailure;
364 }
365 }
366
367 if (SECSuccess == rv) {
368 rv = SEC_QuickDERDecodeItem(crl->arena,
369 &crl->crl,
370 CERT_CrlTemplateEntriesOnly,
371 crldata);
372 if (SECSuccess == rv) {
373 extended->partial = PR_FALSE; /* successful decode, avoid
374 decoding again */
375 } else {
376 extended->decodingError = PR_TRUE;
377 extended->badEntries = PR_TRUE;
378 /* cache the decoding failure. If it fails the first time,
379 it will fail again, which will grow the arena and leak
380 memory, so we want to avoid it */
381 }
382 rv = cert_check_crl_entries(&crl->crl);
383 if (rv != SECSuccess) {
384 extended->badExtensions = PR_TRUE;
385 }
386 }
387 return rv;
388 }
389
390 /*
391 * take a DER CRL and decode it into a CRL structure
392 * allow reusing the input DER without making a copy
393 */
394 CERTSignedCrl *
395 CERT_DecodeDERCrlWithFlags(PLArenaPool *narena, SECItem *derSignedCrl,
396 int type, PRInt32 options)
397 {
398 PLArenaPool *arena;
399 CERTSignedCrl *crl;
400 SECStatus rv;
401 OpaqueCRLFields* extended = NULL;
402 const SEC_ASN1Template* crlTemplate = CERT_SignedCrlTemplate;
403 PRInt32 testOptions = options;
404
405 PORT_Assert(derSignedCrl);
406 if (!derSignedCrl) {
407 PORT_SetError(SEC_ERROR_INVALID_ARGS);
408 return NULL;
409 }
410
411 /* Adopting DER requires not copying it. Code that sets ADOPT flag
412 * but doesn't set DONT_COPY probably doesn't know What it is doing.
413 * That condition is a programming error in the caller.
414 */
415 testOptions &= (CRL_DECODE_ADOPT_HEAP_DER | CRL_DECODE_DONT_COPY_DER);
416 PORT_Assert(testOptions != CRL_DECODE_ADOPT_HEAP_DER);
417 if (testOptions == CRL_DECODE_ADOPT_HEAP_DER) {
418 PORT_SetError(SEC_ERROR_INVALID_ARGS);
419 return NULL;
420 }
421
422 /* make a new arena if needed */
423 if (narena == NULL) {
424 arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
425 if ( !arena ) {
426 return NULL;
427 }
428 } else {
429 arena = narena;
430 }
431
432 /* allocate the CRL structure */
433 crl = (CERTSignedCrl *)PORT_ArenaZAlloc(arena, sizeof(CERTSignedCrl));
434 if ( !crl ) {
435 PORT_SetError(SEC_ERROR_NO_MEMORY);
436 goto loser;
437 }
438
439 crl->arena = arena;
440
441 /* allocate opaque fields */
442 crl->opaque = (void*)PORT_ArenaZAlloc(arena, sizeof(OpaqueCRLFields));
443 if ( !crl->opaque ) {
444 goto loser;
445 }
446 extended = (OpaqueCRLFields*) crl->opaque;
447 if (options & CRL_DECODE_ADOPT_HEAP_DER) {
448 extended->heapDER = PR_TRUE;
449 }
450 if (options & CRL_DECODE_DONT_COPY_DER) {
451 crl->derCrl = derSignedCrl; /* DER is not copied . The application
452 must keep derSignedCrl until it
453 destroys the CRL */
454 } else {
455 crl->derCrl = (SECItem *)PORT_ArenaZAlloc(arena,sizeof(SECItem));
456 if (crl->derCrl == NULL) {
457 goto loser;
458 }
459 rv = SECITEM_CopyItem(arena, crl->derCrl, derSignedCrl);
460 if (rv != SECSuccess) {
461 goto loser;
462 }
463 }
464
465 /* Save the arena in the inner crl for CRL extensions support */
466 crl->crl.arena = arena;
467 if (options & CRL_DECODE_SKIP_ENTRIES) {
468 crlTemplate = cert_SignedCrlTemplateNoEntries;
469 extended->partial = PR_TRUE;
470 }
471
472 /* decode the CRL info */
473 switch (type) {
474 case SEC_CRL_TYPE:
475 rv = SEC_QuickDERDecodeItem(arena, crl, crlTemplate, crl->derCrl);
476 if (rv != SECSuccess) {
477 extended->badDER = PR_TRUE;
478 break;
479 }
480 /* check for critical extensions */
481 rv = cert_check_crl_version (&crl->crl);
482 if (rv != SECSuccess) {
483 extended->badExtensions = PR_TRUE;
484 break;
485 }
486
487 if (PR_TRUE == extended->partial) {
488 /* partial decoding, don't verify entries */
489 break;
490 }
491
492 rv = cert_check_crl_entries(&crl->crl);
493 if (rv != SECSuccess) {
494 extended->badExtensions = PR_TRUE;
495 }
496
497 break;
498
499 default:
500 PORT_SetError(SEC_ERROR_INVALID_ARGS);
501 rv = SECFailure;
502 break;
503 }
504
505 if (rv != SECSuccess) {
506 goto loser;
507 }
508
509 crl->referenceCount = 1;
510
511 return(crl);
512
513 loser:
514 if (options & CRL_DECODE_KEEP_BAD_CRL) {
515 if (extended) {
516 extended->decodingError = PR_TRUE;
517 }
518 if (crl) {
519 crl->referenceCount = 1;
520 return(crl);
521 }
522 }
523
524 if ((narena == NULL) && arena ) {
525 PORT_FreeArena(arena, PR_FALSE);
526 }
527
528 return(0);
529 }
530
531 /*
532 * take a DER CRL and decode it into a CRL structure
533 */
534 CERTSignedCrl *
535 CERT_DecodeDERCrl(PLArenaPool *narena, SECItem *derSignedCrl, int type)
536 {
537 return CERT_DecodeDERCrlWithFlags(narena, derSignedCrl, type,
538 CRL_DECODE_DEFAULT_OPTIONS);
539 }
540
541 /*
542 * Lookup a CRL in the databases. We mirror the same fast caching data base
543 * caching stuff used by certificates....?
544 * return values :
545 *
546 * SECSuccess means we got a valid decodable DER CRL, or no CRL at all.
547 * Caller may distinguish those cases by the value returned in "decoded".
548 * When DER CRL is not found, error code will be SEC_ERROR_CRL_NOT_FOUND.
549 *
550 * SECFailure means we got a fatal error - most likely, we found a CRL,
551 * and it failed decoding, or there was an out of memory error. Do NOT ignore
552 * it and specifically do NOT treat it the same as having no CRL, as this
553 * can compromise security !!! Ideally, you should treat this case as if you
554 * received a "catch-all" CRL where all certs you were looking up are
555 * considered to be revoked
556 */
557 static SECStatus
558 SEC_FindCrlByKeyOnSlot(PK11SlotInfo *slot, SECItem *crlKey, int type,
559 CERTSignedCrl** decoded, PRInt32 decodeoptions)
560 {
561 SECStatus rv = SECSuccess;
562 CERTSignedCrl *crl = NULL;
563 SECItem *derCrl = NULL;
564 CK_OBJECT_HANDLE crlHandle = 0;
565 char *url = NULL;
566
567 PORT_Assert(decoded);
568 if (!decoded) {
569 PORT_SetError(SEC_ERROR_INVALID_ARGS);
570 return SECFailure;
571 }
572
573 derCrl = PK11_FindCrlByName(&slot, &crlHandle, crlKey, type, &url);
574 if (derCrl == NULL) {
575 /* if we had a problem other than the CRL just didn't exist, return
576 * a failure to the upper level */
577 int nsserror = PORT_GetError();
578 if (nsserror != SEC_ERROR_CRL_NOT_FOUND) {
579 rv = SECFailure;
580 }
581 goto loser;
582 }
583 PORT_Assert(crlHandle != CK_INVALID_HANDLE);
584 /* PK11_FindCrlByName obtained a slot reference. */
585
586 /* derCRL is a fresh HEAP copy made for us by PK11_FindCrlByName.
587 Force adoption of the DER CRL from the heap - this will cause it
588 to be automatically freed when SEC_DestroyCrl is invoked */
589 decodeoptions |= (CRL_DECODE_ADOPT_HEAP_DER | CRL_DECODE_DONT_COPY_DER);
590
591 crl = CERT_DecodeDERCrlWithFlags(NULL, derCrl, type, decodeoptions);
592 if (crl) {
593 crl->slot = slot;
594 slot = NULL; /* adopt it */
595 derCrl = NULL; /* adopted by the crl struct */
596 crl->pkcs11ID = crlHandle;
597 if (url) {
598 crl->url = PORT_ArenaStrdup(crl->arena,url);
599 }
600 } else {
601 rv = SECFailure;
602 }
603
604 if (url) {
605 PORT_Free(url);
606 }
607
608 if (slot) {
609 PK11_FreeSlot(slot);
610 }
611
612 loser:
613 if (derCrl) {
614 SECITEM_FreeItem(derCrl, PR_TRUE);
615 }
616
617 *decoded = crl;
618
619 return rv;
620 }
621
622
623 CERTSignedCrl *
624 crl_storeCRL (PK11SlotInfo *slot,char *url,
625 CERTSignedCrl *newCrl, SECItem *derCrl, int type)
626 {
627 CERTSignedCrl *oldCrl = NULL, *crl = NULL;
628 PRBool deleteOldCrl = PR_FALSE;
629 CK_OBJECT_HANDLE crlHandle = CK_INVALID_HANDLE;
630 SECStatus rv;
631
632 PORT_Assert(newCrl);
633 PORT_Assert(derCrl);
634 PORT_Assert(type == SEC_CRL_TYPE);
635
636 if (type != SEC_CRL_TYPE) {
637 PORT_SetError(SEC_ERROR_INVALID_ARGS);
638 return NULL;
639 }
640
641 /* we can't use the cache here because we must look in the same
642 token */
643 rv = SEC_FindCrlByKeyOnSlot(slot, &newCrl->crl.derName, type,
644 &oldCrl, CRL_DECODE_SKIP_ENTRIES);
645 /* if there is an old crl on the token, make sure the one we are
646 installing is newer. If not, exit out, otherwise delete the
647 old crl.
648 */
649 if (oldCrl != NULL) {
650 /* if it's already there, quietly continue */
651 if (SECITEM_CompareItem(newCrl->derCrl, oldCrl->derCrl)
652 == SECEqual) {
653 crl = newCrl;
654 crl->slot = PK11_ReferenceSlot(slot);
655 crl->pkcs11ID = oldCrl->pkcs11ID;
656 if (oldCrl->url && !url)
657 url = oldCrl->url;
658 if (url)
659 crl->url = PORT_ArenaStrdup(crl->arena, url);
660 goto done;
661 }
662 if (!SEC_CrlIsNewer(&newCrl->crl,&oldCrl->crl)) {
663 PORT_SetError(SEC_ERROR_OLD_CRL);
664 goto done;
665 }
666
667 /* if we have a url in the database, use that one */
668 if (oldCrl->url && !url) {
669 url = oldCrl->url;
670 }
671
672 /* really destroy this crl */
673 /* first drum it out of the permanment Data base */
674 deleteOldCrl = PR_TRUE;
675 }
676
677 /* invalidate CRL cache for this issuer */
678 CERT_CRLCacheRefreshIssuer(NULL, &newCrl->crl.derName);
679 /* Write the new entry into the data base */
680 crlHandle = PK11_PutCrl(slot, derCrl, &newCrl->crl.derName, url, type);
681 if (crlHandle != CK_INVALID_HANDLE) {
682 crl = newCrl;
683 crl->slot = PK11_ReferenceSlot(slot);
684 crl->pkcs11ID = crlHandle;
685 if (url) {
686 crl->url = PORT_ArenaStrdup(crl->arena,url);
687 }
688 }
689
690 done:
691 if (oldCrl) {
692 if (deleteOldCrl && crlHandle != CK_INVALID_HANDLE) {
693 SEC_DeletePermCRL(oldCrl);
694 }
695 SEC_DestroyCrl(oldCrl);
696 }
697
698 return crl;
699 }
700
701 /*
702 *
703 * create a new CRL from DER material.
704 *
705 * The signature on this CRL must be checked before you
706 * load it. ???
707 */
708 CERTSignedCrl *
709 SEC_NewCrl(CERTCertDBHandle *handle, char *url, SECItem *derCrl, int type)
710 {
711 CERTSignedCrl* retCrl = NULL;
712 PK11SlotInfo* slot = PK11_GetInternalKeySlot();
713 retCrl = PK11_ImportCRL(slot, derCrl, url, type, NULL,
714 CRL_IMPORT_BYPASS_CHECKS, NULL, CRL_DECODE_DEFAULT_OPTIONS);
715 PK11_FreeSlot(slot);
716
717 return retCrl;
718 }
719
720 CERTSignedCrl *
721 SEC_FindCrlByDERCert(CERTCertDBHandle *handle, SECItem *derCrl, int type)
722 {
723 PLArenaPool *arena;
724 SECItem crlKey;
725 SECStatus rv;
726 CERTSignedCrl *crl = NULL;
727
728 /* create a scratch arena */
729 arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
730 if ( arena == NULL ) {
731 return(NULL);
732 }
733
734 /* extract the database key from the cert */
735 rv = CERT_KeyFromDERCrl(arena, derCrl, &crlKey);
736 if ( rv != SECSuccess ) {
737 goto loser;
738 }
739
740 /* find the crl */
741 crl = SEC_FindCrlByName(handle, &crlKey, type);
742
743 loser:
744 PORT_FreeArena(arena, PR_FALSE);
745 return(crl);
746 }
747
748 CERTSignedCrl* SEC_DupCrl(CERTSignedCrl* acrl)
749 {
750 if (acrl)
751 {
752 PR_ATOMIC_INCREMENT(&acrl->referenceCount);
753 return acrl;
754 }
755 return NULL;
756 }
757
758 SECStatus
759 SEC_DestroyCrl(CERTSignedCrl *crl)
760 {
761 if (crl) {
762 if (PR_ATOMIC_DECREMENT(&crl->referenceCount) < 1) {
763 if (crl->slot) {
764 PK11_FreeSlot(crl->slot);
765 }
766 if (GetOpaqueCRLFields(crl) &&
767 PR_TRUE == GetOpaqueCRLFields(crl)->heapDER) {
768 SECITEM_FreeItem(crl->derCrl, PR_TRUE);
769 }
770 if (crl->arena) {
771 PORT_FreeArena(crl->arena, PR_FALSE);
772 }
773 }
774 return SECSuccess;
775 } else {
776 return SECFailure;
777 }
778 }
779
780 SECStatus
781 SEC_LookupCrls(CERTCertDBHandle *handle, CERTCrlHeadNode **nodes, int type)
782 {
783 CERTCrlHeadNode *head;
784 PLArenaPool *arena = NULL;
785 SECStatus rv;
786
787 *nodes = NULL;
788
789 arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
790 if ( arena == NULL ) {
791 return SECFailure;
792 }
793
794 /* build a head structure */
795 head = (CERTCrlHeadNode *)PORT_ArenaAlloc(arena, sizeof(CERTCrlHeadNode));
796 head->arena = arena;
797 head->first = NULL;
798 head->last = NULL;
799 head->dbhandle = handle;
800
801 /* Look up the proper crl types */
802 *nodes = head;
803
804 rv = PK11_LookupCrls(head, type, NULL);
805
806 if (rv != SECSuccess) {
807 if ( arena ) {
808 PORT_FreeArena(arena, PR_FALSE);
809 *nodes = NULL;
810 }
811 }
812
813 return rv;
814 }
815
816 /* These functions simply return the address of the above-declared templates.
817 ** This is necessary for Windows DLLs. Sigh.
818 */
819 SEC_ASN1_CHOOSER_IMPLEMENT(CERT_IssuerAndSNTemplate)
820 SEC_ASN1_CHOOSER_IMPLEMENT(CERT_CrlTemplate)
821 SEC_ASN1_CHOOSER_IMPLEMENT(CERT_SignedCrlTemplate)
822 SEC_ASN1_CHOOSER_IMPLEMENT(CERT_SetOfSignedCrlTemplate)
823
824 /* CRL cache code starts here */
825
826 /* constructor */
827 static SECStatus CachedCrl_Create(CachedCrl** returned, CERTSignedCrl* crl,
828 CRLOrigin origin);
829 /* destructor */
830 static SECStatus CachedCrl_Destroy(CachedCrl* crl);
831
832 /* create hash table of CRL entries */
833 static SECStatus CachedCrl_Populate(CachedCrl* crlobject);
834
835 /* empty the cache content */
836 static SECStatus CachedCrl_Depopulate(CachedCrl* crl);
837
838 /* are these CRLs the same, as far as the cache is concerned ?
839 Or are they the same token object, but with different DER ? */
840
841 static SECStatus CachedCrl_Compare(CachedCrl* a, CachedCrl* b, PRBool* isDupe,
842 PRBool* isUpdated);
843
844 /* create a DPCache object */
845 static SECStatus DPCache_Create(CRLDPCache** returned, CERTCertificate* issuer,
846 const SECItem* subject, SECItem* dp);
847
848 /* destructor for CRL DPCache object */
849 static SECStatus DPCache_Destroy(CRLDPCache* cache);
850
851 /* add a new CRL object to the dynamic array of CRLs of the DPCache, and
852 returns the cached CRL object . Needs write access to DPCache. */
853 static SECStatus DPCache_AddCRL(CRLDPCache* cache, CachedCrl* crl,
854 PRBool* added);
855
856 /* fetch the CRL for this DP from the PKCS#11 tokens */
857 static SECStatus DPCache_FetchFromTokens(CRLDPCache* cache, PRTime vfdate,
858 void* wincx);
859
860 /* update the content of the CRL cache, including fetching of CRLs, and
861 reprocessing with specified issuer and date */
862 static SECStatus DPCache_GetUpToDate(CRLDPCache* cache, CERTCertificate* issuer,
863 PRBool readlocked, PRTime vfdate, void* wincx);
864
865 /* returns true if there are CRLs from PKCS#11 slots */
866 static PRBool DPCache_HasTokenCRLs(CRLDPCache* cache);
867
868 /* remove CRL at offset specified */
869 static SECStatus DPCache_RemoveCRL(CRLDPCache* cache, PRUint32 offset);
870
871 /* Pick best CRL to use . needs write access */
872 static SECStatus DPCache_SelectCRL(CRLDPCache* cache);
873
874 /* create an issuer cache object (per CA subject ) */
875 static SECStatus IssuerCache_Create(CRLIssuerCache** returned,
876 CERTCertificate* issuer,
877 const SECItem* subject, const SECItem* dp);
878
879 /* destructor for CRL IssuerCache object */
880 SECStatus IssuerCache_Destroy(CRLIssuerCache* cache);
881
882 /* add a DPCache to the issuer cache */
883 static SECStatus IssuerCache_AddDP(CRLIssuerCache* cache,
884 CERTCertificate* issuer,
885 const SECItem* subject,
886 const SECItem* dp, CRLDPCache** newdpc);
887
888 /* get a particular DPCache object from an IssuerCache */
889 static CRLDPCache* IssuerCache_GetDPCache(CRLIssuerCache* cache,
890 const SECItem* dp);
891
892 /*
893 ** Pre-allocator hash allocator ops.
894 */
895
896 /* allocate memory for hash table */
897 static void * PR_CALLBACK
898 PreAllocTable(void *pool, PRSize size)
899 {
900 PreAllocator* alloc = (PreAllocator*)pool;
901 PORT_Assert(alloc);
902 if (!alloc)
903 {
904 /* no allocator, or buffer full */
905 return NULL;
906 }
907 if (size > (alloc->len - alloc->used))
908 {
909 /* initial buffer full, let's use the arena */
910 alloc->extra += size;
911 return PORT_ArenaAlloc(alloc->arena, size);
912 }
913 /* use the initial buffer */
914 alloc->used += size;
915 return (char*) alloc->data + alloc->used - size;
916 }
917
918 /* free hash table memory.
919 Individual PreAllocator elements cannot be freed, so this is a no-op. */
920 static void PR_CALLBACK
921 PreFreeTable(void *pool, void *item)
922 {
923 }
924
925 /* allocate memory for hash table */
926 static PLHashEntry * PR_CALLBACK
927 PreAllocEntry(void *pool, const void *key)
928 {
929 return PreAllocTable(pool, sizeof(PLHashEntry));
930 }
931
932 /* free hash table entry.
933 Individual PreAllocator elements cannot be freed, so this is a no-op. */
934 static void PR_CALLBACK
935 PreFreeEntry(void *pool, PLHashEntry *he, PRUintn flag)
936 {
937 }
938
939 /* methods required for PL hash table functions */
940 static PLHashAllocOps preAllocOps =
941 {
942 PreAllocTable, PreFreeTable,
943 PreAllocEntry, PreFreeEntry
944 };
945
946 /* destructor for PreAllocator object */
947 void PreAllocator_Destroy(PreAllocator* PreAllocator)
948 {
949 if (!PreAllocator)
950 {
951 return;
952 }
953 if (PreAllocator->arena)
954 {
955 PORT_FreeArena(PreAllocator->arena, PR_TRUE);
956 }
957 }
958
959 /* constructor for PreAllocator object */
960 PreAllocator* PreAllocator_Create(PRSize size)
961 {
962 PLArenaPool* arena = NULL;
963 PreAllocator* prebuffer = NULL;
964 arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
965 if (!arena)
966 {
967 return NULL;
968 }
969 prebuffer = (PreAllocator*)PORT_ArenaZAlloc(arena,
970 sizeof(PreAllocator));
971 if (!prebuffer)
972 {
973 PORT_FreeArena(arena, PR_TRUE);
974 return NULL;
975 }
976 prebuffer->arena = arena;
977
978 if (size)
979 {
980 prebuffer->len = size;
981 prebuffer->data = PORT_ArenaAlloc(arena, size);
982 if (!prebuffer->data)
983 {
984 PORT_FreeArena(arena, PR_TRUE);
985 return NULL;
986 }
987 }
988 return prebuffer;
989 }
990
991 /* global Named CRL cache object */
992 static NamedCRLCache namedCRLCache = { NULL, NULL };
993
994 /* global CRL cache object */
995 static CRLCache crlcache = { NULL, NULL };
996
997 /* initial state is off */
998 static PRBool crlcache_initialized = PR_FALSE;
999
1000 PRTime CRLCache_Empty_TokenFetch_Interval = 60 * 1000000; /* how often
1001 to query the tokens for CRL objects, in order to discover new objects, if
1002 the cache does not contain any token CRLs . In microseconds */
1003
1004 PRTime CRLCache_TokenRefetch_Interval = 600 * 1000000 ; /* how often
1005 to query the tokens for CRL objects, in order to discover new objects, if
1006 the cache already contains token CRLs In microseconds */
1007
1008 PRTime CRLCache_ExistenceCheck_Interval = 60 * 1000000; /* how often to check
1009 if a token CRL object still exists. In microseconds */
1010
1011 /* this function is called at NSS initialization time */
1012 SECStatus InitCRLCache(void)
1013 {
1014 if (PR_FALSE == crlcache_initialized)
1015 {
1016 PORT_Assert(NULL == crlcache.lock);
1017 PORT_Assert(NULL == crlcache.issuers);
1018 PORT_Assert(NULL == namedCRLCache.lock);
1019 PORT_Assert(NULL == namedCRLCache.entries);
1020 if (crlcache.lock || crlcache.issuers || namedCRLCache.lock ||
1021 namedCRLCache.entries)
1022 {
1023 /* CRL cache already partially initialized */
1024 PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
1025 return SECFailure;
1026 }
1027 #ifdef GLOBAL_RWLOCK
1028 crlcache.lock = NSSRWLock_New(NSS_RWLOCK_RANK_NONE, NULL);
1029 #else
1030 crlcache.lock = PR_NewLock();
1031 #endif
1032 namedCRLCache.lock = PR_NewLock();
1033 crlcache.issuers = PL_NewHashTable(0, SECITEM_Hash, SECITEM_HashCompare,
1034 PL_CompareValues, NULL, NULL);
1035 namedCRLCache.entries = PL_NewHashTable(0, SECITEM_Hash, SECITEM_HashCompare,
1036 PL_CompareValues, NULL, NULL);
1037 if (!crlcache.lock || !namedCRLCache.lock || !crlcache.issuers ||
1038 !namedCRLCache.entries)
1039 {
1040 if (crlcache.lock)
1041 {
1042 #ifdef GLOBAL_RWLOCK
1043 NSSRWLock_Destroy(crlcache.lock);
1044 #else
1045 PR_DestroyLock(crlcache.lock);
1046 #endif
1047 crlcache.lock = NULL;
1048 }
1049 if (namedCRLCache.lock)
1050 {
1051 PR_DestroyLock(namedCRLCache.lock);
1052 namedCRLCache.lock = NULL;
1053 }
1054 if (crlcache.issuers)
1055 {
1056 PL_HashTableDestroy(crlcache.issuers);
1057 crlcache.issuers = NULL;
1058 }
1059 if (namedCRLCache.entries)
1060 {
1061 PL_HashTableDestroy(namedCRLCache.entries);
1062 namedCRLCache.entries = NULL;
1063 }
1064
1065 return SECFailure;
1066 }
1067 crlcache_initialized = PR_TRUE;
1068 return SECSuccess;
1069 }
1070 else
1071 {
1072 PORT_Assert(crlcache.lock);
1073 PORT_Assert(crlcache.issuers);
1074 if ( (NULL == crlcache.lock) || (NULL == crlcache.issuers) )
1075 {
1076 /* CRL cache not fully initialized */
1077 return SECFailure;
1078 }
1079 else
1080 {
1081 /* CRL cache already initialized */
1082 return SECSuccess;
1083 }
1084 }
1085 }
1086
1087 /* destructor for CRL DPCache object */
1088 static SECStatus DPCache_Destroy(CRLDPCache* cache)
1089 {
1090 PRUint32 i = 0;
1091 PORT_Assert(cache);
1092 if (!cache)
1093 {
1094 PORT_Assert(0);
1095 PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
1096 return SECFailure;
1097 }
1098 if (cache->lock)
1099 {
1100 #ifdef DPC_RWLOCK
1101 NSSRWLock_Destroy(cache->lock);
1102 #else
1103 PR_DestroyLock(cache->lock);
1104 #endif
1105 }
1106 else
1107 {
1108 PORT_Assert(0);
1109 return SECFailure;
1110 }
1111 /* destroy all our CRL objects */
1112 for (i=0;i<cache->ncrls;i++)
1113 {
1114 if (!cache->crls || !cache->crls[i] ||
1115 SECSuccess != CachedCrl_Destroy(cache->crls[i]))
1116 {
1117 return SECFailure;
1118 }
1119 }
1120 /* free the array of CRLs */
1121 if (cache->crls)
1122 {
1123 PORT_Free(cache->crls);
1124 }
1125 /* destroy the cert */
1126 if (cache->issuer)
1127 {
1128 CERT_DestroyCertificate(cache->issuer);
1129 }
1130 /* free the subject */
1131 if (cache->subject)
1132 {
1133 SECITEM_FreeItem(cache->subject, PR_TRUE);
1134 }
1135 /* free the distribution points */
1136 if (cache->distributionPoint)
1137 {
1138 SECITEM_FreeItem(cache->distributionPoint, PR_TRUE);
1139 }
1140 PORT_Free(cache);
1141 return SECSuccess;
1142 }
1143
1144 /* destructor for CRL IssuerCache object */
1145 SECStatus IssuerCache_Destroy(CRLIssuerCache* cache)
1146 {
1147 PORT_Assert(cache);
1148 if (!cache)
1149 {
1150 PORT_Assert(0);
1151 PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
1152 return SECFailure;
1153 }
1154 #ifdef XCRL
1155 if (cache->lock)
1156 {
1157 NSSRWLock_Destroy(cache->lock);
1158 }
1159 else
1160 {
1161 PORT_Assert(0);
1162 PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
1163 return SECFailure;
1164 }
1165 if (cache->issuer)
1166 {
1167 CERT_DestroyCertificate(cache->issuer);
1168 }
1169 #endif
1170 /* free the subject */
1171 if (cache->subject)
1172 {
1173 SECITEM_FreeItem(cache->subject, PR_TRUE);
1174 }
1175 if (SECSuccess != DPCache_Destroy(cache->dpp))
1176 {
1177 PORT_Assert(0);
1178 return SECFailure;
1179 }
1180 PORT_Free(cache);
1181 return SECSuccess;
1182 }
1183
1184 /* create a named CRL entry object */
1185 static SECStatus NamedCRLCacheEntry_Create(NamedCRLCacheEntry** returned)
1186 {
1187 NamedCRLCacheEntry* entry = NULL;
1188 if (!returned)
1189 {
1190 PORT_Assert(0);
1191 PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
1192 return SECFailure;
1193 }
1194 *returned = NULL;
1195 entry = (NamedCRLCacheEntry*) PORT_ZAlloc(sizeof(NamedCRLCacheEntry));
1196 if (!entry)
1197 {
1198 return SECFailure;
1199 }
1200 *returned = entry;
1201 return SECSuccess;
1202 }
1203
1204 /* destroy a named CRL entry object */
1205 static SECStatus NamedCRLCacheEntry_Destroy(NamedCRLCacheEntry* entry)
1206 {
1207 if (!entry)
1208 {
1209 PORT_Assert(0);
1210 PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
1211 return SECFailure;
1212 }
1213 if (entry->crl)
1214 {
1215 /* named CRL cache owns DER memory */
1216 SECITEM_ZfreeItem(entry->crl, PR_TRUE);
1217 }
1218 if (entry->canonicalizedName)
1219 {
1220 SECITEM_FreeItem(entry->canonicalizedName, PR_TRUE);
1221 }
1222 PORT_Free(entry);
1223 return SECSuccess;
1224 }
1225
1226 /* callback function used in hash table destructor */
1227 static PRIntn PR_CALLBACK FreeIssuer(PLHashEntry *he, PRIntn i, void *arg)
1228 {
1229 CRLIssuerCache* issuer = NULL;
1230 SECStatus* rv = (SECStatus*) arg;
1231
1232 PORT_Assert(he);
1233 if (!he)
1234 {
1235 return HT_ENUMERATE_NEXT;
1236 }
1237 issuer = (CRLIssuerCache*) he->value;
1238 PORT_Assert(issuer);
1239 if (issuer)
1240 {
1241 if (SECSuccess != IssuerCache_Destroy(issuer))
1242 {
1243 PORT_Assert(rv);
1244 if (rv)
1245 {
1246 *rv = SECFailure;
1247 }
1248 return HT_ENUMERATE_NEXT;
1249 }
1250 }
1251 return HT_ENUMERATE_NEXT;
1252 }
1253
1254 /* callback function used in hash table destructor */
1255 static PRIntn PR_CALLBACK FreeNamedEntries(PLHashEntry *he, PRIntn i, void *arg)
1256 {
1257 NamedCRLCacheEntry* entry = NULL;
1258 SECStatus* rv = (SECStatus*) arg;
1259
1260 PORT_Assert(he);
1261 if (!he)
1262 {
1263 return HT_ENUMERATE_NEXT;
1264 }
1265 entry = (NamedCRLCacheEntry*) he->value;
1266 PORT_Assert(entry);
1267 if (entry)
1268 {
1269 if (SECSuccess != NamedCRLCacheEntry_Destroy(entry))
1270 {
1271 PORT_Assert(rv);
1272 if (rv)
1273 {
1274 *rv = SECFailure;
1275 }
1276 return HT_ENUMERATE_NEXT;
1277 }
1278 }
1279 return HT_ENUMERATE_NEXT;
1280 }
1281
1282 /* needs to be called at NSS shutdown time
1283 This will destroy the global CRL cache, including
1284 - the hash table of issuer cache objects
1285 - the issuer cache objects
1286 - DPCache objects in issuer cache objects */
1287 SECStatus ShutdownCRLCache(void)
1288 {
1289 SECStatus rv = SECSuccess;
1290 if (PR_FALSE == crlcache_initialized &&
1291 !crlcache.lock && !crlcache.issuers)
1292 {
1293 /* CRL cache has already been shut down */
1294 return SECSuccess;
1295 }
1296 if (PR_TRUE == crlcache_initialized &&
1297 (!crlcache.lock || !crlcache.issuers || !namedCRLCache.lock ||
1298 !namedCRLCache.entries))
1299 {
1300 /* CRL cache has partially been shut down */
1301 PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
1302 return SECFailure;
1303 }
1304 /* empty the CRL cache */
1305 /* free the issuers */
1306 PL_HashTableEnumerateEntries(crlcache.issuers, &FreeIssuer, &rv);
1307 /* free the hash table of issuers */
1308 PL_HashTableDestroy(crlcache.issuers);
1309 crlcache.issuers = NULL;
1310 /* free the global lock */
1311 #ifdef GLOBAL_RWLOCK
1312 NSSRWLock_Destroy(crlcache.lock);
1313 #else
1314 PR_DestroyLock(crlcache.lock);
1315 #endif
1316 crlcache.lock = NULL;
1317
1318 /* empty the named CRL cache. This must be done after freeing the CRL
1319 * cache, since some CRLs in this cache are in the memory for the other */
1320 /* free the entries */
1321 PL_HashTableEnumerateEntries(namedCRLCache.entries, &FreeNamedEntries, &rv);
1322 /* free the hash table of issuers */
1323 PL_HashTableDestroy(namedCRLCache.entries);
1324 namedCRLCache.entries = NULL;
1325 /* free the global lock */
1326 PR_DestroyLock(namedCRLCache.lock);
1327 namedCRLCache.lock = NULL;
1328
1329 crlcache_initialized = PR_FALSE;
1330 return rv;
1331 }
1332
1333 /* add a new CRL object to the dynamic array of CRLs of the DPCache, and
1334 returns the cached CRL object . Needs write access to DPCache. */
1335 static SECStatus DPCache_AddCRL(CRLDPCache* cache, CachedCrl* newcrl,
1336 PRBool* added)
1337 {
1338 CachedCrl** newcrls = NULL;
1339 PRUint32 i = 0;
1340 PORT_Assert(cache);
1341 PORT_Assert(newcrl);
1342 PORT_Assert(added);
1343 if (!cache || !newcrl || !added)
1344 {
1345 PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
1346 return SECFailure;
1347 }
1348
1349 *added = PR_FALSE;
1350 /* before adding a new CRL, check if it is a duplicate */
1351 for (i=0;i<cache->ncrls;i++)
1352 {
1353 CachedCrl* existing = NULL;
1354 SECStatus rv = SECSuccess;
1355 PRBool dupe = PR_FALSE, updated = PR_FALSE;
1356 if (!cache->crls)
1357 {
1358 PORT_Assert(0);
1359 return SECFailure;
1360 }
1361 existing = cache->crls[i];
1362 if (!existing)
1363 {
1364 PORT_Assert(0);
1365 return SECFailure;
1366 }
1367 rv = CachedCrl_Compare(existing, newcrl, &dupe, &updated);
1368 if (SECSuccess != rv)
1369 {
1370 PORT_Assert(0);
1371 PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
1372 return SECFailure;
1373 }
1374 if (PR_TRUE == dupe)
1375 {
1376 /* dupe */
1377 PORT_SetError(SEC_ERROR_CRL_ALREADY_EXISTS);
1378 return SECSuccess;
1379 }
1380 if (PR_TRUE == updated)
1381 {
1382 /* this token CRL is in the same slot and has the same object ID,
1383 but different content. We need to remove the old object */
1384 if (SECSuccess != DPCache_RemoveCRL(cache, i))
1385 {
1386 PORT_Assert(0);
1387 PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
1388 return PR_FALSE;
1389 }
1390 }
1391 }
1392
1393 newcrls = (CachedCrl**)PORT_Realloc(cache->crls,
1394 (cache->ncrls+1)*sizeof(CachedCrl*));
1395 if (!newcrls)
1396 {
1397 return SECFailure;
1398 }
1399 cache->crls = newcrls;
1400 cache->ncrls++;
1401 cache->crls[cache->ncrls-1] = newcrl;
1402 *added = PR_TRUE;
1403 return SECSuccess;
1404 }
1405
1406 /* remove CRL at offset specified */
1407 static SECStatus DPCache_RemoveCRL(CRLDPCache* cache, PRUint32 offset)
1408 {
1409 CachedCrl* acrl = NULL;
1410 PORT_Assert(cache);
1411 if (!cache || (!cache->crls) || (!(offset<cache->ncrls)) )
1412 {
1413 PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
1414 return SECFailure;
1415 }
1416 acrl = cache->crls[offset];
1417 PORT_Assert(acrl);
1418 if (!acrl)
1419 {
1420 PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
1421 return SECFailure;
1422 }
1423 cache->crls[offset] = cache->crls[cache->ncrls-1];
1424 cache->crls[cache->ncrls-1] = NULL;
1425 cache->ncrls--;
1426 if (cache->selected == acrl) {
1427 cache->selected = NULL;
1428 }
1429 if (SECSuccess != CachedCrl_Destroy(acrl))
1430 {
1431 PORT_Assert(0);
1432 PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
1433 return SECFailure;
1434 }
1435 return SECSuccess;
1436 }
1437
1438 /* check whether a CRL object stored in a PKCS#11 token still exists in
1439 that token . This has to be efficient (the entire CRL value cannot be
1440 transferred accross the token boundaries), so this is accomplished by
1441 simply fetching the subject attribute and making sure it hasn't changed .
1442 Note that technically, the CRL object could have been replaced with a new
1443 PKCS#11 object of the same ID and subject (which actually happens in
1444 softoken), but this function has no way of knowing that the object
1445 value changed, since CKA_VALUE isn't checked. */
1446 static PRBool TokenCRLStillExists(CERTSignedCrl* crl)
1447 {
1448 NSSItem newsubject;
1449 SECItem subject;
1450 CK_ULONG crl_class;
1451 PRStatus status;
1452 PK11SlotInfo* slot = NULL;
1453 nssCryptokiObject instance;
1454 NSSArena* arena;
1455 PRBool xstatus = PR_TRUE;
1456 SECItem* oldSubject = NULL;
1457
1458 PORT_Assert(crl);
1459 if (!crl)
1460 {
1461 return PR_FALSE;
1462 }
1463 slot = crl->slot;
1464 PORT_Assert(crl->slot);
1465 if (!slot)
1466 {
1467 return PR_FALSE;
1468 }
1469 oldSubject = &crl->crl.derName;
1470 PORT_Assert(oldSubject);
1471 if (!oldSubject)
1472 {
1473 return PR_FALSE;
1474 }
1475
1476 /* query subject and type attributes in order to determine if the
1477 object has been deleted */
1478
1479 /* first, make an nssCryptokiObject */
1480 instance.handle = crl->pkcs11ID;
1481 PORT_Assert(instance.handle);
1482 if (!instance.handle)
1483 {
1484 return PR_FALSE;
1485 }
1486 instance.token = PK11Slot_GetNSSToken(slot);
1487 PORT_Assert(instance.token);
1488 if (!instance.token)
1489 {
1490 return PR_FALSE;
1491 }
1492 instance.isTokenObject = PR_TRUE;
1493 instance.label = NULL;
1494
1495 arena = NSSArena_Create();
1496 PORT_Assert(arena);
1497 if (!arena)
1498 {
1499 return PR_FALSE;
1500 }
1501
1502 status = nssCryptokiCRL_GetAttributes(&instance,
1503 NULL, /* XXX sessionOpt */
1504 arena,
1505 NULL,
1506 &newsubject, /* subject */
1507 &crl_class, /* class */
1508 NULL,
1509 NULL);
1510 if (PR_SUCCESS == status)
1511 {
1512 subject.data = newsubject.data;
1513 subject.len = newsubject.size;
1514 if (SECITEM_CompareItem(oldSubject, &subject) != SECEqual)
1515 {
1516 xstatus = PR_FALSE;
1517 }
1518 if (CKO_NETSCAPE_CRL != crl_class)
1519 {
1520 xstatus = PR_FALSE;
1521 }
1522 }
1523 else
1524 {
1525 xstatus = PR_FALSE;
1526 }
1527 NSSArena_Destroy(arena);
1528 return xstatus;
1529 }
1530
1531 /* verify the signature of a CRL against its issuer at a given date */
1532 static SECStatus CERT_VerifyCRL(
1533 CERTSignedCrl* crlobject,
1534 CERTCertificate* issuer,
1535 PRTime vfdate,
1536 void* wincx)
1537 {
1538 return CERT_VerifySignedData(&crlobject->signatureWrap,
1539 issuer, vfdate, wincx);
1540 }
1541
1542 /* verify a CRL and update cache state */
1543 static SECStatus CachedCrl_Verify(CRLDPCache* cache, CachedCrl* crlobject,
1544 PRTime vfdate, void* wincx)
1545 {
1546 /* Check if it is an invalid CRL
1547 if we got a bad CRL, we want to cache it in order to avoid
1548 subsequent fetches of this same identical bad CRL. We set
1549 the cache to the invalid state to ensure that all certs on this
1550 DP are considered to have unknown status from now on. The cache
1551 object will remain in this state until the bad CRL object
1552 is removed from the token it was fetched from. If the cause
1553 of the failure is that we didn't have the issuer cert to
1554 verify the signature, this state can be cleared when
1555 the issuer certificate becomes available if that causes the
1556 signature to verify */
1557
1558 if (!cache || !crlobject)
1559 {
1560 PORT_Assert(0);
1561 PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
1562 return SECFailure;
1563 }
1564 if (PR_TRUE == GetOpaqueCRLFields(crlobject->crl)->decodingError)
1565 {
1566 crlobject->sigChecked = PR_TRUE; /* we can never verify a CRL
1567 with bogus DER. Mark it checked so we won't try again */
1568 PORT_SetError(SEC_ERROR_BAD_DER);
1569 return SECSuccess;
1570 }
1571 else
1572 {
1573 SECStatus signstatus = SECFailure;
1574 if (cache->issuer)
1575 {
1576 signstatus = CERT_VerifyCRL(crlobject->crl, cache->issuer, vfdate,
1577 wincx);
1578 }
1579 if (SECSuccess != signstatus)
1580 {
1581 if (!cache->issuer)
1582 {
1583 /* we tried to verify without an issuer cert . This is
1584 because this CRL came through a call to SEC_FindCrlByName.
1585 So, we don't cache this verification failure. We'll try
1586 to verify the CRL again when a certificate from that issuer
1587 becomes available */
1588 } else
1589 {
1590 crlobject->sigChecked = PR_TRUE;
1591 }
1592 PORT_SetError(SEC_ERROR_CRL_BAD_SIGNATURE);
1593 return SECSuccess;
1594 } else
1595 {
1596 crlobject->sigChecked = PR_TRUE;
1597 crlobject->sigValid = PR_TRUE;
1598 }
1599 }
1600
1601 return SECSuccess;
1602 }
1603
1604 /* fetch the CRLs for this DP from the PKCS#11 tokens */
1605 static SECStatus DPCache_FetchFromTokens(CRLDPCache* cache, PRTime vfdate,
1606 void* wincx)
1607 {
1608 SECStatus rv = SECSuccess;
1609 CERTCrlHeadNode head;
1610 if (!cache)
1611 {
1612 PORT_Assert(0);
1613 PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
1614 return SECFailure;
1615 }
1616 /* first, initialize list */
1617 memset(&head, 0, sizeof(head));
1618 head.arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
1619 rv = pk11_RetrieveCrls(&head, cache->subject, wincx);
1620
1621 /* if this function fails, something very wrong happened, such as an out
1622 of memory error during CRL decoding. We don't want to proceed and must
1623 mark the cache object invalid */
1624 if (SECFailure == rv)
1625 {
1626 /* fetch failed, add error bit */
1627 cache->invalid |= CRL_CACHE_LAST_FETCH_FAILED;
1628 } else
1629 {
1630 /* fetch was successful, clear this error bit */
1631 cache->invalid &= (~CRL_CACHE_LAST_FETCH_FAILED);
1632 }
1633
1634 /* add any CRLs found to our array */
1635 if (SECSuccess == rv)
1636 {
1637 CERTCrlNode* crlNode = NULL;
1638
1639 for (crlNode = head.first; crlNode ; crlNode = crlNode->next)
1640 {
1641 CachedCrl* returned = NULL;
1642 CERTSignedCrl* crlobject = crlNode->crl;
1643 if (!crlobject)
1644 {
1645 PORT_Assert(0);
1646 continue;
1647 }
1648 rv = CachedCrl_Create(&returned, crlobject, CRL_OriginToken);
1649 if (SECSuccess == rv)
1650 {
1651 PRBool added = PR_FALSE;
1652 rv = DPCache_AddCRL(cache, returned, &added);
1653 if (PR_TRUE != added)
1654 {
1655 rv = CachedCrl_Destroy(returned);
1656 returned = NULL;
1657 }
1658 else if (vfdate)
1659 {
1660 rv = CachedCrl_Verify(cache, returned, vfdate, wincx);
1661 }
1662 }
1663 else
1664 {
1665 /* not enough memory to add the CRL to the cache. mark it
1666 invalid so we will try again . */
1667 cache->invalid |= CRL_CACHE_LAST_FETCH_FAILED;
1668 }
1669 if (SECFailure == rv)
1670 {
1671 break;
1672 }
1673 }
1674 }
1675
1676 if (head.arena)
1677 {
1678 CERTCrlNode* crlNode = NULL;
1679 /* clean up the CRL list in case we got a partial one
1680 during a failed fetch */
1681 for (crlNode = head.first; crlNode ; crlNode = crlNode->next)
1682 {
1683 if (crlNode->crl)
1684 {
1685 SEC_DestroyCrl(crlNode->crl); /* free the CRL. Either it got
1686 added to the cache and the refcount got bumped, or not, and
1687 thus we need to free its RAM */
1688 }
1689 }
1690 PORT_FreeArena(head.arena, PR_FALSE); /* destroy CRL list */
1691 }
1692
1693 return rv;
1694 }
1695
1696 static SECStatus CachedCrl_GetEntry(CachedCrl* crl, const SECItem* sn,
1697 CERTCrlEntry** returned)
1698 {
1699 CERTCrlEntry* acrlEntry;
1700
1701 PORT_Assert(crl);
1702 PORT_Assert(crl->entries);
1703 PORT_Assert(sn);
1704 PORT_Assert(returned);
1705 if (!crl || !sn || !returned || !crl->entries)
1706 {
1707 PORT_SetError(SEC_ERROR_INVALID_ARGS);
1708 return SECFailure;
1709 }
1710 acrlEntry = PL_HashTableLookup(crl->entries, (void*)sn);
1711 if (acrlEntry)
1712 {
1713 *returned = acrlEntry;
1714 }
1715 else
1716 {
1717 *returned = NULL;
1718 }
1719 return SECSuccess;
1720 }
1721
1722 /* check if a particular SN is in the CRL cache and return its entry */
1723 dpcacheStatus DPCache_Lookup(CRLDPCache* cache, const SECItem* sn,
1724 CERTCrlEntry** returned)
1725 {
1726 SECStatus rv;
1727 if (!cache || !sn || !returned)
1728 {
1729 PORT_SetError(SEC_ERROR_INVALID_ARGS);
1730 /* no cache or SN to look up, or no way to return entry */
1731 return dpcacheCallerError;
1732 }
1733 *returned = NULL;
1734 if (0 != cache->invalid)
1735 {
1736 /* the cache contains a bad CRL, or there was a CRL fetching error. */
1737 PORT_SetError(SEC_ERROR_CRL_INVALID);
1738 return dpcacheInvalidCacheError;
1739 }
1740 if (!cache->selected)
1741 {
1742 /* no CRL means no entry to return. This is OK, except for
1743 * NIST policy */
1744 return dpcacheEmpty;
1745 }
1746 rv = CachedCrl_GetEntry(cache->selected, sn, returned);
1747 if (SECSuccess != rv)
1748 {
1749 return dpcacheLookupError;
1750 }
1751 else
1752 {
1753 if (*returned)
1754 {
1755 return dpcacheFoundEntry;
1756 }
1757 else
1758 {
1759 return dpcacheNoEntry;
1760 }
1761 }
1762 }
1763
1764 #if defined(DPC_RWLOCK)
1765
1766 #define DPCache_LockWrite() \
1767 { \
1768 if (readlocked) \
1769 { \
1770 NSSRWLock_UnlockRead(cache->lock); \
1771 } \
1772 NSSRWLock_LockWrite(cache->lock); \
1773 }
1774
1775 #define DPCache_UnlockWrite() \
1776 { \
1777 if (readlocked) \
1778 { \
1779 NSSRWLock_LockRead(cache->lock); \
1780 } \
1781 NSSRWLock_UnlockWrite(cache->lock); \
1782 }
1783
1784 #else
1785
1786 /* with a global lock, we are always locked for read before we need write
1787 access, so do nothing */
1788
1789 #define DPCache_LockWrite() \
1790 { \
1791 }
1792
1793 #define DPCache_UnlockWrite() \
1794 { \
1795 }
1796
1797 #endif
1798
1799 /* update the content of the CRL cache, including fetching of CRLs, and
1800 reprocessing with specified issuer and date . We are always holding
1801 either the read or write lock on DPCache upon entry. */
1802 static SECStatus DPCache_GetUpToDate(CRLDPCache* cache, CERTCertificate*
1803 issuer, PRBool readlocked, PRTime vfdate,
1804 void* wincx)
1805 {
1806 /* Update the CRLDPCache now. We don't cache token CRL lookup misses
1807 yet, as we have no way of getting notified of new PKCS#11 object
1808 creation that happens in a token */
1809 SECStatus rv = SECSuccess;
1810 PRUint32 i = 0;
1811 PRBool forcedrefresh = PR_FALSE;
1812 PRBool dirty = PR_FALSE; /* whether something was changed in the
1813 cache state during this update cycle */
1814 PRBool hastokenCRLs = PR_FALSE;
1815 PRTime now = 0;
1816 PRTime lastfetch = 0;
1817 PRBool mustunlock = PR_FALSE;
1818
1819 if (!cache)
1820 {
1821 PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
1822 return SECFailure;
1823 }
1824
1825 /* first, make sure we have obtained all the CRLs we need.
1826 We do an expensive token fetch in the following cases :
1827 1) cache is empty because no fetch was ever performed yet
1828 2) cache is explicitly set to refresh state
1829 3) cache is in invalid state because last fetch failed
1830 4) cache contains no token CRLs, and it's been more than one minute
1831 since the last fetch
1832 5) cache contains token CRLs, and it's been more than 10 minutes since
1833 the last fetch
1834 */
1835 forcedrefresh = cache->refresh;
1836 lastfetch = cache->lastfetch;
1837 if (PR_TRUE != forcedrefresh &&
1838 (!(cache->invalid & CRL_CACHE_LAST_FETCH_FAILED)))
1839 {
1840 now = PR_Now();
1841 hastokenCRLs = DPCache_HasTokenCRLs(cache);
1842 }
1843 if ( (0 == lastfetch) ||
1844
1845 (PR_TRUE == forcedrefresh) ||
1846
1847 (cache->invalid & CRL_CACHE_LAST_FETCH_FAILED) ||
1848
1849 ( (PR_FALSE == hastokenCRLs) &&
1850 ( (now - cache->lastfetch > CRLCache_Empty_TokenFetch_Interval) ||
1851 (now < cache->lastfetch)) ) ||
1852
1853 ( (PR_TRUE == hastokenCRLs) &&
1854 ((now - cache->lastfetch > CRLCache_TokenRefetch_Interval) ||
1855 (now < cache->lastfetch)) ) )
1856 {
1857 /* the cache needs to be refreshed, and/or we had zero CRL for this
1858 DP. Try to get one from PKCS#11 tokens */
1859 DPCache_LockWrite();
1860 /* check if another thread updated before us, and skip update if so */
1861 if (lastfetch == cache->lastfetch)
1862 {
1863 /* we are the first */
1864 rv = DPCache_FetchFromTokens(cache, vfdate, wincx);
1865 if (PR_TRUE == cache->refresh)
1866 {
1867 cache->refresh = PR_FALSE; /* clear refresh state */
1868 }
1869 dirty = PR_TRUE;
1870 cache->lastfetch = PR_Now();
1871 }
1872 DPCache_UnlockWrite();
1873 }
1874
1875 /* now, make sure we have no extraneous CRLs (deleted token objects)
1876 we'll do this inexpensive existence check either
1877 1) if there was a token object fetch
1878 2) every minute */
1879 if (( PR_TRUE != dirty) && (!now) )
1880 {
1881 now = PR_Now();
1882 }
1883 if ( (PR_TRUE == dirty) ||
1884 ( (now - cache->lastcheck > CRLCache_ExistenceCheck_Interval) ||
1885 (now < cache->lastcheck)) )
1886 {
1887 PRTime lastcheck = cache->lastcheck;
1888 mustunlock = PR_FALSE;
1889 /* check if all CRLs still exist */
1890 for (i = 0; (i < cache->ncrls) ; i++)
1891 {
1892 CachedCrl* savcrl = cache->crls[i];
1893 if ( (!savcrl) || (savcrl && CRL_OriginToken != savcrl->origin))
1894 {
1895 /* we only want to check token CRLs */
1896 continue;
1897 }
1898 if ((PR_TRUE != TokenCRLStillExists(savcrl->crl)))
1899 {
1900
1901 /* this CRL is gone */
1902 if (PR_TRUE != mustunlock)
1903 {
1904 DPCache_LockWrite();
1905 mustunlock = PR_TRUE;
1906 }
1907 /* first, we need to check if another thread did an update
1908 before we did */
1909 if (lastcheck == cache->lastcheck)
1910 {
1911 /* the CRL is gone. And we are the one to do the update */
1912 DPCache_RemoveCRL(cache, i);
1913 dirty = PR_TRUE;
1914 }
1915 /* stay locked here intentionally so we do all the other
1916 updates in this thread for the remaining CRLs */
1917 }
1918 }
1919 if (PR_TRUE == mustunlock)
1920 {
1921 cache->lastcheck = PR_Now();
1922 DPCache_UnlockWrite();
1923 mustunlock = PR_FALSE;
1924 }
1925 }
1926
1927 /* add issuer certificate if it was previously unavailable */
1928 if (issuer && (NULL == cache->issuer) &&
1929 (SECSuccess == CERT_CheckCertUsage(issuer, KU_CRL_SIGN)))
1930 {
1931 /* if we didn't have a valid issuer cert yet, but we do now. add it */
1932 DPCache_LockWrite();
1933 if (!cache->issuer)
1934 {
1935 dirty = PR_TRUE;
1936 cache->issuer = CERT_DupCertificate(issuer);
1937 }
1938 DPCache_UnlockWrite();
1939 }
1940
1941 /* verify CRLs that couldn't be checked when inserted into the cache
1942 because the issuer cert or a verification date was unavailable.
1943 These are CRLs that were inserted into the cache through
1944 SEC_FindCrlByName, or through manual insertion, rather than through a
1945 certificate verification (CERT_CheckCRL) */
1946
1947 if (cache->issuer && vfdate )
1948 {
1949 mustunlock = PR_FALSE;
1950 /* re-process all unverified CRLs */
1951 for (i = 0; i < cache->ncrls ; i++)
1952 {
1953 CachedCrl* savcrl = cache->crls[i];
1954 if (!savcrl)
1955 {
1956 continue;
1957 }
1958 if (PR_TRUE != savcrl->sigChecked)
1959 {
1960 if (!mustunlock)
1961 {
1962 DPCache_LockWrite();
1963 mustunlock = PR_TRUE;
1964 }
1965 /* first, we need to check if another thread updated
1966 it before we did, and abort if it has been modified since
1967 we acquired the lock. Make sure first that the CRL is still
1968 in the array at the same position */
1969 if ( (i<cache->ncrls) && (savcrl == cache->crls[i]) &&
1970 (PR_TRUE != savcrl->sigChecked) )
1971 {
1972 /* the CRL is still there, unverified. Do it */
1973 CachedCrl_Verify(cache, savcrl, vfdate, wincx);
1974 dirty = PR_TRUE;
1975 }
1976 /* stay locked here intentionally so we do all the other
1977 updates in this thread for the remaining CRLs */
1978 }
1979 if (mustunlock && !dirty)
1980 {
1981 DPCache_UnlockWrite();
1982 mustunlock = PR_FALSE;
1983 }
1984 }
1985 }
1986
1987 if (dirty || cache->mustchoose)
1988 {
1989 /* changes to the content of the CRL cache necessitate examining all
1990 CRLs for selection of the most appropriate one to cache */
1991 if (!mustunlock)
1992 {
1993 DPCache_LockWrite();
1994 mustunlock = PR_TRUE;
1995 }
1996 DPCache_SelectCRL(cache);
1997 cache->mustchoose = PR_FALSE;
1998 }
1999 if (mustunlock)
2000 DPCache_UnlockWrite();
2001
2002 return rv;
2003 }
2004
2005 /* callback for qsort to sort by thisUpdate */
2006 static int SortCRLsByThisUpdate(const void* arg1, const void* arg2)
2007 {
2008 PRTime timea, timeb;
2009 SECStatus rv = SECSuccess;
2010 CachedCrl* a, *b;
2011
2012 a = *(CachedCrl**) arg1;
2013 b = *(CachedCrl**) arg2;
2014
2015 if (!a || !b)
2016 {
2017 PORT_Assert(0);
2018 PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
2019 rv = SECFailure;
2020 }
2021
2022 if (SECSuccess == rv)
2023 {
2024 rv = DER_DecodeTimeChoice(&timea, &a->crl->crl.lastUpdate);
2025 }
2026 if (SECSuccess == rv)
2027 {
2028 rv = DER_DecodeTimeChoice(&timeb, &b->crl->crl.lastUpdate);
2029 }
2030 if (SECSuccess == rv)
2031 {
2032 if (timea > timeb)
2033 {
2034 return 1; /* a is better than b */
2035 }
2036 if (timea < timeb )
2037 {
2038 return -1; /* a is not as good as b */
2039 }
2040 }
2041
2042 /* if they are equal, or if all else fails, use pointer differences */
2043 PORT_Assert(a != b); /* they should never be equal */
2044 return a>b?1:-1;
2045 }
2046
2047 /* callback for qsort to sort a set of disparate CRLs, some of which are
2048 invalid DER or failed signature check.
2049
2050 Validated CRLs are differentiated by thisUpdate .
2051 Validated CRLs are preferred over non-validated CRLs .
2052 Proper DER CRLs are preferred over non-DER data .
2053 */
2054 static int SortImperfectCRLs(const void* arg1, const void* arg2)
2055 {
2056 CachedCrl* a, *b;
2057
2058 a = *(CachedCrl**) arg1;
2059 b = *(CachedCrl**) arg2;
2060
2061 if (!a || !b)
2062 {
2063 PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
2064 PORT_Assert(0);
2065 }
2066 else
2067 {
2068 PRBool aDecoded = PR_FALSE, bDecoded = PR_FALSE;
2069 if ( (PR_TRUE == a->sigValid) && (PR_TRUE == b->sigValid) )
2070 {
2071 /* both CRLs have been validated, choose the latest one */
2072 return SortCRLsByThisUpdate(arg1, arg2);
2073 }
2074 if (PR_TRUE == a->sigValid)
2075 {
2076 return 1; /* a is greater than b */
2077 }
2078 if (PR_TRUE == b->sigValid)
2079 {
2080 return -1; /* a is not as good as b */
2081 }
2082 aDecoded = GetOpaqueCRLFields(a->crl)->decodingError;
2083 bDecoded = GetOpaqueCRLFields(b->crl)->decodingError;
2084 /* neither CRL had its signature check pass */
2085 if ( (PR_FALSE == aDecoded) && (PR_FALSE == bDecoded) )
2086 {
2087 /* both CRLs are proper DER, choose the latest one */
2088 return SortCRLsByThisUpdate(arg1, arg2);
2089 }
2090 if (PR_FALSE == aDecoded)
2091 {
2092 return 1; /* a is better than b */
2093 }
2094 if (PR_FALSE == bDecoded)
2095 {
2096 return -1; /* a is not as good as b */
2097 }
2098 /* both are invalid DER. sigh. */
2099 }
2100 /* if they are equal, or if all else fails, use pointer differences */
2101 PORT_Assert(a != b); /* they should never be equal */
2102 return a>b?1:-1;
2103 }
2104
2105
2106 /* Pick best CRL to use . needs write access */
2107 static SECStatus DPCache_SelectCRL(CRLDPCache* cache)
2108 {
2109 PRUint32 i;
2110 PRBool valid = PR_TRUE;
2111 CachedCrl* selected = NULL;
2112
2113 PORT_Assert(cache);
2114 if (!cache)
2115 {
2116 PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
2117 return SECFailure;
2118 }
2119 /* if any invalid CRL is present, then the CRL cache is
2120 considered invalid, for security reasons */
2121 for (i = 0 ; i<cache->ncrls; i++)
2122 {
2123 if (!cache->crls[i] || !cache->crls[i]->sigChecked ||
2124 !cache->crls[i]->sigValid)
2125 {
2126 valid = PR_FALSE;
2127 break;
2128 }
2129 }
2130 if (PR_TRUE == valid)
2131 {
2132 /* all CRLs are valid, clear this error */
2133 cache->invalid &= (~CRL_CACHE_INVALID_CRLS);
2134 } else
2135 {
2136 /* some CRLs are invalid, set this error */
2137 cache->invalid |= CRL_CACHE_INVALID_CRLS;
2138 }
2139
2140 if (cache->invalid)
2141 {
2142 /* cache is in an invalid state, so reset it */
2143 if (cache->selected)
2144 {
2145 cache->selected = NULL;
2146 }
2147 /* also sort the CRLs imperfectly */
2148 qsort(cache->crls, cache->ncrls, sizeof(CachedCrl*),
2149 SortImperfectCRLs);
2150 return SECSuccess;
2151 }
2152 /* all CRLs are good, sort them by thisUpdate */
2153 qsort(cache->crls, cache->ncrls, sizeof(CachedCrl*),
2154 SortCRLsByThisUpdate);
2155
2156 if (cache->ncrls)
2157 {
2158 /* pick the newest CRL */
2159 selected = cache->crls[cache->ncrls-1];
2160
2161 /* and populate the cache */
2162 if (SECSuccess != CachedCrl_Populate(selected))
2163 {
2164 return SECFailure;
2165 }
2166 }
2167
2168 cache->selected = selected;
2169
2170 return SECSuccess;
2171 }
2172
2173 /* initialize a DPCache object */
2174 static SECStatus DPCache_Create(CRLDPCache** returned, CERTCertificate* issuer,
2175 const SECItem* subject, SECItem* dp)
2176 {
2177 CRLDPCache* cache = NULL;
2178 PORT_Assert(returned);
2179 /* issuer and dp are allowed to be NULL */
2180 if (!returned || !subject)
2181 {
2182 PORT_Assert(0);
2183 PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
2184 return SECFailure;
2185 }
2186 *returned = NULL;
2187 cache = PORT_ZAlloc(sizeof(CRLDPCache));
2188 if (!cache)
2189 {
2190 return SECFailure;
2191 }
2192 #ifdef DPC_RWLOCK
2193 cache->lock = NSSRWLock_New(NSS_RWLOCK_RANK_NONE, NULL);
2194 #else
2195 cache->lock = PR_NewLock();
2196 #endif
2197 if (!cache->lock)
2198 {
2199 PORT_Free(cache);
2200 return SECFailure;
2201 }
2202 if (issuer)
2203 {
2204 cache->issuer = CERT_DupCertificate(issuer);
2205 }
2206 cache->distributionPoint = SECITEM_DupItem(dp);
2207 cache->subject = SECITEM_DupItem(subject);
2208 cache->lastfetch = 0;
2209 cache->lastcheck = 0;
2210 *returned = cache;
2211 return SECSuccess;
2212 }
2213
2214 /* create an issuer cache object (per CA subject ) */
2215 static SECStatus IssuerCache_Create(CRLIssuerCache** returned,
2216 CERTCertificate* issuer,
2217 const SECItem* subject, const SECItem* dp)
2218 {
2219 SECStatus rv = SECSuccess;
2220 CRLIssuerCache* cache = NULL;
2221 PORT_Assert(returned);
2222 PORT_Assert(subject);
2223 /* issuer and dp are allowed to be NULL */
2224 if (!returned || !subject)
2225 {
2226 PORT_Assert(0);
2227 PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
2228 return SECFailure;
2229 }
2230 *returned = NULL;
2231 cache = (CRLIssuerCache*) PORT_ZAlloc(sizeof(CRLIssuerCache));
2232 if (!cache)
2233 {
2234 return SECFailure;
2235 }
2236 cache->subject = SECITEM_DupItem(subject);
2237 #ifdef XCRL
2238 cache->lock = NSSRWLock_New(NSS_RWLOCK_RANK_NONE, NULL);
2239 if (!cache->lock)
2240 {
2241 rv = SECFailure;
2242 }
2243 if (SECSuccess == rv && issuer)
2244 {
2245 cache->issuer = CERT_DupCertificate(issuer);
2246 if (!cache->issuer)
2247 {
2248 rv = SECFailure;
2249 }
2250 }
2251 #endif
2252 if (SECSuccess != rv)
2253 {
2254 PORT_Assert(SECSuccess == IssuerCache_Destroy(cache));
2255 return SECFailure;
2256 }
2257 *returned = cache;
2258 return SECSuccess;
2259 }
2260
2261 /* add a DPCache to the issuer cache */
2262 static SECStatus IssuerCache_AddDP(CRLIssuerCache* cache,
2263 CERTCertificate* issuer,
2264 const SECItem* subject,
2265 const SECItem* dp,
2266 CRLDPCache** newdpc)
2267 {
2268 /* now create the required DP cache object */
2269 if (!cache || !subject || !newdpc)
2270 {
2271 PORT_Assert(0);
2272 PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
2273 return SECFailure;
2274 }
2275 if (!dp)
2276 {
2277 /* default distribution point */
2278 SECStatus rv = DPCache_Create(&cache->dpp, issuer, subject, NULL);
2279 if (SECSuccess == rv)
2280 {
2281 *newdpc = cache->dpp;
2282 return SECSuccess;
2283 }
2284 }
2285 else
2286 {
2287 /* we should never hit this until we support multiple DPs */
2288 PORT_Assert(dp);
2289 /* XCRL allocate a new distribution point cache object, initialize it,
2290 and add it to the hash table of DPs */
2291 }
2292 return SECFailure;
2293 }
2294
2295 /* add an IssuerCache to the global hash table of issuers */
2296 static SECStatus CRLCache_AddIssuer(CRLIssuerCache* issuer)
2297 {
2298 PORT_Assert(issuer);
2299 PORT_Assert(crlcache.issuers);
2300 if (!issuer || !crlcache.issuers)
2301 {
2302 PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
2303 return SECFailure;
2304 }
2305 if (NULL == PL_HashTableAdd(crlcache.issuers, (void*) issuer->subject,
2306 (void*) issuer))
2307 {
2308 return SECFailure;
2309 }
2310 return SECSuccess;
2311 }
2312
2313 /* retrieve the issuer cache object for a given issuer subject */
2314 static SECStatus CRLCache_GetIssuerCache(CRLCache* cache,
2315 const SECItem* subject,
2316 CRLIssuerCache** returned)
2317 {
2318 /* we need to look up the issuer in the hash table */
2319 SECStatus rv = SECSuccess;
2320 PORT_Assert(cache);
2321 PORT_Assert(subject);
2322 PORT_Assert(returned);
2323 PORT_Assert(crlcache.issuers);
2324 if (!cache || !subject || !returned || !crlcache.issuers)
2325 {
2326 PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
2327 rv = SECFailure;
2328 }
2329
2330 if (SECSuccess == rv)
2331 {
2332 *returned = (CRLIssuerCache*) PL_HashTableLookup(crlcache.issuers,
2333 (void*) subject);
2334 }
2335
2336 return rv;
2337 }
2338
2339 /* retrieve the full CRL object that best matches the content of a DPCache */
2340 static CERTSignedCrl* GetBestCRL(CRLDPCache* cache, PRBool entries)
2341 {
2342 CachedCrl* acrl = NULL;
2343
2344 PORT_Assert(cache);
2345 if (!cache)
2346 {
2347 PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
2348 return NULL;
2349 }
2350
2351 if (0 == cache->ncrls)
2352 {
2353 /* empty cache*/
2354 PORT_SetError(SEC_ERROR_CRL_NOT_FOUND);
2355 return NULL;
2356 }
2357
2358 /* if we have a valid full CRL selected, return it */
2359 if (cache->selected)
2360 {
2361 return SEC_DupCrl(cache->selected->crl);
2362 }
2363
2364 /* otherwise, use latest valid DER CRL */
2365 acrl = cache->crls[cache->ncrls-1];
2366
2367 if (acrl && (PR_FALSE == GetOpaqueCRLFields(acrl->crl)->decodingError) )
2368 {
2369 SECStatus rv = SECSuccess;
2370 if (PR_TRUE == entries)
2371 {
2372 rv = CERT_CompleteCRLDecodeEntries(acrl->crl);
2373 }
2374 if (SECSuccess == rv)
2375 {
2376 return SEC_DupCrl(acrl->crl);
2377 }
2378 }
2379
2380 PORT_SetError(SEC_ERROR_CRL_NOT_FOUND);
2381 return NULL;
2382 }
2383
2384 /* get a particular DPCache object from an IssuerCache */
2385 static CRLDPCache* IssuerCache_GetDPCache(CRLIssuerCache* cache, const SECItem* dp)
2386 {
2387 CRLDPCache* dpp = NULL;
2388 PORT_Assert(cache);
2389 /* XCRL for now we only support the "default" DP, ie. the
2390 full CRL. So we can return the global one without locking. In
2391 the future we will have a lock */
2392 PORT_Assert(NULL == dp);
2393 if (!cache || dp)
2394 {
2395 PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
2396 return NULL;
2397 }
2398 #ifdef XCRL
2399 NSSRWLock_LockRead(cache->lock);
2400 #endif
2401 dpp = cache->dpp;
2402 #ifdef XCRL
2403 NSSRWLock_UnlockRead(cache->lock);
2404 #endif
2405 return dpp;
2406 }
2407
2408 /* get a DPCache object for the given issuer subject and dp
2409 Automatically creates the cache object if it doesn't exist yet.
2410 */
2411 SECStatus AcquireDPCache(CERTCertificate* issuer, const SECItem* subject,
2412 const SECItem* dp, PRTime t, void* wincx,
2413 CRLDPCache** dpcache, PRBool* writeLocked)
2414 {
2415 SECStatus rv = SECSuccess;
2416 CRLIssuerCache* issuercache = NULL;
2417 #ifdef GLOBAL_RWLOCK
2418 PRBool globalwrite = PR_FALSE;
2419 #endif
2420 PORT_Assert(crlcache.lock);
2421 if (!crlcache.lock)
2422 {
2423 /* CRL cache is not initialized */
2424 PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
2425 return SECFailure;
2426 }
2427 #ifdef GLOBAL_RWLOCK
2428 NSSRWLock_LockRead(crlcache.lock);
2429 #else
2430 PR_Lock(crlcache.lock);
2431 #endif
2432 rv = CRLCache_GetIssuerCache(&crlcache, subject, &issuercache);
2433 if (SECSuccess != rv)
2434 {
2435 #ifdef GLOBAL_RWLOCK
2436 NSSRWLock_UnlockRead(crlcache.lock);
2437 #else
2438 PR_Unlock(crlcache.lock);
2439 #endif
2440 PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
2441 return SECFailure;
2442 }
2443 if (!issuercache)
2444 {
2445 /* there is no cache for this issuer yet. This means this is the
2446 first time we look up a cert from that issuer, and we need to
2447 create the cache. */
2448
2449 rv = IssuerCache_Create(&issuercache, issuer, subject, dp);
2450 if (SECSuccess == rv && !issuercache)
2451 {
2452 PORT_Assert(issuercache);
2453 rv = SECFailure;
2454 }
2455
2456 if (SECSuccess == rv)
2457 {
2458 /* This is the first time we look up a cert of this issuer.
2459 Create the DPCache for this DP . */
2460 rv = IssuerCache_AddDP(issuercache, issuer, subject, dp, dpcache);
2461 }
2462
2463 if (SECSuccess == rv)
2464 {
2465 /* lock the DPCache for write to ensure the update happens in this
2466 thread */
2467 *writeLocked = PR_TRUE;
2468 #ifdef DPC_RWLOCK
2469 NSSRWLock_LockWrite((*dpcache)->lock);
2470 #else
2471 PR_Lock((*dpcache)->lock);
2472 #endif
2473 }
2474
2475 if (SECSuccess == rv)
2476 {
2477 /* now add the new issuer cache to the global hash table of
2478 issuers */
2479 #ifdef GLOBAL_RWLOCK
2480 CRLIssuerCache* existing = NULL;
2481 NSSRWLock_UnlockRead(crlcache.lock);
2482 /* when using a r/w lock for the global cache, check if the issuer
2483 already exists before adding to the hash table */
2484 NSSRWLock_LockWrite(crlcache.lock);
2485 globalwrite = PR_TRUE;
2486 rv = CRLCache_GetIssuerCache(&crlcache, subject, &existing);
2487 if (!existing)
2488 {
2489 #endif
2490 rv = CRLCache_AddIssuer(issuercache);
2491 if (SECSuccess != rv)
2492 {
2493 /* failure */
2494 rv = SECFailure;
2495 }
2496 #ifdef GLOBAL_RWLOCK
2497 }
2498 else
2499 {
2500 /* somebody else updated before we did */
2501 IssuerCache_Destroy(issuercache); /* destroy the new object */
2502 issuercache = existing; /* use the existing one */
2503 *dpcache = IssuerCache_GetDPCache(issuercache, dp);
2504 }
2505 #endif
2506 }
2507
2508 /* now unlock the global cache. We only want to lock the issuer hash
2509 table addition. Holding it longer would hurt scalability */
2510 #ifdef GLOBAL_RWLOCK
2511 if (PR_TRUE == globalwrite)
2512 {
2513 NSSRWLock_UnlockWrite(crlcache.lock);
2514 globalwrite = PR_FALSE;
2515 }
2516 else
2517 {
2518 NSSRWLock_UnlockRead(crlcache.lock);
2519 }
2520 #else
2521 PR_Unlock(crlcache.lock);
2522 #endif
2523
2524 /* if there was a failure adding an issuer cache object, destroy it */
2525 if (SECSuccess != rv && issuercache)
2526 {
2527 if (PR_TRUE == *writeLocked)
2528 {
2529 #ifdef DPC_RWLOCK
2530 NSSRWLock_UnlockWrite((*dpcache)->lock);
2531 #else
2532 PR_Unlock((*dpcache)->lock);
2533 #endif
2534 }
2535 IssuerCache_Destroy(issuercache);
2536 issuercache = NULL;
2537 }
2538
2539 if (SECSuccess != rv)
2540 {
2541 return SECFailure;
2542 }
2543 } else
2544 {
2545 #ifdef GLOBAL_RWLOCK
2546 NSSRWLock_UnlockRead(crlcache.lock);
2547 #else
2548 PR_Unlock(crlcache.lock);
2549 #endif
2550 *dpcache = IssuerCache_GetDPCache(issuercache, dp);
2551 }
2552 /* we now have a DPCache that we can use for lookups */
2553 /* lock it for read, unless we already locked for write */
2554 if (PR_FALSE == *writeLocked)
2555 {
2556 #ifdef DPC_RWLOCK
2557 NSSRWLock_LockRead((*dpcache)->lock);
2558 #else
2559 PR_Lock((*dpcache)->lock);
2560 #endif
2561 }
2562
2563 if (SECSuccess == rv)
2564 {
2565 /* currently there is always one and only one DPCache per issuer */
2566 PORT_Assert(*dpcache);
2567 if (*dpcache)
2568 {
2569 /* make sure the DP cache is up to date before using it */
2570 rv = DPCache_GetUpToDate(*dpcache, issuer, PR_FALSE == *writeLocked,
2571 t, wincx);
2572 }
2573 else
2574 {
2575 rv = SECFailure;
2576 }
2577 }
2578 return rv;
2579 }
2580
2581 /* unlock access to the DPCache */
2582 void ReleaseDPCache(CRLDPCache* dpcache, PRBool writeLocked)
2583 {
2584 if (!dpcache)
2585 {
2586 PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
2587 return;
2588 }
2589 #ifdef DPC_RWLOCK
2590 if (PR_TRUE == writeLocked)
2591 {
2592 NSSRWLock_UnlockWrite(dpcache->lock);
2593 }
2594 else
2595 {
2596 NSSRWLock_UnlockRead(dpcache->lock);
2597 }
2598 #else
2599 PR_Unlock(dpcache->lock);
2600 #endif
2601 }
2602
2603 SECStatus
2604 cert_CheckCertRevocationStatus(CERTCertificate* cert, CERTCertificate* issuer,
2605 const SECItem* dp, PRTime t, void *wincx,
2606 CERTRevocationStatus *revStatus,
2607 CERTCRLEntryReasonCode *revReason)
2608 {
2609 PRBool lockedwrite = PR_FALSE;
2610 SECStatus rv = SECSuccess;
2611 CRLDPCache* dpcache = NULL;
2612 CERTRevocationStatus status = certRevocationStatusRevoked;
2613 CERTCRLEntryReasonCode reason = crlEntryReasonUnspecified;
2614 CERTCrlEntry* entry = NULL;
2615 dpcacheStatus ds;
2616
2617 if (!cert || !issuer)
2618 {
2619 PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
2620 return SECFailure;
2621 }
2622
2623 if (revStatus)
2624 {
2625 *revStatus = status;
2626 }
2627 if (revReason)
2628 {
2629 *revReason = reason;
2630 }
2631
2632 if (t && secCertTimeValid != CERT_CheckCertValidTimes(issuer, t, PR_FALSE))
2633 {
2634 /* we won't be able to check the CRL's signature if the issuer cert
2635 is expired as of the time we are verifying. This may cause a valid
2636 CRL to be cached as bad. short-circuit to avoid this case. */
2637 PORT_SetError(SEC_ERROR_EXPIRED_ISSUER_CERTIFICATE);
2638 return SECFailure;
2639 }
2640
2641 rv = AcquireDPCache(issuer, &issuer->derSubject, dp, t, wincx, &dpcache,
2642 &lockedwrite);
2643 PORT_Assert(SECSuccess == rv);
2644 if (SECSuccess != rv)
2645 {
2646 PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
2647 return SECFailure;
2648 }
2649 /* now look up the certificate SN in the DP cache's CRL */
2650 ds = DPCache_Lookup(dpcache, &cert->serialNumber, &entry);
2651 switch (ds)
2652 {
2653 case dpcacheFoundEntry:
2654 PORT_Assert(entry);
2655 /* check the time if we have one */
2656 if (entry->revocationDate.data && entry->revocationDate.len)
2657 {
2658 PRTime revocationDate = 0;
2659 if (SECSuccess == DER_DecodeTimeChoice(&revocationDate,
2660 &entry->revocationDate))
2661 {
2662 /* we got a good revocation date, only consider the
2663 certificate revoked if the time we are inquiring about
2664 is past the revocation date */
2665 if (t>=revocationDate)
2666 {
2667 rv = SECFailure;
2668 }
2669 else
2670 {
2671 status = certRevocationStatusValid;
2672 }
2673 }
2674 else
2675 {
2676 /* invalid revocation date, consider the certificate
2677 permanently revoked */
2678 rv = SECFailure;
2679 }
2680 }
2681 else
2682 {
2683 /* no revocation date, certificate is permanently revoked */
2684 rv = SECFailure;
2685 }
2686 if (SECFailure == rv)
2687 {
2688 SECStatus rv2 = CERT_FindCRLEntryReasonExten(entry, &reason);
2689 PORT_SetError(SEC_ERROR_REVOKED_CERTIFICATE);
2690 }
2691 break;
2692
2693 case dpcacheEmpty:
2694 /* useful for NIST policy */
2695 status = certRevocationStatusUnknown;
2696 break;
2697
2698 case dpcacheNoEntry:
2699 status = certRevocationStatusValid;
2700 break;
2701
2702 case dpcacheInvalidCacheError:
2703 /* treat it as unknown and let the caller decide based on
2704 the policy */
2705 status = certRevocationStatusUnknown;
2706 break;
2707
2708 default:
2709 /* leave status as revoked */
2710 break;
2711 }
2712
2713 ReleaseDPCache(dpcache, lockedwrite);
2714 if (revStatus)
2715 {
2716 *revStatus = status;
2717 }
2718 if (revReason)
2719 {
2720 *revReason = reason;
2721 }
2722 return rv;
2723 }
2724
2725 /* check CRL revocation status of given certificate and issuer */
2726 SECStatus
2727 CERT_CheckCRL(CERTCertificate* cert, CERTCertificate* issuer,
2728 const SECItem* dp, PRTime t, void* wincx)
2729 {
2730 return cert_CheckCertRevocationStatus(cert, issuer, dp, t, wincx,
2731 NULL, NULL);
2732 }
2733
2734 /* retrieve full CRL object that best matches the cache status */
2735 CERTSignedCrl *
2736 SEC_FindCrlByName(CERTCertDBHandle *handle, SECItem *crlKey, int type)
2737 {
2738 CERTSignedCrl* acrl = NULL;
2739 CRLDPCache* dpcache = NULL;
2740 SECStatus rv = SECSuccess;
2741 PRBool writeLocked = PR_FALSE;
2742
2743 if (!crlKey)
2744 {
2745 PORT_SetError(SEC_ERROR_INVALID_ARGS);
2746 return NULL;
2747 }
2748
2749 rv = AcquireDPCache(NULL, crlKey, NULL, 0, NULL, &dpcache, &writeLocked);
2750 if (SECSuccess == rv)
2751 {
2752 acrl = GetBestCRL(dpcache, PR_TRUE); /* decode entries, because
2753 SEC_FindCrlByName always returned fully decoded CRLs in the past */
2754 ReleaseDPCache(dpcache, writeLocked);
2755 }
2756 return acrl;
2757 }
2758
2759 /* invalidate the CRL cache for a given issuer, which forces a refetch of
2760 CRL objects from PKCS#11 tokens */
2761 void CERT_CRLCacheRefreshIssuer(CERTCertDBHandle* dbhandle, SECItem* crlKey)
2762 {
2763 CRLDPCache* cache = NULL;
2764 SECStatus rv = SECSuccess;
2765 PRBool writeLocked = PR_FALSE;
2766 PRBool readlocked;
2767
2768 (void) dbhandle; /* silence compiler warnings */
2769
2770 /* XCRL we will need to refresh all the DPs of the issuer in the future,
2771 not just the default one */
2772 rv = AcquireDPCache(NULL, crlKey, NULL, 0, NULL, &cache, &writeLocked);
2773 if (SECSuccess != rv)
2774 {
2775 return;
2776 }
2777 /* we need to invalidate the DPCache here */
2778 readlocked = (writeLocked == PR_TRUE? PR_FALSE : PR_TRUE);
2779 DPCache_LockWrite();
2780 cache->refresh = PR_TRUE;
2781 DPCache_UnlockWrite();
2782 ReleaseDPCache(cache, writeLocked);
2783 return;
2784 }
2785
2786 /* add the specified RAM CRL object to the cache */
2787 SECStatus CERT_CacheCRL(CERTCertDBHandle* dbhandle, SECItem* newdercrl)
2788 {
2789 CRLDPCache* cache = NULL;
2790 SECStatus rv = SECSuccess;
2791 PRBool writeLocked = PR_FALSE;
2792 PRBool readlocked;
2793 CachedCrl* returned = NULL;
2794 PRBool added = PR_FALSE;
2795 CERTSignedCrl* newcrl = NULL;
2796 int realerror = 0;
2797
2798 if (!dbhandle || !newdercrl)
2799 {
2800 PORT_SetError(SEC_ERROR_INVALID_ARGS);
2801 return SECFailure;
2802 }
2803
2804 /* first decode the DER CRL to make sure it's OK */
2805 newcrl = CERT_DecodeDERCrlWithFlags(NULL, newdercrl, SEC_CRL_TYPE,
2806 CRL_DECODE_DONT_COPY_DER |
2807 CRL_DECODE_SKIP_ENTRIES);
2808
2809 if (!newcrl)
2810 {
2811 return SECFailure;
2812 }
2813
2814 /* XXX check if it has IDP extension. If so, do not proceed and set error */
2815
2816 rv = AcquireDPCache(NULL,
2817 &newcrl->crl.derName,
2818 NULL, 0, NULL, &cache, &writeLocked);
2819 if (SECSuccess == rv)
2820 {
2821 readlocked = (writeLocked == PR_TRUE? PR_FALSE : PR_TRUE);
2822
2823 rv = CachedCrl_Create(&returned, newcrl, CRL_OriginExplicit);
2824 if (SECSuccess == rv && returned)
2825 {
2826 DPCache_LockWrite();
2827 rv = DPCache_AddCRL(cache, returned, &added);
2828 if (PR_TRUE != added)
2829 {
2830 realerror = PORT_GetError();
2831 CachedCrl_Destroy(returned);
2832 returned = NULL;
2833 }
2834 DPCache_UnlockWrite();
2835 }
2836
2837 ReleaseDPCache(cache, writeLocked);
2838
2839 if (!added)
2840 {
2841 rv = SECFailure;
2842 }
2843 }
2844 SEC_DestroyCrl(newcrl); /* free the CRL. Either it got added to the cache
2845 and the refcount got bumped, or not, and thus we need to free its
2846 RAM */
2847 if (realerror)
2848 {
2849 PORT_SetError(realerror);
2850 }
2851 return rv;
2852 }
2853
2854 /* remove the specified RAM CRL object from the cache */
2855 SECStatus CERT_UncacheCRL(CERTCertDBHandle* dbhandle, SECItem* olddercrl)
2856 {
2857 CRLDPCache* cache = NULL;
2858 SECStatus rv = SECSuccess;
2859 PRBool writeLocked = PR_FALSE;
2860 PRBool readlocked;
2861 PRBool removed = PR_FALSE;
2862 PRUint32 i;
2863 CERTSignedCrl* oldcrl = NULL;
2864
2865 if (!dbhandle || !olddercrl)
2866 {
2867 PORT_SetError(SEC_ERROR_INVALID_ARGS);
2868 return SECFailure;
2869 }
2870
2871 /* first decode the DER CRL to make sure it's OK */
2872 oldcrl = CERT_DecodeDERCrlWithFlags(NULL, olddercrl, SEC_CRL_TYPE,
2873 CRL_DECODE_DONT_COPY_DER |
2874 CRL_DECODE_SKIP_ENTRIES);
2875
2876 if (!oldcrl)
2877 {
2878 /* if this DER CRL can't decode, it can't be in the cache */
2879 return SECFailure;
2880 }
2881
2882 rv = AcquireDPCache(NULL,
2883 &oldcrl->crl.derName,
2884 NULL, 0, NULL, &cache, &writeLocked);
2885 if (SECSuccess == rv)
2886 {
2887 CachedCrl* returned = NULL;
2888
2889 readlocked = (writeLocked == PR_TRUE? PR_FALSE : PR_TRUE);
2890
2891 rv = CachedCrl_Create(&returned, oldcrl, CRL_OriginExplicit);
2892 if (SECSuccess == rv && returned)
2893 {
2894 DPCache_LockWrite();
2895 for (i=0;i<cache->ncrls;i++)
2896 {
2897 PRBool dupe = PR_FALSE, updated = PR_FALSE;
2898 rv = CachedCrl_Compare(returned, cache->crls[i],
2899 &dupe, &updated);
2900 if (SECSuccess != rv)
2901 {
2902 PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
2903 break;
2904 }
2905 if (PR_TRUE == dupe)
2906 {
2907 rv = DPCache_RemoveCRL(cache, i); /* got a match */
2908 if (SECSuccess == rv) {
2909 cache->mustchoose = PR_TRUE;
2910 removed = PR_TRUE;
2911 }
2912 break;
2913 }
2914 }
2915
2916 DPCache_UnlockWrite();
2917
2918 if (SECSuccess != CachedCrl_Destroy(returned) ) {
2919 rv = SECFailure;
2920 }
2921 }
2922
2923 ReleaseDPCache(cache, writeLocked);
2924 }
2925 if (SECSuccess != SEC_DestroyCrl(oldcrl) ) {
2926 /* need to do this because object is refcounted */
2927 rv = SECFailure;
2928 }
2929 if (SECSuccess == rv && PR_TRUE != removed)
2930 {
2931 PORT_SetError(SEC_ERROR_CRL_NOT_FOUND);
2932 }
2933 return rv;
2934 }
2935
2936 SECStatus cert_AcquireNamedCRLCache(NamedCRLCache** returned)
2937 {
2938 PORT_Assert(returned);
2939 if (!namedCRLCache.lock)
2940 {
2941 PORT_Assert(0);
2942 return SECFailure;
2943 }
2944 PR_Lock(namedCRLCache.lock);
2945 *returned = &namedCRLCache;
2946 return SECSuccess;
2947 }
2948
2949 /* This must be called only while cache is acquired, and the entry is only
2950 * valid until cache is released.
2951 */
2952 SECStatus cert_FindCRLByGeneralName(NamedCRLCache* ncc,
2953 const SECItem* canonicalizedName,
2954 NamedCRLCacheEntry** retEntry)
2955 {
2956 if (!ncc || !canonicalizedName || !retEntry)
2957 {
2958 PORT_SetError(SEC_ERROR_INVALID_ARGS);
2959 return SECFailure;
2960 }
2961 *retEntry = (NamedCRLCacheEntry*) PL_HashTableLookup(namedCRLCache.entries,
2962 (void*) canonicalizedName);
2963 return SECSuccess;
2964 }
2965
2966 SECStatus cert_ReleaseNamedCRLCache(NamedCRLCache* ncc)
2967 {
2968 if (!ncc)
2969 {
2970 return SECFailure;
2971 }
2972 if (!ncc->lock)
2973 {
2974 PORT_Assert(0);
2975 return SECFailure;
2976 }
2977 PR_Unlock(namedCRLCache.lock);
2978 return SECSuccess;
2979 }
2980
2981 /* creates new named cache entry from CRL, and tries to add it to CRL cache */
2982 static SECStatus addCRLToCache(CERTCertDBHandle* dbhandle, SECItem* crl,
2983 const SECItem* canonicalizedName,
2984 NamedCRLCacheEntry** newEntry)
2985 {
2986 SECStatus rv = SECSuccess;
2987 NamedCRLCacheEntry* entry = NULL;
2988
2989 /* create new named entry */
2990 if (SECSuccess != NamedCRLCacheEntry_Create(newEntry) || !*newEntry)
2991 {
2992 /* no need to keep unused CRL around */
2993 SECITEM_ZfreeItem(crl, PR_TRUE);
2994 return SECFailure;
2995 }
2996 entry = *newEntry;
2997 entry->crl = crl; /* named CRL cache owns DER */
2998 entry->lastAttemptTime = PR_Now();
2999 entry->canonicalizedName = SECITEM_DupItem(canonicalizedName);
3000 if (!entry->canonicalizedName)
3001 {
3002 rv = NamedCRLCacheEntry_Destroy(entry); /* destroys CRL too */
3003 PORT_Assert(SECSuccess == rv);
3004 return SECFailure;
3005 }
3006 /* now, attempt to insert CRL into CRL cache */
3007 if (SECSuccess == CERT_CacheCRL(dbhandle, entry->crl))
3008 {
3009 entry->inCRLCache = PR_TRUE;
3010 entry->successfulInsertionTime = entry->lastAttemptTime;
3011 }
3012 else
3013 {
3014 switch (PR_GetError())
3015 {
3016 case SEC_ERROR_CRL_ALREADY_EXISTS:
3017 entry->dupe = PR_TRUE;
3018 break;
3019
3020 case SEC_ERROR_BAD_DER:
3021 entry->badDER = PR_TRUE;
3022 break;
3023
3024 /* all other reasons */
3025 default:
3026 entry->unsupported = PR_TRUE;
3027 break;
3028 }
3029 rv = SECFailure;
3030 /* no need to keep unused CRL around */
3031 SECITEM_ZfreeItem(entry->crl, PR_TRUE);
3032 entry->crl = NULL;
3033 }
3034 return rv;
3035 }
3036
3037 /* take ownership of CRL, and insert it into the named CRL cache
3038 * and indexed CRL cache
3039 */
3040 SECStatus cert_CacheCRLByGeneralName(CERTCertDBHandle* dbhandle, SECItem* crl,
3041 const SECItem* canonicalizedName)
3042 {
3043 NamedCRLCacheEntry* oldEntry, * newEntry = NULL;
3044 NamedCRLCache* ncc = NULL;
3045 SECStatus rv = SECSuccess, rv2;
3046
3047 PORT_Assert(namedCRLCache.lock);
3048 PORT_Assert(namedCRLCache.entries);
3049
3050 if (!crl || !canonicalizedName)
3051 {
3052 PORT_Assert(0);
3053 PORT_SetError(SEC_ERROR_INVALID_ARGS);
3054 return SECFailure;
3055 }
3056
3057 rv = cert_AcquireNamedCRLCache(&ncc);
3058 PORT_Assert(SECSuccess == rv);
3059 if (SECSuccess != rv)
3060 {
3061 SECITEM_ZfreeItem(crl, PR_TRUE);
3062 return SECFailure;
3063 }
3064 rv = cert_FindCRLByGeneralName(ncc, canonicalizedName, &oldEntry);
3065 PORT_Assert(SECSuccess == rv);
3066 if (SECSuccess != rv)
3067 {
3068 rv = cert_ReleaseNamedCRLCache(ncc);
3069 SECITEM_ZfreeItem(crl, PR_TRUE);
3070 return SECFailure;
3071 }
3072 if (SECSuccess == addCRLToCache(dbhandle, crl, canonicalizedName,
3073 &newEntry) )
3074 {
3075 if (!oldEntry)
3076 {
3077 /* add new good entry to the hash table */
3078 if (NULL == PL_HashTableAdd(namedCRLCache.entries,
3079 (void*) newEntry->canonicalizedName,
3080 (void*) newEntry))
3081 {
3082 PORT_Assert(0);
3083 rv2 = NamedCRLCacheEntry_Destroy(newEntry);
3084 PORT_Assert(SECSuccess == rv2);
3085 rv = SECFailure;
3086 }
3087 }
3088 else
3089 {
3090 PRBool removed;
3091 /* remove the old CRL from the cache if needed */
3092 if (oldEntry->inCRLCache)
3093 {
3094 rv = CERT_UncacheCRL(dbhandle, oldEntry->crl);
3095 PORT_Assert(SECSuccess == rv);
3096 }
3097 removed = PL_HashTableRemove(namedCRLCache.entries,
3098 (void*) oldEntry->canonicalizedName);
3099 PORT_Assert(removed);
3100 if (!removed)
3101 {
3102 rv = SECFailure;
3103 /* leak old entry since we couldn't remove it from the hash table */
3104 }
3105 else
3106 {
3107 rv2 = NamedCRLCacheEntry_Destroy(oldEntry);
3108 PORT_Assert(SECSuccess == rv2);
3109 }
3110 if (NULL == PL_HashTableAdd(namedCRLCache.entries,
3111 (void*) newEntry->canonicalizedName,
3112 (void*) newEntry))
3113 {
3114 PORT_Assert(0);
3115 rv = SECFailure;
3116 }
3117 }
3118 } else
3119 {
3120 /* error adding new CRL to cache */
3121 if (!oldEntry)
3122 {
3123 /* no old cache entry, use the new one even though it's bad */
3124 if (NULL == PL_HashTableAdd(namedCRLCache.entries,
3125 (void*) newEntry->canonicalizedName,
3126 (void*) newEntry))
3127 {
3128 PORT_Assert(0);
3129 rv = SECFailure;
3130 }
3131 }
3132 else
3133 {
3134 if (oldEntry->inCRLCache)
3135 {
3136 /* previous cache entry was good, keep it and update time */
3137 oldEntry-> lastAttemptTime = newEntry->lastAttemptTime;
3138 /* throw away new bad entry */
3139 rv = NamedCRLCacheEntry_Destroy(newEntry);
3140 PORT_Assert(SECSuccess == rv);
3141 }
3142 else
3143 {
3144 /* previous cache entry was bad, just replace it */
3145 PRBool removed = PL_HashTableRemove(namedCRLCache.entries,
3146 (void*) oldEntry->canonicalizedName);
3147 PORT_Assert(removed);
3148 if (!removed)
3149 {
3150 /* leak old entry since we couldn't remove it from the hash table */
3151 rv = SECFailure;
3152 }
3153 else
3154 {
3155 rv2 = NamedCRLCacheEntry_Destroy(oldEntry);
3156 PORT_Assert(SECSuccess == rv2);
3157 }
3158 if (NULL == PL_HashTableAdd(namedCRLCache.entries,
3159 (void*) newEntry->canonicalizedName,
3160 (void*) newEntry))
3161 {
3162 PORT_Assert(0);
3163 rv = SECFailure;
3164 }
3165 }
3166 }
3167 }
3168 rv2 = cert_ReleaseNamedCRLCache(ncc);
3169 PORT_Assert(SECSuccess == rv2);
3170
3171 return rv;
3172 }
3173
3174 static SECStatus CachedCrl_Create(CachedCrl** returned, CERTSignedCrl* crl,
3175 CRLOrigin origin)
3176 {
3177 CachedCrl* newcrl = NULL;
3178 if (!returned)
3179 {
3180 PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
3181 return SECFailure;
3182 }
3183 newcrl = PORT_ZAlloc(sizeof(CachedCrl));
3184 if (!newcrl)
3185 {
3186 return SECFailure;
3187 }
3188 newcrl->crl = SEC_DupCrl(crl);
3189 newcrl->origin = origin;
3190 *returned = newcrl;
3191 return SECSuccess;
3192 }
3193
3194 /* empty the cache content */
3195 static SECStatus CachedCrl_Depopulate(CachedCrl* crl)
3196 {
3197 if (!crl)
3198 {
3199 PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
3200 return SECFailure;
3201 }
3202 /* destroy the hash table */
3203 if (crl->entries)
3204 {
3205 PL_HashTableDestroy(crl->entries);
3206 crl->entries = NULL;
3207 }
3208
3209 /* free the pre buffer */
3210 if (crl->prebuffer)
3211 {
3212 PreAllocator_Destroy(crl->prebuffer);
3213 crl->prebuffer = NULL;
3214 }
3215 return SECSuccess;
3216 }
3217
3218 static SECStatus CachedCrl_Destroy(CachedCrl* crl)
3219 {
3220 if (!crl)
3221 {
3222 PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
3223 return SECFailure;
3224 }
3225 CachedCrl_Depopulate(crl);
3226 SEC_DestroyCrl(crl->crl);
3227 PORT_Free(crl);
3228 return SECSuccess;
3229 }
3230
3231 /* create hash table of CRL entries */
3232 static SECStatus CachedCrl_Populate(CachedCrl* crlobject)
3233 {
3234 SECStatus rv = SECFailure;
3235 CERTCrlEntry** crlEntry = NULL;
3236 PRUint32 numEntries = 0;
3237
3238 if (!crlobject)
3239 {
3240 PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
3241 return SECFailure;
3242 }
3243 /* complete the entry decoding . XXX thread-safety of CRL object */
3244 rv = CERT_CompleteCRLDecodeEntries(crlobject->crl);
3245 if (SECSuccess != rv)
3246 {
3247 crlobject->unbuildable = PR_TRUE; /* don't try to build this again */
3248 return SECFailure;
3249 }
3250
3251 if (crlobject->entries && crlobject->prebuffer)
3252 {
3253 /* cache is already built */
3254 return SECSuccess;
3255 }
3256
3257 /* build the hash table from the full CRL */
3258 /* count CRL entries so we can pre-allocate space for hash table entries */
3259 for (crlEntry = crlobject->crl->crl.entries; crlEntry && *crlEntry;
3260 crlEntry++)
3261 {
3262 numEntries++;
3263 }
3264 crlobject->prebuffer = PreAllocator_Create(numEntries*sizeof(PLHashEntry));
3265 PORT_Assert(crlobject->prebuffer);
3266 if (!crlobject->prebuffer)
3267 {
3268 return SECFailure;
3269 }
3270 /* create a new hash table */
3271 crlobject->entries = PL_NewHashTable(0, SECITEM_Hash, SECITEM_HashCompare,
3272 PL_CompareValues, &preAllocOps, crlobject->prebuffer);
3273 PORT_Assert(crlobject->entries);
3274 if (!crlobject->entries)
3275 {
3276 return SECFailure;
3277 }
3278 /* add all serial numbers to the hash table */
3279 for (crlEntry = crlobject->crl->crl.entries; crlEntry && *crlEntry;
3280 crlEntry++)
3281 {
3282 PL_HashTableAdd(crlobject->entries, &(*crlEntry)->serialNumber,
3283 *crlEntry);
3284 }
3285
3286 return SECSuccess;
3287 }
3288
3289 /* returns true if there are CRLs from PKCS#11 slots */
3290 static PRBool DPCache_HasTokenCRLs(CRLDPCache* cache)
3291 {
3292 PRBool answer = PR_FALSE;
3293 PRUint32 i;
3294 for (i=0;i<cache->ncrls;i++)
3295 {
3296 if (cache->crls[i] && (CRL_OriginToken == cache->crls[i]->origin) )
3297 {
3298 answer = PR_TRUE;
3299 break;
3300 }
3301 }
3302 return answer;
3303 }
3304
3305 /* are these CRLs the same, as far as the cache is concerned ? */
3306 /* are these CRLs the same token object but with different DER ?
3307 This can happen if the DER CRL got updated in the token, but the PKCS#11
3308 object ID did not change. NSS softoken has the unfortunate property to
3309 never change the object ID for CRL objects. */
3310 static SECStatus CachedCrl_Compare(CachedCrl* a, CachedCrl* b, PRBool* isDupe,
3311 PRBool* isUpdated)
3312 {
3313 PORT_Assert(a);
3314 PORT_Assert(b);
3315 PORT_Assert(isDupe);
3316 PORT_Assert(isUpdated);
3317 if (!a || !b || !isDupe || !isUpdated || !a->crl || !b->crl)
3318 {
3319 PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
3320 return SECFailure;
3321 }
3322
3323 *isDupe = *isUpdated = PR_FALSE;
3324
3325 if (a == b)
3326 {
3327 /* dupe */
3328 *isDupe = PR_TRUE;
3329 *isUpdated = PR_FALSE;
3330 return SECSuccess;
3331 }
3332 if (b->origin != a->origin)
3333 {
3334 /* CRLs of different origins are not considered dupes,
3335 and can't be updated either */
3336 return SECSuccess;
3337 }
3338 if (CRL_OriginToken == b->origin)
3339 {
3340 /* for token CRLs, slot and PKCS#11 object handle must match for CRL
3341 to truly be a dupe */
3342 if ( (b->crl->slot == a->crl->slot) &&
3343 (b->crl->pkcs11ID == a->crl->pkcs11ID) )
3344 {
3345 /* ASN.1 DER needs to match for dupe check */
3346 /* could optimize by just checking a few fields like thisUpdate */
3347 if ( SECEqual == SECITEM_CompareItem(b->crl->derCrl,
3348 a->crl->derCrl) )
3349 {
3350 *isDupe = PR_TRUE;
3351 }
3352 else
3353 {
3354 *isUpdated = PR_TRUE;
3355 }
3356 }
3357 return SECSuccess;
3358 }
3359 if (CRL_OriginExplicit == b->origin)
3360 {
3361 /* We need to make sure this is the same object that the user provided
3362 to CERT_CacheCRL previously. That API takes a SECItem*, thus, we
3363 just do a pointer comparison here.
3364 */
3365 if (b->crl->derCrl == a->crl->derCrl)
3366 {
3367 *isDupe = PR_TRUE;
3368 }
3369 }
3370 return SECSuccess;
3371 }
This site is hosted by Intevation GmbH (Datenschutzerklärung und Impressum | Privacy Policy and Imprint)