Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(469)

Side by Side Diff: nss/lib/certdb/crl.c

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

Powered by Google App Engine
This is Rietveld 408576698