Bug Summary

File:s/lib/certdb/crl.c
Warning:line 2830, column 48
Access to field 'canonicalizedName' results in a dereference of a null pointer (loaded from variable 'newEntry')

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name crl.c -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -analyzer-config-compatibility-mode=true -mrelocation-model pic -pic-level 2 -fhalf-no-semantic-interposition -mframe-pointer=all -fmath-errno -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fdebug-compilation-dir=/var/lib/jenkins/workspace/nss-scan-build/nss/lib/certdb -ffunction-sections -fdata-sections -fcoverage-compilation-dir=/var/lib/jenkins/workspace/nss-scan-build/nss/lib/certdb -resource-dir /usr/lib/llvm-18/lib/clang/18 -D HAVE_STRERROR -D LINUX -D linux -D XP_UNIX -D XP_UNIX -D DEBUG -U NDEBUG -D _DEFAULT_SOURCE -D _BSD_SOURCE -D _POSIX_SOURCE -D SDB_MEASURE_USE_TEMP_DIR -D _REENTRANT -D DEBUG -U NDEBUG -D _DEFAULT_SOURCE -D _BSD_SOURCE -D _POSIX_SOURCE -D SDB_MEASURE_USE_TEMP_DIR -D _REENTRANT -D NSS_DISABLE_SSE3 -D NSS_NO_INIT_SUPPORT -D USE_UTIL_DIRECTLY -D NO_NSPR_10_SUPPORT -D SSL_DISABLE_DEPRECATED_CIPHER_SUITE_NAMES -I ../../../dist/Linux4.19_x86_64_gcc_glibc_PTH_64_DBG.OBJ/include -I ../../../dist/public/nss -I ../../../dist/private/nss -internal-isystem /usr/lib/llvm-18/lib/clang/18/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/14/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -std=c99 -ferror-limit 19 -fgnuc-version=4.2.1 -analyzer-output=html -analyzer-config stable-report-filename=true -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /tmp/scan-build-2024-05-18-082241-28900-1 -x c crl.c
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_RWLOCK1) || defined(GLOBAL_RWLOCK)
23#include "nssrwlk.h"
24#endif
25#include "pk11priv.h"
26
27const SEC_ASN1Template SEC_CERTExtensionTemplate[] = {
28 { SEC_ASN1_SEQUENCE0x10, 0, NULL((void*)0), sizeof(CERTCertExtension) },
29 { SEC_ASN1_OBJECT_ID0x06, offsetof(CERTCertExtension, id)__builtin_offsetof(CERTCertExtension, id) },
30 { SEC_ASN1_OPTIONAL0x00100 | SEC_ASN1_BOOLEAN0x01, /* XXX DER_DEFAULT */
31 offsetof(CERTCertExtension, critical)__builtin_offsetof(CERTCertExtension, critical) },
32 { SEC_ASN1_OCTET_STRING0x04, offsetof(CERTCertExtension, value)__builtin_offsetof(CERTCertExtension, value) },
33 { 0 }
34};
35
36static const SEC_ASN1Template SEC_CERTExtensionsTemplate[] = {
37 { SEC_ASN1_SEQUENCE_OF(0x02000 | 0x10), 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
45const SEC_ASN1Template CERT_IssuerAndSNTemplate[] = {
46 { SEC_ASN1_SEQUENCE0x10, 0, NULL((void*)0), sizeof(CERTIssuerAndSN) },
47 { SEC_ASN1_SAVE0x20000, offsetof(CERTIssuerAndSN, derIssuer)__builtin_offsetof(CERTIssuerAndSN, derIssuer) },
48 { SEC_ASN1_INLINE0x00800, offsetof(CERTIssuerAndSN, issuer)__builtin_offsetof(CERTIssuerAndSN, issuer), CERT_NameTemplate },
49 { SEC_ASN1_INTEGER0x02, offsetof(CERTIssuerAndSN, serialNumber)__builtin_offsetof(CERTIssuerAndSN, serialNumber) },
50 { 0 }
51};
52
53SEC_ASN1_MKSUB(SECOID_AlgorithmIDTemplate)
54SEC_ASN1_MKSUB(CERT_TimeChoiceTemplate)
55
56static const SEC_ASN1Template cert_CrlKeyTemplate[] = {
57 { SEC_ASN1_SEQUENCE0x10, 0, NULL((void*)0), sizeof(CERTCrlKey) },
58 { SEC_ASN1_INTEGER0x02 | SEC_ASN1_OPTIONAL0x00100, offsetof(CERTCrlKey, dummy)__builtin_offsetof(CERTCrlKey, dummy) },
59 { SEC_ASN1_SKIP0x08000 },
60 { SEC_ASN1_ANY0x00400, offsetof(CERTCrlKey, derName)__builtin_offsetof(CERTCrlKey, derName) },
61 { SEC_ASN1_SKIP_REST0x80000 },
62 { 0 }
63};
64
65static const SEC_ASN1Template cert_CrlEntryTemplate[] = {
66 { SEC_ASN1_SEQUENCE0x10, 0, NULL((void*)0), sizeof(CERTCrlEntry) },
67 { SEC_ASN1_INTEGER0x02, offsetof(CERTCrlEntry, serialNumber)__builtin_offsetof(CERTCrlEntry, serialNumber) },
68 { SEC_ASN1_INLINE0x00800 | SEC_ASN1_XTRN0, offsetof(CERTCrlEntry, revocationDate)__builtin_offsetof(CERTCrlEntry, revocationDate),
69 SEC_ASN1_SUB(CERT_TimeChoiceTemplate)CERT_TimeChoiceTemplate },
70 { SEC_ASN1_OPTIONAL0x00100 | SEC_ASN1_SEQUENCE_OF(0x02000 | 0x10),
71 offsetof(CERTCrlEntry, extensions)__builtin_offsetof(CERTCrlEntry, extensions), SEC_CERTExtensionTemplate },
72 { 0 }
73};
74
75const SEC_ASN1Template CERT_CrlTemplate[] = {
76 { SEC_ASN1_SEQUENCE0x10, 0, NULL((void*)0), sizeof(CERTCrl) },
77 { SEC_ASN1_INTEGER0x02 | SEC_ASN1_OPTIONAL0x00100, offsetof(CERTCrl, version)__builtin_offsetof(CERTCrl, version) },
78 { SEC_ASN1_INLINE0x00800 | SEC_ASN1_XTRN0, offsetof(CERTCrl, signatureAlg)__builtin_offsetof(CERTCrl, signatureAlg),
79 SEC_ASN1_SUB(SECOID_AlgorithmIDTemplate)SECOID_AlgorithmIDTemplate_Util },
80 { SEC_ASN1_SAVE0x20000, offsetof(CERTCrl, derName)__builtin_offsetof(CERTCrl, derName) },
81 { SEC_ASN1_INLINE0x00800, offsetof(CERTCrl, name)__builtin_offsetof(CERTCrl, name), CERT_NameTemplate },
82 { SEC_ASN1_INLINE0x00800 | SEC_ASN1_XTRN0, offsetof(CERTCrl, lastUpdate)__builtin_offsetof(CERTCrl, lastUpdate),
83 SEC_ASN1_SUB(CERT_TimeChoiceTemplate)CERT_TimeChoiceTemplate },
84 { SEC_ASN1_INLINE0x00800 | SEC_ASN1_OPTIONAL0x00100 | SEC_ASN1_XTRN0,
85 offsetof(CERTCrl, nextUpdate)__builtin_offsetof(CERTCrl, nextUpdate), SEC_ASN1_SUB(CERT_TimeChoiceTemplate)CERT_TimeChoiceTemplate },
86 { SEC_ASN1_OPTIONAL0x00100 | SEC_ASN1_SEQUENCE_OF(0x02000 | 0x10), offsetof(CERTCrl, entries)__builtin_offsetof(CERTCrl, entries),
87 cert_CrlEntryTemplate },
88 { SEC_ASN1_OPTIONAL0x00100 | SEC_ASN1_CONSTRUCTED0x20 | SEC_ASN1_CONTEXT_SPECIFIC0x80 |
89 SEC_ASN1_EXPLICIT0x00200 | 0,
90 offsetof(CERTCrl, extensions)__builtin_offsetof(CERTCrl, extensions), SEC_CERTExtensionsTemplate },
91 { 0 }
92};
93
94const SEC_ASN1Template CERT_CrlTemplateNoEntries[] = {
95 { SEC_ASN1_SEQUENCE0x10, 0, NULL((void*)0), sizeof(CERTCrl) },
96 { SEC_ASN1_INTEGER0x02 | SEC_ASN1_OPTIONAL0x00100, offsetof(CERTCrl, version)__builtin_offsetof(CERTCrl, version) },
97 { SEC_ASN1_INLINE0x00800 | SEC_ASN1_XTRN0, offsetof(CERTCrl, signatureAlg)__builtin_offsetof(CERTCrl, signatureAlg),
98 SEC_ASN1_SUB(SECOID_AlgorithmIDTemplate)SECOID_AlgorithmIDTemplate_Util },
99 { SEC_ASN1_SAVE0x20000, offsetof(CERTCrl, derName)__builtin_offsetof(CERTCrl, derName) },
100 { SEC_ASN1_INLINE0x00800, offsetof(CERTCrl, name)__builtin_offsetof(CERTCrl, name), CERT_NameTemplate },
101 { SEC_ASN1_INLINE0x00800 | SEC_ASN1_XTRN0, offsetof(CERTCrl, lastUpdate)__builtin_offsetof(CERTCrl, lastUpdate),
102 SEC_ASN1_SUB(CERT_TimeChoiceTemplate)CERT_TimeChoiceTemplate },
103 { SEC_ASN1_INLINE0x00800 | SEC_ASN1_OPTIONAL0x00100 | SEC_ASN1_XTRN0,
104 offsetof(CERTCrl, nextUpdate)__builtin_offsetof(CERTCrl, nextUpdate), SEC_ASN1_SUB(CERT_TimeChoiceTemplate)CERT_TimeChoiceTemplate },
105 { SEC_ASN1_OPTIONAL0x00100 | SEC_ASN1_SEQUENCE_OF(0x02000 | 0x10) |
106 SEC_ASN1_SKIP0x08000 }, /* skip entries */
107 { SEC_ASN1_OPTIONAL0x00100 | SEC_ASN1_CONSTRUCTED0x20 | SEC_ASN1_CONTEXT_SPECIFIC0x80 |
108 SEC_ASN1_EXPLICIT0x00200 | 0,
109 offsetof(CERTCrl, extensions)__builtin_offsetof(CERTCrl, extensions), SEC_CERTExtensionsTemplate },
110 { 0 }
111};
112
113const SEC_ASN1Template CERT_CrlTemplateEntriesOnly[] = {
114 { SEC_ASN1_SEQUENCE0x10, 0, NULL((void*)0), sizeof(CERTCrl) },
115 { SEC_ASN1_SKIP0x08000 | SEC_ASN1_INTEGER0x02 | SEC_ASN1_OPTIONAL0x00100 },
116 { SEC_ASN1_SKIP0x08000 },
117 { SEC_ASN1_SKIP0x08000 },
118 { SEC_ASN1_SKIP0x08000 | SEC_ASN1_INLINE0x00800 | SEC_ASN1_XTRN0,
119 offsetof(CERTCrl, lastUpdate)__builtin_offsetof(CERTCrl, lastUpdate), SEC_ASN1_SUB(CERT_TimeChoiceTemplate)CERT_TimeChoiceTemplate },
120 { SEC_ASN1_SKIP0x08000 | SEC_ASN1_INLINE0x00800 | SEC_ASN1_OPTIONAL0x00100 | SEC_ASN1_XTRN0,
121 offsetof(CERTCrl, nextUpdate)__builtin_offsetof(CERTCrl, nextUpdate), SEC_ASN1_SUB(CERT_TimeChoiceTemplate)CERT_TimeChoiceTemplate },
122 { SEC_ASN1_OPTIONAL0x00100 | SEC_ASN1_SEQUENCE_OF(0x02000 | 0x10), offsetof(CERTCrl, entries)__builtin_offsetof(CERTCrl, entries),
123 cert_CrlEntryTemplate }, /* decode entries */
124 { SEC_ASN1_SKIP_REST0x80000 },
125 { 0 }
126};
127
128const SEC_ASN1Template CERT_SignedCrlTemplate[] = {
129 { SEC_ASN1_SEQUENCE0x10, 0, NULL((void*)0), sizeof(CERTSignedCrl) },
130 { SEC_ASN1_SAVE0x20000, offsetof(CERTSignedCrl, signatureWrap.data)__builtin_offsetof(CERTSignedCrl, signatureWrap.data) },
131 { SEC_ASN1_INLINE0x00800, offsetof(CERTSignedCrl, crl)__builtin_offsetof(CERTSignedCrl, crl), CERT_CrlTemplate },
132 { SEC_ASN1_INLINE0x00800 | SEC_ASN1_XTRN0,
133 offsetof(CERTSignedCrl, signatureWrap.signatureAlgorithm)__builtin_offsetof(CERTSignedCrl, signatureWrap.signatureAlgorithm
)
,
134 SEC_ASN1_SUB(SECOID_AlgorithmIDTemplate)SECOID_AlgorithmIDTemplate_Util },
135 { SEC_ASN1_BIT_STRING0x03, offsetof(CERTSignedCrl, signatureWrap.signature)__builtin_offsetof(CERTSignedCrl, signatureWrap.signature) },
136 { 0 }
137};
138
139static const SEC_ASN1Template cert_SignedCrlTemplateNoEntries[] = {
140 { SEC_ASN1_SEQUENCE0x10, 0, NULL((void*)0), sizeof(CERTSignedCrl) },
141 { SEC_ASN1_SAVE0x20000, offsetof(CERTSignedCrl, signatureWrap.data)__builtin_offsetof(CERTSignedCrl, signatureWrap.data) },
142 { SEC_ASN1_INLINE0x00800, offsetof(CERTSignedCrl, crl)__builtin_offsetof(CERTSignedCrl, crl),
143 CERT_CrlTemplateNoEntries },
144 { SEC_ASN1_INLINE0x00800 | SEC_ASN1_XTRN0,
145 offsetof(CERTSignedCrl, signatureWrap.signatureAlgorithm)__builtin_offsetof(CERTSignedCrl, signatureWrap.signatureAlgorithm
)
,
146 SEC_ASN1_SUB(SECOID_AlgorithmIDTemplate)SECOID_AlgorithmIDTemplate_Util },
147 { SEC_ASN1_BIT_STRING0x03, offsetof(CERTSignedCrl, signatureWrap.signature)__builtin_offsetof(CERTSignedCrl, signatureWrap.signature) },
148 { 0 }
149};
150
151const SEC_ASN1Template CERT_SetOfSignedCrlTemplate[] = {
152 { SEC_ASN1_SET_OF(0x02000 | 0x11), 0, CERT_SignedCrlTemplate },
153};
154
155/* get CRL version */
156int
157cert_get_crl_version(CERTCrl* crl)
158{
159 /* CRL version is defaulted to v1 */
160 int version = SEC_CRL_VERSION_10;
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 */
168SECStatus
169cert_check_crl_entries(CERTCrl* crl)
170{
171 CERTCrlEntry** entries;
172 CERTCrlEntry* entry;
173 PRBool hasCriticalExten = PR_FALSE0;
174 SECStatus rv = SECSuccess;
175
176 if (!crl) {
177 return SECFailure;
178 }
179
180 if (crl->entries == NULL((void*)0)) {
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_FALSE0) {
198 hasCriticalExten = cert_HasCriticalExtension(entry->extensions);
199 if (hasCriticalExten) {
200 if (cert_get_crl_version(crl) != SEC_CRL_VERSION_21) {
201 /* only CRL v2 critical extensions are supported */
202 PORT_SetErrorPORT_SetError_Util(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_TRUE1) {
214 PORT_SetErrorPORT_SetError_Util(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 */
229SECStatus
230cert_check_crl_version(CERTCrl* crl)
231{
232 PRBool hasCriticalExten = PR_FALSE0;
233 int version = cert_get_crl_version(crl);
234
235 if (version > SEC_CRL_VERSION_21) {
236 PORT_SetErrorPORT_SetError_Util(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_21) {
247 /* only CRL v2 critical extensions are supported */
248 PORT_SetErrorPORT_SetError_Util(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_TRUE1) {
253 PORT_SetErrorPORT_SetError_Util(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 */
266SECStatus
267CERT_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_NewArenaPORT_NewArena_Util(DER_DEFAULT_CHUNKSIZE(2048));
277 } else {
278 myArena = arena;
279 }
280 PORT_Memsetmemset(&sd, 0, sizeof(sd));
281 rv = SEC_QuickDERDecodeItemSEC_QuickDERDecodeItem_Util(myArena, &sd, CERT_SignedDataTemplate, derCrl);
282 if (SECSuccess == rv) {
283 PORT_Memsetmemset(&crlkey, 0, sizeof(crlkey));
284 rv = SEC_QuickDERDecodeItemSEC_QuickDERDecodeItem_Util(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_CopyItemSECITEM_CopyItem_Util(arena, key, &crlkey.derName);
292 }
293
294 if (myArena != arena) {
295 PORT_FreeArenaPORT_FreeArena_Util(myArena, PR_FALSE0);
296 }
297
298 return rv;
299}
300
301#define GetOpaqueCRLFields(x)((OpaqueCRLFields*)x->opaque) ((OpaqueCRLFields*)x->opaque)
302
303SECStatus
304CERT_CompleteCRLDecodeEntries(CERTSignedCrl* crl)
305{
306 SECStatus rv = SECSuccess;
307 SECItem* crldata = NULL((void*)0);
308 OpaqueCRLFields* extended = NULL((void*)0);
309
310 if ((!crl) || (!(extended = (OpaqueCRLFields*)crl->opaque)) ||
311 (PR_TRUE1 == extended->decodingError)) {
312 rv = SECFailure;
313 } else {
314 if (PR_FALSE0 == extended->partial) {
315 /* the CRL has already been fully decoded */
316 return SECSuccess;
317 }
318 if (PR_TRUE1 == 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_QuickDERDecodeItemSEC_QuickDERDecodeItem_Util(crl->arena, &crl->crl,
330 CERT_CrlTemplateEntriesOnly, crldata);
331 if (SECSuccess == rv) {
332 extended->partial = PR_FALSE0; /* successful decode, avoid
333 decoding again */
334 } else {
335 extended->decodingError = PR_TRUE1;
336 extended->badEntries = PR_TRUE1;
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_TRUE1;
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 */
353CERTSignedCrl*
354CERT_DecodeDERCrlWithFlags(PLArenaPool* narena, SECItem* derSignedCrl, int type,
355 PRInt32 options)
356{
357 PLArenaPool* arena;
358 CERTSignedCrl* crl;
359 SECStatus rv;
360 OpaqueCRLFields* extended = NULL((void*)0);
361 const SEC_ASN1Template* crlTemplate = CERT_SignedCrlTemplate;
362 PRInt32 testOptions = options;
363
364 PORT_Assert(derSignedCrl)((derSignedCrl)?((void)0):PR_Assert("derSignedCrl","crl.c",364
))
;
365 if (!derSignedCrl) {
366 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_INVALID_ARGS);
367 return NULL((void*)0);
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_DER0x00000008 | CRL_DECODE_DONT_COPY_DER0x00000001);
375 PORT_Assert(testOptions != CRL_DECODE_ADOPT_HEAP_DER)((testOptions != 0x00000008)?((void)0):PR_Assert("testOptions != CRL_DECODE_ADOPT_HEAP_DER"
,"crl.c",375))
;
376 if (testOptions == CRL_DECODE_ADOPT_HEAP_DER0x00000008) {
377 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_INVALID_ARGS);
378 return NULL((void*)0);
379 }
380
381 /* make a new arena if needed */
382 if (narena == NULL((void*)0)) {
383 arena = PORT_NewArenaPORT_NewArena_Util(DER_DEFAULT_CHUNKSIZE(2048));
384 if (!arena) {
385 return NULL((void*)0);
386 }
387 } else {
388 arena = narena;
389 }
390
391 /* allocate the CRL structure */
392 crl = (CERTSignedCrl*)PORT_ArenaZAllocPORT_ArenaZAlloc_Util(arena, sizeof(CERTSignedCrl));
393 if (!crl) {
394 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_NO_MEMORY);
395 goto loser;
396 }
397
398 crl->arena = arena;
399
400 /* allocate opaque fields */
401 crl->opaque = (void*)PORT_ArenaZAllocPORT_ArenaZAlloc_Util(arena, sizeof(OpaqueCRLFields));
402 if (!crl->opaque) {
403 goto loser;
404 }
405 extended = (OpaqueCRLFields*)crl->opaque;
406 if (options & CRL_DECODE_ADOPT_HEAP_DER0x00000008) {
407 extended->heapDER = PR_TRUE1;
408 }
409 if (options & CRL_DECODE_DONT_COPY_DER0x00000001) {
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_ArenaZAllocPORT_ArenaZAlloc_Util(arena, sizeof(SECItem));
415 if (crl->derCrl == NULL((void*)0)) {
416 goto loser;
417 }
418 rv = SECITEM_CopyItemSECITEM_CopyItem_Util(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_ENTRIES0x00000002) {
427 crlTemplate = cert_SignedCrlTemplateNoEntries;
428 extended->partial = PR_TRUE1;
429 }
430
431 /* decode the CRL info */
432 switch (type) {
433 case SEC_CRL_TYPE1:
434 rv = SEC_QuickDERDecodeItemSEC_QuickDERDecodeItem_Util(arena, crl, crlTemplate, crl->derCrl);
435 if (rv != SECSuccess) {
436 extended->badDER = PR_TRUE1;
437 break;
438 }
439 /* check for critical extensions */
440 rv = cert_check_crl_version(&crl->crl);
441 if (rv != SECSuccess) {
442 extended->badExtensions = PR_TRUE1;
443 break;
444 }
445
446 if (PR_TRUE1 == 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_TRUE1;
454 }
455
456 break;
457
458 default:
459 PORT_SetErrorPORT_SetError_Util(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
472loser:
473 if (options & CRL_DECODE_KEEP_BAD_CRL0x00000004) {
474 if (extended) {
475 extended->decodingError = PR_TRUE1;
476 }
477 if (crl) {
478 crl->referenceCount = 1;
479 return (crl);
480 }
481 }
482
483 if ((narena == NULL((void*)0)) && arena) {
484 PORT_FreeArenaPORT_FreeArena_Util(arena, PR_FALSE0);
485 }
486
487 return (0);
488}
489
490/*
491 * take a DER CRL and decode it into a CRL structure
492 */
493CERTSignedCrl*
494CERT_DecodeDERCrl(PLArenaPool* narena, SECItem* derSignedCrl, int type)
495{
496 return CERT_DecodeDERCrlWithFlags(narena, derSignedCrl, type,
497 CRL_DECODE_DEFAULT_OPTIONS0x00000000);
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 */
516static SECStatus
517SEC_FindCrlByKeyOnSlot(PK11SlotInfo* slot, SECItem* crlKey, int type,
518 CERTSignedCrl** decoded, PRInt32 decodeoptions)
519{
520 SECStatus rv = SECSuccess;
521 CERTSignedCrl* crl = NULL((void*)0);
522 SECItem* derCrl = NULL((void*)0);
523 CK_OBJECT_HANDLE crlHandle = 0;
524 char* url = NULL((void*)0);
525
526 PORT_Assert(decoded)((decoded)?((void)0):PR_Assert("decoded","crl.c",526));
527 if (!decoded) {
528 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_INVALID_ARGS);
529 return SECFailure;
530 }
531
532 derCrl = PK11_FindCrlByName(&slot, &crlHandle, crlKey, type, &url);
533 if (derCrl == NULL((void*)0)) {
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_GetErrorPORT_GetError_Util();
537 if (nsserror != SEC_ERROR_CRL_NOT_FOUND) {
538 rv = SECFailure;
539 }
540 goto loser;
541 }
542 PORT_Assert(crlHandle != CK_INVALID_HANDLE)((crlHandle != 0)?((void)0):PR_Assert("crlHandle != CK_INVALID_HANDLE"
,"crl.c",542))
;
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_DER0x00000008 | CRL_DECODE_DONT_COPY_DER0x00000001);
549
550 crl = CERT_DecodeDERCrlWithFlags(NULL((void*)0), derCrl, type, decodeoptions);
551 if (crl) {
552 crl->slot = slot;
553 slot = NULL((void*)0); /* adopt it */
554 derCrl = NULL((void*)0); /* adopted by the crl struct */
555 crl->pkcs11ID = crlHandle;
556 if (url) {
557 crl->url = PORT_ArenaStrdupPORT_ArenaStrdup_Util(crl->arena, url);
558 }
559 } else {
560 rv = SECFailure;
561 }
562
563 if (url) {
564 PORT_FreePORT_Free_Util(url);
565 }
566
567 if (slot) {
568 PK11_FreeSlot(slot);
569 }
570
571loser:
572 if (derCrl) {
573 SECITEM_FreeItemSECITEM_FreeItem_Util(derCrl, PR_TRUE1);
574 }
575
576 *decoded = crl;
577
578 return rv;
579}
580
581CERTSignedCrl*
582crl_storeCRL(PK11SlotInfo* slot, char* url, CERTSignedCrl* newCrl,
583 SECItem* derCrl, int type)
584{
585 CERTSignedCrl *oldCrl = NULL((void*)0), *crl = NULL((void*)0);
586 PRBool deleteOldCrl = PR_FALSE0;
587 CK_OBJECT_HANDLE crlHandle = CK_INVALID_HANDLE0;
588
589 PORT_Assert(newCrl)((newCrl)?((void)0):PR_Assert("newCrl","crl.c",589));
590 PORT_Assert(derCrl)((derCrl)?((void)0):PR_Assert("derCrl","crl.c",590));
591 PORT_Assert(type == SEC_CRL_TYPE)((type == 1)?((void)0):PR_Assert("type == SEC_CRL_TYPE","crl.c"
,591))
;
592
593 if (type != SEC_CRL_TYPE1) {
594 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_INVALID_ARGS);
595 return NULL((void*)0);
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_ENTRIES0x00000002);
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((void*)0)) {
607 /* if it's already there, quietly continue */
608 if (SECITEM_CompareItemSECITEM_CompareItem_Util(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_ArenaStrdupPORT_ArenaStrdup_Util(crl->arena, url);
616 goto done;
617 }
618 if (!SEC_CrlIsNewer(&newCrl->crl, &oldCrl->crl)) {
619 PORT_SetErrorPORT_SetError_Util(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_TRUE1;
631 }
632
633 /* invalidate CRL cache for this issuer */
634 CERT_CRLCacheRefreshIssuer(NULL((void*)0), &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_HANDLE0) {
638 crl = newCrl;
639 crl->slot = PK11_ReferenceSlot(slot);
640 crl->pkcs11ID = crlHandle;
641 if (url) {
642 crl->url = PORT_ArenaStrdupPORT_ArenaStrdup_Util(crl->arena, url);
643 }
644 }
645
646done:
647 if (oldCrl) {
648 if (deleteOldCrl && crlHandle != CK_INVALID_HANDLE0) {
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 */
664CERTSignedCrl*
665SEC_NewCrl(CERTCertDBHandle* handle, char* url, SECItem* derCrl, int type)
666{
667 CERTSignedCrl* retCrl = NULL((void*)0);
668 PK11SlotInfo* slot = PK11_GetInternalKeySlot();
669 retCrl =
670 PK11_ImportCRL(slot, derCrl, url, type, NULL((void*)0), CRL_IMPORT_BYPASS_CHECKS0x00000001,
671 NULL((void*)0), CRL_DECODE_DEFAULT_OPTIONS0x00000000);
672 PK11_FreeSlot(slot);
673
674 return retCrl;
675}
676
677CERTSignedCrl*
678SEC_FindCrlByDERCert(CERTCertDBHandle* handle, SECItem* derCrl, int type)
679{
680 PLArenaPool* arena;
681 SECItem crlKey;
682 SECStatus rv;
683 CERTSignedCrl* crl = NULL((void*)0);
684
685 /* create a scratch arena */
686 arena = PORT_NewArenaPORT_NewArena_Util(DER_DEFAULT_CHUNKSIZE(2048));
687 if (arena == NULL((void*)0)) {
688 return (NULL((void*)0));
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
700loser:
701 PORT_FreeArenaPORT_FreeArena_Util(arena, PR_FALSE0);
702 return (crl);
703}
704
705CERTSignedCrl*
706SEC_DupCrl(CERTSignedCrl* acrl)
707{
708 if (acrl) {
709 PR_ATOMIC_INCREMENT(&acrl->referenceCount)__sync_add_and_fetch(&acrl->referenceCount, 1);
710 return acrl;
711 }
712 return NULL((void*)0);
713}
714
715SECStatus
716SEC_DestroyCrl(CERTSignedCrl* crl)
717{
718 if (crl) {
719 if (PR_ATOMIC_DECREMENT(&crl->referenceCount)__sync_sub_and_fetch(&crl->referenceCount, 1) < 1) {
720 if (crl->slot) {
721 PK11_FreeSlot(crl->slot);
722 }
723 if (GetOpaqueCRLFields(crl)((OpaqueCRLFields*)crl->opaque) &&
724 PR_TRUE1 == GetOpaqueCRLFields(crl)((OpaqueCRLFields*)crl->opaque)->heapDER) {
725 SECITEM_FreeItemSECITEM_FreeItem_Util(crl->derCrl, PR_TRUE1);
726 }
727 if (crl->arena) {
728 PORT_FreeArenaPORT_FreeArena_Util(crl->arena, PR_FALSE0);
729 }
730 }
731 return SECSuccess;
732 } else {
733 return SECFailure;
734 }
735}
736
737SECStatus
738SEC_LookupCrls(CERTCertDBHandle* handle, CERTCrlHeadNode** nodes, int type)
739{
740 CERTCrlHeadNode* head;
741 PLArenaPool* arena = NULL((void*)0);
742 SECStatus rv;
743
744 *nodes = NULL((void*)0);
745
746 arena = PORT_NewArenaPORT_NewArena_Util(DER_DEFAULT_CHUNKSIZE(2048));
747 if (arena == NULL((void*)0)) {
748 return SECFailure;
749 }
750
751 /* build a head structure */
752 head = (CERTCrlHeadNode*)PORT_ArenaAllocPORT_ArenaAlloc_Util(arena, sizeof(CERTCrlHeadNode));
753 head->arena = arena;
754 head->first = NULL((void*)0);
755 head->last = NULL((void*)0);
756 head->dbhandle = handle;
757
758 /* Look up the proper crl types */
759 *nodes = head;
760
761 rv = PK11_LookupCrls(head, type, NULL((void*)0));
762
763 if (rv != SECSuccess) {
764 if (arena) {
765 PORT_FreeArenaPORT_FreeArena_Util(arena, PR_FALSE0);
766 *nodes = NULL((void*)0);
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*/
776SEC_ASN1_CHOOSER_IMPLEMENT(CERT_IssuerAndSNTemplate)const SEC_ASN1Template *NSS_Get_CERT_IssuerAndSNTemplate(void
*arg, PRBool enc) { return CERT_IssuerAndSNTemplate; }
777SEC_ASN1_CHOOSER_IMPLEMENT(CERT_CrlTemplate)const SEC_ASN1Template *NSS_Get_CERT_CrlTemplate(void *arg, PRBool
enc) { return CERT_CrlTemplate; }
778SEC_ASN1_CHOOSER_IMPLEMENT(CERT_SignedCrlTemplate)const SEC_ASN1Template *NSS_Get_CERT_SignedCrlTemplate(void *
arg, PRBool enc) { return CERT_SignedCrlTemplate; }
779SEC_ASN1_CHOOSER_IMPLEMENT(CERT_SetOfSignedCrlTemplate)const SEC_ASN1Template *NSS_Get_CERT_SetOfSignedCrlTemplate(void
*arg, PRBool enc) { return CERT_SetOfSignedCrlTemplate; }
780
781/* CRL cache code starts here */
782
783/* constructor */
784static SECStatus CachedCrl_Create(CachedCrl** returned, CERTSignedCrl* crl,
785 CRLOrigin origin);
786/* destructor */
787static SECStatus CachedCrl_Destroy(CachedCrl* crl);
788
789/* create hash table of CRL entries */
790static SECStatus CachedCrl_Populate(CachedCrl* crlobject);
791
792/* empty the cache content */
793static 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
798static SECStatus CachedCrl_Compare(CachedCrl* a, CachedCrl* b, PRBool* isDupe,
799 PRBool* isUpdated);
800
801/* create a DPCache object */
802static SECStatus DPCache_Create(CRLDPCache** returned, CERTCertificate* issuer,
803 const SECItem* subject, SECItem* dp);
804
805/* destructor for CRL DPCache object */
806static 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. */
810static SECStatus DPCache_AddCRL(CRLDPCache* cache, CachedCrl* crl,
811 PRBool* added);
812
813/* fetch the CRL for this DP from the PKCS#11 tokens */
814static 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 */
819static 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 */
824static PRBool DPCache_HasTokenCRLs(CRLDPCache* cache);
825
826/* remove CRL at offset specified */
827static SECStatus DPCache_RemoveCRL(CRLDPCache* cache, PRUint32 offset);
828
829/* Pick best CRL to use . needs write access */
830static SECStatus DPCache_SelectCRL(CRLDPCache* cache);
831
832/* create an issuer cache object (per CA subject ) */
833static SECStatus IssuerCache_Create(CRLIssuerCache** returned,
834 CERTCertificate* issuer,
835 const SECItem* subject, const SECItem* dp);
836
837/* destructor for CRL IssuerCache object */
838SECStatus IssuerCache_Destroy(CRLIssuerCache* cache);
839
840/* add a DPCache to the issuer cache */
841static 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 */
847static 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 */
855static void* PR_CALLBACK
856PreAllocTable(void* pool, PRSize size)
857{
858 PreAllocator* alloc = (PreAllocator*)pool;
859 PORT_Assert(alloc)((alloc)?((void)0):PR_Assert("alloc","crl.c",859));
860 if (!alloc) {
861 /* no allocator, or buffer full */
862 return NULL((void*)0);
863 }
864 if (size > (alloc->len - alloc->used)) {
865 /* initial buffer full, let's use the arena */
866 alloc->extra += size;
867 return PORT_ArenaAllocPORT_ArenaAlloc_Util(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. */
876static void PR_CALLBACK
877PreFreeTable(void* pool, void* item)
878{
879}
880
881/* allocate memory for hash table */
882static PLHashEntry* PR_CALLBACK
883PreAllocEntry(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. */
890static void PR_CALLBACK
891PreFreeEntry(void* pool, PLHashEntry* he, PRUintn flag)
892{
893}
894
895/* methods required for PL hash table functions */
896static PLHashAllocOps preAllocOps = { PreAllocTable, PreFreeTable,
897 PreAllocEntry, PreFreeEntry };
898
899/* destructor for PreAllocator object */
900void
901PreAllocator_Destroy(PreAllocator* allocator)
902{
903 if (!allocator) {
904 return;
905 }
906 if (allocator->arena) {
907 PORT_FreeArenaPORT_FreeArena_Util(allocator->arena, PR_TRUE1);
908 }
909}
910
911/* constructor for PreAllocator object */
912PreAllocator*
913PreAllocator_Create(PRSize size)
914{
915 PLArenaPool* arena = NULL((void*)0);
916 PreAllocator* prebuffer = NULL((void*)0);
917 arena = PORT_NewArenaPORT_NewArena_Util(DER_DEFAULT_CHUNKSIZE(2048));
918 if (!arena) {
919 return NULL((void*)0);
920 }
921 prebuffer = (PreAllocator*)PORT_ArenaZAllocPORT_ArenaZAlloc_Util(arena, sizeof(PreAllocator));
922 if (!prebuffer) {
923 PORT_FreeArenaPORT_FreeArena_Util(arena, PR_TRUE1);
924 return NULL((void*)0);
925 }
926 prebuffer->arena = arena;
927
928 if (size) {
929 prebuffer->len = size;
930 prebuffer->data = PORT_ArenaAllocPORT_ArenaAlloc_Util(arena, size);
931 if (!prebuffer->data) {
932 PORT_FreeArenaPORT_FreeArena_Util(arena, PR_TRUE1);
933 return NULL((void*)0);
934 }
935 }
936 return prebuffer;
937}
938
939/* global Named CRL cache object */
940static NamedCRLCache namedCRLCache = { NULL((void*)0), NULL((void*)0) };
941
942/* global CRL cache object */
943static CRLCache crlcache = { NULL((void*)0), NULL((void*)0) };
944
945/* initial state is off */
946static PRBool crlcache_initialized = PR_FALSE0;
947
948PRTime 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
952PRTime 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
956PRTime 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 */
960SECStatus
961InitCRLCache(void)
962{
963 if (PR_FALSE0 == crlcache_initialized) {
964 PORT_Assert(NULL == crlcache.lock)((((void*)0) == crlcache.lock)?((void)0):PR_Assert("NULL == crlcache.lock"
,"crl.c",964))
;
965 PORT_Assert(NULL == crlcache.issuers)((((void*)0) == crlcache.issuers)?((void)0):PR_Assert("NULL == crlcache.issuers"
,"crl.c",965))
;
966 PORT_Assert(NULL == namedCRLCache.lock)((((void*)0) == namedCRLCache.lock)?((void)0):PR_Assert("NULL == namedCRLCache.lock"
,"crl.c",966))
;
967 PORT_Assert(NULL == namedCRLCache.entries)((((void*)0) == namedCRLCache.entries)?((void)0):PR_Assert("NULL == namedCRLCache.entries"
,"crl.c",967))
;
968 if (crlcache.lock || crlcache.issuers || namedCRLCache.lock ||
969 namedCRLCache.entries) {
970 /* CRL cache already partially initialized */
971 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_LIBRARY_FAILURE);
972 return SECFailure;
973 }
974#ifdef GLOBAL_RWLOCK
975 crlcache.lock = NSSRWLock_NewNSSRWLock_New_Util(NSS_RWLOCK_RANK_NONE0, NULL((void*)0));
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((void*)0), NULL((void*)0));
982 namedCRLCache.entries = PL_NewHashTable(
983 0, SECITEM_Hash, SECITEM_HashCompare, PL_CompareValues, NULL((void*)0), NULL((void*)0));
984 if (!crlcache.lock || !namedCRLCache.lock || !crlcache.issuers ||
985 !namedCRLCache.entries) {
986 if (crlcache.lock) {
987#ifdef GLOBAL_RWLOCK
988 NSSRWLock_DestroyNSSRWLock_Destroy_Util(crlcache.lock);
989#else
990 PR_DestroyLock(crlcache.lock);
991#endif
992 crlcache.lock = NULL((void*)0);
993 }
994 if (namedCRLCache.lock) {
995 PR_DestroyLock(namedCRLCache.lock);
996 namedCRLCache.lock = NULL((void*)0);
997 }
998 if (crlcache.issuers) {
999 PL_HashTableDestroy(crlcache.issuers);
1000 crlcache.issuers = NULL((void*)0);
1001 }
1002 if (namedCRLCache.entries) {
1003 PL_HashTableDestroy(namedCRLCache.entries);
1004 namedCRLCache.entries = NULL((void*)0);
1005 }
1006
1007 return SECFailure;
1008 }
1009 crlcache_initialized = PR_TRUE1;
1010 return SECSuccess;
1011 } else {
1012 PORT_Assert(crlcache.lock)((crlcache.lock)?((void)0):PR_Assert("crlcache.lock","crl.c",
1012))
;
1013 PORT_Assert(crlcache.issuers)((crlcache.issuers)?((void)0):PR_Assert("crlcache.issuers","crl.c"
,1013))
;
1014 if ((NULL((void*)0) == crlcache.lock) || (NULL((void*)0) == 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 */
1025static SECStatus
1026DPCache_Destroy(CRLDPCache* cache)
1027{
1028 PRUint32 i = 0;
1029 PORT_Assert(cache)((cache)?((void)0):PR_Assert("cache","crl.c",1029));
1030 if (!cache) {
1031 PORT_Assert(0)((0)?((void)0):PR_Assert("0","crl.c",1031));
1032 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_LIBRARY_FAILURE);
1033 return SECFailure;
1034 }
1035 if (cache->lock) {
1036#ifdef DPC_RWLOCK1
1037 NSSRWLock_DestroyNSSRWLock_Destroy_Util(cache->lock);
1038#else
1039 PR_DestroyLock(cache->lock);
1040#endif
1041 } else {
1042 PORT_Assert(0)((0)?((void)0):PR_Assert("0","crl.c",1042));
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_FreePORT_Free_Util(cache->crls);
1055 }
1056 /* destroy the cert */
1057 if (cache->issuerDERCert) {
1058 SECITEM_FreeItemSECITEM_FreeItem_Util(cache->issuerDERCert, PR_TRUE1);
1059 }
1060 /* free the subject */
1061 if (cache->subject) {
1062 SECITEM_FreeItemSECITEM_FreeItem_Util(cache->subject, PR_TRUE1);
1063 }
1064 /* free the distribution points */
1065 if (cache->distributionPoint) {
1066 SECITEM_FreeItemSECITEM_FreeItem_Util(cache->distributionPoint, PR_TRUE1);
1067 }
1068 PORT_FreePORT_Free_Util(cache);
1069 return SECSuccess;
1070}
1071
1072/* destructor for CRL IssuerCache object */
1073SECStatus
1074IssuerCache_Destroy(CRLIssuerCache* cache)
1075{
1076 PORT_Assert(cache)((cache)?((void)0):PR_Assert("cache","crl.c",1076));
1077 if (!cache) {
1078 PORT_Assert(0)((0)?((void)0):PR_Assert("0","crl.c",1078));
1079 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_LIBRARY_FAILURE);
1080 return SECFailure;
1081 }
1082#ifdef XCRL
1083 if (cache->lock) {
1084 NSSRWLock_DestroyNSSRWLock_Destroy_Util(cache->lock);
1085 } else {
1086 PORT_Assert(0)((0)?((void)0):PR_Assert("0","crl.c",1086));
1087 PORT_SetErrorPORT_SetError_Util(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_FreeItemSECITEM_FreeItem_Util(cache->subject, PR_TRUE1);
1097 }
1098 if (SECSuccess != DPCache_Destroy(cache->dpp)) {
1099 PORT_Assert(0)((0)?((void)0):PR_Assert("0","crl.c",1099));
1100 return SECFailure;
1101 }
1102 PORT_FreePORT_Free_Util(cache);
1103 return SECSuccess;
1104}
1105
1106/* create a named CRL entry object */
1107static SECStatus
1108NamedCRLCacheEntry_Create(NamedCRLCacheEntry** returned)
1109{
1110 NamedCRLCacheEntry* entry = NULL((void*)0);
1111 if (!returned
22.1
'returned' is non-null
) {
23
Taking false branch
1112 PORT_Assert(0)((0)?((void)0):PR_Assert("0","crl.c",1112));
1113 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_LIBRARY_FAILURE);
1114 return SECFailure;
1115 }
1116 *returned = NULL((void*)0);
24
Null pointer value stored to 'newEntry'
1117 entry = (NamedCRLCacheEntry*)PORT_ZAllocPORT_ZAlloc_Util(sizeof(NamedCRLCacheEntry));
1118 if (!entry) {
25
Assuming 'entry' is null
26
Taking true branch
1119 return SECFailure;
1120 }
1121 *returned = entry;
1122 return SECSuccess;
1123}
1124
1125/* destroy a named CRL entry object */
1126static SECStatus
1127NamedCRLCacheEntry_Destroy(NamedCRLCacheEntry* entry)
1128{
1129 if (!entry) {
1130 PORT_Assert(0)((0)?((void)0):PR_Assert("0","crl.c",1130));
1131 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_LIBRARY_FAILURE);
1132 return SECFailure;
1133 }
1134 if (entry->crl) {
1135 /* named CRL cache owns DER memory */
1136 SECITEM_ZfreeItemSECITEM_ZfreeItem_Util(entry->crl, PR_TRUE1);
1137 }
1138 if (entry->canonicalizedName) {
1139 SECITEM_FreeItemSECITEM_FreeItem_Util(entry->canonicalizedName, PR_TRUE1);
1140 }
1141 PORT_FreePORT_Free_Util(entry);
1142 return SECSuccess;
1143}
1144
1145/* callback function used in hash table destructor */
1146static PRIntn PR_CALLBACK
1147FreeIssuer(PLHashEntry* he, PRIntn i, void* arg)
1148{
1149 CRLIssuerCache* issuer = NULL((void*)0);
1150 SECStatus* rv = (SECStatus*)arg;
1151
1152 PORT_Assert(he)((he)?((void)0):PR_Assert("he","crl.c",1152));
1153 if (!he) {
1154 return HT_ENUMERATE_NEXT0;
1155 }
1156 issuer = (CRLIssuerCache*)he->value;
1157 PORT_Assert(issuer)((issuer)?((void)0):PR_Assert("issuer","crl.c",1157));
1158 if (issuer) {
1159 if (SECSuccess != IssuerCache_Destroy(issuer)) {
1160 PORT_Assert(rv)((rv)?((void)0):PR_Assert("rv","crl.c",1160));
1161 if (rv) {
1162 *rv = SECFailure;
1163 }
1164 return HT_ENUMERATE_NEXT0;
1165 }
1166 }
1167 return HT_ENUMERATE_NEXT0;
1168}
1169
1170/* callback function used in hash table destructor */
1171static PRIntn PR_CALLBACK
1172FreeNamedEntries(PLHashEntry* he, PRIntn i, void* arg)
1173{
1174 NamedCRLCacheEntry* entry = NULL((void*)0);
1175 SECStatus* rv = (SECStatus*)arg;
1176
1177 PORT_Assert(he)((he)?((void)0):PR_Assert("he","crl.c",1177));
1178 if (!he) {
1179 return HT_ENUMERATE_NEXT0;
1180 }
1181 entry = (NamedCRLCacheEntry*)he->value;
1182 PORT_Assert(entry)((entry)?((void)0):PR_Assert("entry","crl.c",1182));
1183 if (entry) {
1184 if (SECSuccess != NamedCRLCacheEntry_Destroy(entry)) {
1185 PORT_Assert(rv)((rv)?((void)0):PR_Assert("rv","crl.c",1185));
1186 if (rv) {
1187 *rv = SECFailure;
1188 }
1189 return HT_ENUMERATE_NEXT0;
1190 }
1191 }
1192 return HT_ENUMERATE_NEXT0;
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 */
1200SECStatus
1201ShutdownCRLCache(void)
1202{
1203 SECStatus rv = SECSuccess;
1204 if (PR_FALSE0 == crlcache_initialized && !crlcache.lock &&
1205 !crlcache.issuers) {
1206 /* CRL cache has already been shut down */
1207 return SECSuccess;
1208 }
1209 if (PR_TRUE1 == crlcache_initialized &&
1210 (!crlcache.lock || !crlcache.issuers || !namedCRLCache.lock ||
1211 !namedCRLCache.entries)) {
1212 /* CRL cache has partially been shut down */
1213 PORT_SetErrorPORT_SetError_Util(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((void*)0);
1222/* free the global lock */
1223#ifdef GLOBAL_RWLOCK
1224 NSSRWLock_DestroyNSSRWLock_Destroy_Util(crlcache.lock);
1225#else
1226 PR_DestroyLock(crlcache.lock);
1227#endif
1228 crlcache.lock = NULL((void*)0);
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((void*)0);
1237 /* free the global lock */
1238 PR_DestroyLock(namedCRLCache.lock);
1239 namedCRLCache.lock = NULL((void*)0);
1240
1241 crlcache_initialized = PR_FALSE0;
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. */
1247static SECStatus
1248DPCache_AddCRL(CRLDPCache* cache, CachedCrl* newcrl, PRBool* added)
1249{
1250 CachedCrl** newcrls = NULL((void*)0);
1251 PRUint32 i = 0;
1252 PORT_Assert(cache)((cache)?((void)0):PR_Assert("cache","crl.c",1252));
1253 PORT_Assert(newcrl)((newcrl)?((void)0):PR_Assert("newcrl","crl.c",1253));
1254 PORT_Assert(added)((added)?((void)0):PR_Assert("added","crl.c",1254));
1255 if (!cache || !newcrl || !added) {
1256 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_LIBRARY_FAILURE);
1257 return SECFailure;
1258 }
1259
1260 *added = PR_FALSE0;
1261 /* before adding a new CRL, check if it is a duplicate */
1262 for (i = 0; i < cache->ncrls; i++) {
1263 CachedCrl* existing = NULL((void*)0);
1264 SECStatus rv = SECSuccess;
1265 PRBool dupe = PR_FALSE0, updated = PR_FALSE0;
1266 if (!cache->crls) {
1267 PORT_Assert(0)((0)?((void)0):PR_Assert("0","crl.c",1267));
1268 return SECFailure;
1269 }
1270 existing = cache->crls[i];
1271 if (!existing) {
1272 PORT_Assert(0)((0)?((void)0):PR_Assert("0","crl.c",1272));
1273 return SECFailure;
1274 }
1275 rv = CachedCrl_Compare(existing, newcrl, &dupe, &updated);
1276 if (SECSuccess != rv) {
1277 PORT_Assert(0)((0)?((void)0):PR_Assert("0","crl.c",1277));
1278 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_LIBRARY_FAILURE);
1279 return SECFailure;
1280 }
1281 if (PR_TRUE1 == dupe) {
1282 /* dupe */
1283 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_CRL_ALREADY_EXISTS);
1284 return SECSuccess;
1285 }
1286 if (PR_TRUE1 == 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)((0)?((void)0):PR_Assert("0","crl.c",1290));
1291 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_LIBRARY_FAILURE);
1292 return PR_FALSE0;
1293 }
1294 }
1295 }
1296
1297 newcrls = (CachedCrl**)PORT_ReallocPORT_Realloc_Util(cache->crls, (cache->ncrls + 1) * sizeof(CachedCrl*));
1298 if (!newcrls) {
1299 return SECFailure;
1300 }
1301 cache->crls = newcrls;
1302 cache->ncrls++;
1303 cache->crls[cache->ncrls - 1] = newcrl;
1304 *added = PR_TRUE1;
1305 return SECSuccess;
1306}
1307
1308/* remove CRL at offset specified */
1309static SECStatus
1310DPCache_RemoveCRL(CRLDPCache* cache, PRUint32 offset)
1311{
1312 CachedCrl* acrl = NULL((void*)0);
1313 PORT_Assert(cache)((cache)?((void)0):PR_Assert("cache","crl.c",1313));
1314 if (!cache || (!cache->crls) || (!(offset < cache->ncrls))) {
1315 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_LIBRARY_FAILURE);
1316 return SECFailure;
1317 }
1318 acrl = cache->crls[offset];
1319 PORT_Assert(acrl)((acrl)?((void)0):PR_Assert("acrl","crl.c",1319));
1320 if (!acrl) {
1321 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_LIBRARY_FAILURE);
1322 return SECFailure;
1323 }
1324 cache->crls[offset] = cache->crls[cache->ncrls - 1];
1325 cache->crls[cache->ncrls - 1] = NULL((void*)0);
1326 cache->ncrls--;
1327 if (cache->selected == acrl) {
1328 cache->selected = NULL((void*)0);
1329 }
1330 if (SECSuccess != CachedCrl_Destroy(acrl)) {
1331 PORT_Assert(0)((0)?((void)0):PR_Assert("0","crl.c",1331));
1332 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_LIBRARY_FAILURE);
1333 return SECFailure;
1334 }
1335 return SECSuccess;
1336}
1337
1338/* check whether a CRL object stored in a PKCS#11 token still exists in
1339 that token . This has to be efficient (the entire CRL value cannot be
1340 transferred accross the token boundaries), so this is accomplished by
1341 simply fetching the subject attribute and making sure it hasn't changed .
1342 Note that technically, the CRL object could have been replaced with a new
1343 PKCS#11 object of the same ID and subject (which actually happens in
1344 softoken), but this function has no way of knowing that the object
1345 value changed, since CKA_VALUE isn't checked. */
1346static PRBool
1347TokenCRLStillExists(CERTSignedCrl* crl)
1348{
1349 NSSItem newsubject;
1350 SECItem subject;
1351 CK_ULONG crl_class;
1352 PRStatus status;
1353 PK11SlotInfo* slot = NULL((void*)0);
1354 nssCryptokiObject instance;
1355 NSSArena* arena;
1356 PRBool xstatus = PR_TRUE1;
1357 SECItem* oldSubject = NULL((void*)0);
1358
1359 PORT_Assert(crl)((crl)?((void)0):PR_Assert("crl","crl.c",1359));
1360 if (!crl) {
1361 return PR_FALSE0;
1362 }
1363 slot = crl->slot;
1364 PORT_Assert(crl->slot)((crl->slot)?((void)0):PR_Assert("crl->slot","crl.c",1364
))
;
1365 if (!slot) {
1366 return PR_FALSE0;
1367 }
1368 oldSubject = &crl->crl.derName;
1369 PORT_Assert(oldSubject)((oldSubject)?((void)0):PR_Assert("oldSubject","crl.c",1369));
1370 if (!oldSubject) {
1371 return PR_FALSE0;
1372 }
1373
1374 /* query subject and type attributes in order to determine if the
1375 object has been deleted */
1376
1377 /* first, make an nssCryptokiObject */
1378 instance.handle = crl->pkcs11ID;
1379 PORT_Assert(instance.handle)((instance.handle)?((void)0):PR_Assert("instance.handle","crl.c"
,1379))
;
1380 if (!instance.handle) {
1381 return PR_FALSE0;
1382 }
1383 instance.token = PK11Slot_GetNSSToken(slot);
1384 PORT_Assert(instance.token)((instance.token)?((void)0):PR_Assert("instance.token","crl.c"
,1384))
;
1385 if (!instance.token) {
1386 return PR_FALSE0;
1387 }
1388 instance.isTokenObject = PR_TRUE1;
1389 instance.label = NULL((void*)0);
1390
1391 arena = NSSArena_Create();
1392 PORT_Assert(arena)((arena)?((void)0):PR_Assert("arena","crl.c",1392));
1393 if (!arena) {
1394 (void)nssToken_Destroy(instance.token);
1395 return PR_FALSE0;
1396 }
1397
1398 status =
1399 nssCryptokiCRL_GetAttributes(&instance, NULL((void*)0), /* XXX sessionOpt */
1400 arena, NULL((void*)0), &newsubject, /* subject */
1401 &crl_class, /* class */
1402 NULL((void*)0), NULL((void*)0));
1403 if (PR_SUCCESS == status) {
1404 subject.data = newsubject.data;
1405 subject.len = newsubject.size;
1406 if (SECITEM_CompareItemSECITEM_CompareItem_Util(oldSubject, &subject) != SECEqual) {
1407 xstatus = PR_FALSE0;
1408 }
1409 if (CKO_NSS_CRL((0x80000000UL | 0x4E534350) + 1) != crl_class) {
1410 xstatus = PR_FALSE0;
1411 }
1412 } else {
1413 xstatus = PR_FALSE0;
1414 }
1415 NSSArena_Destroy(arena);
1416 (void)nssToken_Destroy(instance.token);
1417 return xstatus;
1418}
1419
1420/* verify the signature of a CRL against its issuer at a given date */
1421static SECStatus
1422CERT_VerifyCRL(CERTSignedCrl* crlobject, CERTCertificate* issuer, PRTime vfdate,
1423 void* wincx)
1424{
1425 return CERT_VerifySignedData(&crlobject->signatureWrap, issuer, vfdate,
1426 wincx);
1427}
1428
1429/* verify a CRL and update cache state */
1430static SECStatus
1431CachedCrl_Verify(CRLDPCache* cache, CachedCrl* crlobject, PRTime vfdate,
1432 void* wincx)
1433{
1434 /* Check if it is an invalid CRL
1435 if we got a bad CRL, we want to cache it in order to avoid
1436 subsequent fetches of this same identical bad CRL. We set
1437 the cache to the invalid state to ensure that all certs on this
1438 DP are considered to have unknown status from now on. The cache
1439 object will remain in this state until the bad CRL object
1440 is removed from the token it was fetched from. If the cause
1441 of the failure is that we didn't have the issuer cert to
1442 verify the signature, this state can be cleared when
1443 the issuer certificate becomes available if that causes the
1444 signature to verify */
1445
1446 if (!cache || !crlobject) {
1447 PORT_Assert(0)((0)?((void)0):PR_Assert("0","crl.c",1447));
1448 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_LIBRARY_FAILURE);
1449 return SECFailure;
1450 }
1451 if (PR_TRUE1 == GetOpaqueCRLFields(crlobject->crl)((OpaqueCRLFields*)crlobject->crl->opaque)->decodingError) {
1452 crlobject->sigChecked = PR_TRUE1; /* we can never verify a CRL
1453 with bogus DER. Mark it checked so we won't try again */
1454 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_BAD_DER);
1455 return SECSuccess;
1456 } else {
1457 SECStatus signstatus = SECFailure;
1458 if (cache->issuerDERCert) {
1459 CERTCertificate* issuer = CERT_NewTempCertificate(
1460 cache->dbHandle, cache->issuerDERCert, NULL((void*)0), PR_FALSE0, PR_TRUE1);
1461
1462 if (issuer) {
1463 signstatus =
1464 CERT_VerifyCRL(crlobject->crl, issuer, vfdate, wincx);
1465 CERT_DestroyCertificate(issuer);
1466 }
1467 }
1468 if (SECSuccess != signstatus) {
1469 if (!cache->issuerDERCert) {
1470 /* we tried to verify without an issuer cert . This is
1471 because this CRL came through a call to SEC_FindCrlByName.
1472 So, we don't cache this verification failure. We'll try
1473 to verify the CRL again when a certificate from that issuer
1474 becomes available */
1475 } else {
1476 crlobject->sigChecked = PR_TRUE1;
1477 }
1478 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_CRL_BAD_SIGNATURE);
1479 return SECSuccess;
1480 } else {
1481 crlobject->sigChecked = PR_TRUE1;
1482 crlobject->sigValid = PR_TRUE1;
1483 }
1484 }
1485
1486 return SECSuccess;
1487}
1488
1489/* fetch the CRLs for this DP from the PKCS#11 tokens */
1490static SECStatus
1491DPCache_FetchFromTokens(CRLDPCache* cache, PRTime vfdate, void* wincx)
1492{
1493 SECStatus rv = SECSuccess;
1494 CERTCrlHeadNode head;
1495 if (!cache) {
1496 PORT_Assert(0)((0)?((void)0):PR_Assert("0","crl.c",1496));
1497 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_LIBRARY_FAILURE);
1498 return SECFailure;
1499 }
1500 /* first, initialize list */
1501 memset(&head, 0, sizeof(head));
1502 head.arena = PORT_NewArenaPORT_NewArena_Util(DER_DEFAULT_CHUNKSIZE(2048));
1503 rv = pk11_RetrieveCrls(&head, cache->subject, wincx);
1504
1505 /* if this function fails, something very wrong happened, such as an out
1506 of memory error during CRL decoding. We don't want to proceed and must
1507 mark the cache object invalid */
1508 if (SECFailure == rv) {
1509 /* fetch failed, add error bit */
1510 cache->invalid |= CRL_CACHE_LAST_FETCH_FAILED0x0002;
1511 } else {
1512 /* fetch was successful, clear this error bit */
1513 cache->invalid &= (~CRL_CACHE_LAST_FETCH_FAILED0x0002);
1514 }
1515
1516 /* add any CRLs found to our array */
1517 if (SECSuccess == rv) {
1518 CERTCrlNode* crlNode = NULL((void*)0);
1519
1520 for (crlNode = head.first; crlNode; crlNode = crlNode->next) {
1521 CachedCrl* returned = NULL((void*)0);
1522 CERTSignedCrl* crlobject = crlNode->crl;
1523 if (!crlobject) {
1524 PORT_Assert(0)((0)?((void)0):PR_Assert("0","crl.c",1524));
1525 continue;
1526 }
1527 rv = CachedCrl_Create(&returned, crlobject, CRL_OriginToken);
1528 if (SECSuccess == rv) {
1529 PRBool added = PR_FALSE0;
1530 rv = DPCache_AddCRL(cache, returned, &added);
1531 if (PR_TRUE1 != added) {
1532 rv = CachedCrl_Destroy(returned);
1533 returned = NULL((void*)0);
1534 } else if (vfdate) {
1535 rv = CachedCrl_Verify(cache, returned, vfdate, wincx);
1536 }
1537 } else {
1538 /* not enough memory to add the CRL to the cache. mark it
1539 invalid so we will try again . */
1540 cache->invalid |= CRL_CACHE_LAST_FETCH_FAILED0x0002;
1541 }
1542 if (SECFailure == rv) {
1543 break;
1544 }
1545 }
1546 }
1547
1548 if (head.arena) {
1549 CERTCrlNode* crlNode = NULL((void*)0);
1550 /* clean up the CRL list in case we got a partial one
1551 during a failed fetch */
1552 for (crlNode = head.first; crlNode; crlNode = crlNode->next) {
1553 if (crlNode->crl) {
1554 SEC_DestroyCrl(crlNode->crl); /* free the CRL. Either it got
1555 added to the cache and the refcount got bumped, or not, and
1556 thus we need to free its RAM */
1557 }
1558 }
1559 PORT_FreeArenaPORT_FreeArena_Util(head.arena, PR_FALSE0); /* destroy CRL list */
1560 }
1561
1562 return rv;
1563}
1564
1565static SECStatus
1566CachedCrl_GetEntry(CachedCrl* crl, const SECItem* sn, CERTCrlEntry** returned)
1567{
1568 CERTCrlEntry* acrlEntry;
1569
1570 PORT_Assert(crl)((crl)?((void)0):PR_Assert("crl","crl.c",1570));
1571 PORT_Assert(crl->entries)((crl->entries)?((void)0):PR_Assert("crl->entries","crl.c"
,1571))
;
1572 PORT_Assert(sn)((sn)?((void)0):PR_Assert("sn","crl.c",1572));
1573 PORT_Assert(returned)((returned)?((void)0):PR_Assert("returned","crl.c",1573));
1574 if (!crl || !sn || !returned || !crl->entries) {
1575 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_INVALID_ARGS);
1576 return SECFailure;
1577 }
1578 acrlEntry = PL_HashTableLookup(crl->entries, (void*)sn);
1579 if (acrlEntry) {
1580 *returned = acrlEntry;
1581 } else {
1582 *returned = NULL((void*)0);
1583 }
1584 return SECSuccess;
1585}
1586
1587/* check if a particular SN is in the CRL cache and return its entry */
1588dpcacheStatus
1589DPCache_Lookup(CRLDPCache* cache, const SECItem* sn, CERTCrlEntry** returned)
1590{
1591 SECStatus rv;
1592 if (!cache || !sn || !returned) {
1593 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_INVALID_ARGS);
1594 /* no cache or SN to look up, or no way to return entry */
1595 return dpcacheCallerError;
1596 }
1597 *returned = NULL((void*)0);
1598 if (0 != cache->invalid) {
1599 /* the cache contains a bad CRL, or there was a CRL fetching error. */
1600 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_CRL_INVALID);
1601 return dpcacheInvalidCacheError;
1602 }
1603 if (!cache->selected) {
1604 /* no CRL means no entry to return. This is OK, except for
1605 * NIST policy */
1606 return dpcacheEmpty;
1607 }
1608 rv = CachedCrl_GetEntry(cache->selected, sn, returned);
1609 if (SECSuccess != rv) {
1610 return dpcacheLookupError;
1611 } else {
1612 if (*returned) {
1613 return dpcacheFoundEntry;
1614 } else {
1615 return dpcacheNoEntry;
1616 }
1617 }
1618}
1619
1620#if defined(DPC_RWLOCK1)
1621
1622#define DPCache_LockWrite(){ if (readlocked) { NSSRWLock_UnlockRead_Util(cache->lock)
; } NSSRWLock_LockWrite_Util(cache->lock); }
\
1623 { \
1624 if (readlocked) { \
1625 NSSRWLock_UnlockReadNSSRWLock_UnlockRead_Util(cache->lock); \
1626 } \
1627 NSSRWLock_LockWriteNSSRWLock_LockWrite_Util(cache->lock); \
1628 }
1629
1630#define DPCache_UnlockWrite(){ if (readlocked) { NSSRWLock_LockRead_Util(cache->lock); }
NSSRWLock_UnlockWrite_Util(cache->lock); }
\
1631 { \
1632 if (readlocked) { \
1633 NSSRWLock_LockReadNSSRWLock_LockRead_Util(cache->lock); \
1634 } \
1635 NSSRWLock_UnlockWriteNSSRWLock_UnlockWrite_Util(cache->lock); \
1636 }
1637
1638#else
1639
1640/* with a global lock, we are always locked for read before we need write
1641 access, so do nothing */
1642
1643#define DPCache_LockWrite(){ if (readlocked) { NSSRWLock_UnlockRead_Util(cache->lock)
; } NSSRWLock_LockWrite_Util(cache->lock); }
\
1644 { \
1645 }
1646
1647#define DPCache_UnlockWrite(){ if (readlocked) { NSSRWLock_LockRead_Util(cache->lock); }
NSSRWLock_UnlockWrite_Util(cache->lock); }
\
1648 { \
1649 }
1650
1651#endif
1652
1653/* update the content of the CRL cache, including fetching of CRLs, and
1654 reprocessing with specified issuer and date . We are always holding
1655 either the read or write lock on DPCache upon entry. */
1656static SECStatus
1657DPCache_GetUpToDate(CRLDPCache* cache, CERTCertificate* issuer,
1658 PRBool readlocked, PRTime vfdate, void* wincx)
1659{
1660 /* Update the CRLDPCache now. We don't cache token CRL lookup misses
1661 yet, as we have no way of getting notified of new PKCS#11 object
1662 creation that happens in a token */
1663 SECStatus rv = SECSuccess;
1664 PRUint32 i = 0;
1665 PRBool forcedrefresh = PR_FALSE0;
1666 PRBool dirty = PR_FALSE0; /* whether something was changed in the
1667 cache state during this update cycle */
1668 PRBool hastokenCRLs = PR_FALSE0;
1669 PRTime now = 0;
1670 PRTime lastfetch = 0;
1671 PRBool mustunlock = PR_FALSE0;
1672
1673 if (!cache) {
1674 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_LIBRARY_FAILURE);
1675 return SECFailure;
1676 }
1677
1678 /* first, make sure we have obtained all the CRLs we need.
1679 We do an expensive token fetch in the following cases :
1680 1) cache is empty because no fetch was ever performed yet
1681 2) cache is explicitly set to refresh state
1682 3) cache is in invalid state because last fetch failed
1683 4) cache contains no token CRLs, and it's been more than one minute
1684 since the last fetch
1685 5) cache contains token CRLs, and it's been more than 10 minutes since
1686 the last fetch
1687 */
1688 forcedrefresh = cache->refresh;
1689 lastfetch = cache->lastfetch;
1690 if (PR_TRUE1 != forcedrefresh &&
1691 (!(cache->invalid & CRL_CACHE_LAST_FETCH_FAILED0x0002))) {
1692 now = PR_Now();
1693 hastokenCRLs = DPCache_HasTokenCRLs(cache);
1694 }
1695 if ((0 == lastfetch) ||
1696
1697 (PR_TRUE1 == forcedrefresh) ||
1698
1699 (cache->invalid & CRL_CACHE_LAST_FETCH_FAILED0x0002) ||
1700
1701 ((PR_FALSE0 == hastokenCRLs) &&
1702 ((now - cache->lastfetch > CRLCache_Empty_TokenFetch_Interval) ||
1703 (now < cache->lastfetch))) ||
1704
1705 ((PR_TRUE1 == hastokenCRLs) &&
1706 ((now - cache->lastfetch > CRLCache_TokenRefetch_Interval) ||
1707 (now < cache->lastfetch)))) {
1708 /* the cache needs to be refreshed, and/or we had zero CRL for this
1709 DP. Try to get one from PKCS#11 tokens */
1710 DPCache_LockWrite(){ if (readlocked) { NSSRWLock_UnlockRead_Util(cache->lock)
; } NSSRWLock_LockWrite_Util(cache->lock); }
;
1711 /* check if another thread updated before us, and skip update if so */
1712 if (lastfetch == cache->lastfetch) {
1713 /* we are the first */
1714 rv = DPCache_FetchFromTokens(cache, vfdate, wincx);
1715 if (PR_TRUE1 == cache->refresh) {
1716 cache->refresh = PR_FALSE0; /* clear refresh state */
1717 }
1718 dirty = PR_TRUE1;
1719 cache->lastfetch = PR_Now();
1720 }
1721 DPCache_UnlockWrite(){ if (readlocked) { NSSRWLock_LockRead_Util(cache->lock); }
NSSRWLock_UnlockWrite_Util(cache->lock); }
;
1722 }
1723
1724 /* now, make sure we have no extraneous CRLs (deleted token objects)
1725 we'll do this inexpensive existence check either
1726 1) if there was a token object fetch
1727 2) every minute */
1728 if ((PR_TRUE1 != dirty) && (!now)) {
1729 now = PR_Now();
1730 }
1731 if ((PR_TRUE1 == dirty) ||
1732 ((now - cache->lastcheck > CRLCache_ExistenceCheck_Interval) ||
1733 (now < cache->lastcheck))) {
1734 PRTime lastcheck = cache->lastcheck;
1735 mustunlock = PR_FALSE0;
1736 /* check if all CRLs still exist */
1737 for (i = 0; (i < cache->ncrls); i++) {
1738 CachedCrl* savcrl = cache->crls[i];
1739 if ((!savcrl) || (savcrl && CRL_OriginToken != savcrl->origin)) {
1740 /* we only want to check token CRLs */
1741 continue;
1742 }
1743 if ((PR_TRUE1 != TokenCRLStillExists(savcrl->crl))) {
1744
1745 /* this CRL is gone */
1746 if (PR_TRUE1 != mustunlock) {
1747 DPCache_LockWrite(){ if (readlocked) { NSSRWLock_UnlockRead_Util(cache->lock)
; } NSSRWLock_LockWrite_Util(cache->lock); }
;
1748 mustunlock = PR_TRUE1;
1749 }
1750 /* first, we need to check if another thread did an update
1751 before we did */
1752 if (lastcheck == cache->lastcheck) {
1753 /* the CRL is gone. And we are the one to do the update */
1754 DPCache_RemoveCRL(cache, i);
1755 dirty = PR_TRUE1;
1756 }
1757 /* stay locked here intentionally so we do all the other
1758 updates in this thread for the remaining CRLs */
1759 }
1760 }
1761 if (PR_TRUE1 == mustunlock) {
1762 cache->lastcheck = PR_Now();
1763 DPCache_UnlockWrite(){ if (readlocked) { NSSRWLock_LockRead_Util(cache->lock); }
NSSRWLock_UnlockWrite_Util(cache->lock); }
;
1764 mustunlock = PR_FALSE0;
1765 }
1766 }
1767
1768 /* add issuer certificate if it was previously unavailable */
1769 if (issuer && (NULL((void*)0) == cache->issuerDERCert) &&
1770 (SECSuccess == CERT_CheckCertUsage(issuer, KU_CRL_SIGN(0x02)))) {
1771 /* if we didn't have a valid issuer cert yet, but we do now. add it */
1772 DPCache_LockWrite(){ if (readlocked) { NSSRWLock_UnlockRead_Util(cache->lock)
; } NSSRWLock_LockWrite_Util(cache->lock); }
;
1773 if (!cache->issuerDERCert) {
1774 dirty = PR_TRUE1;
1775 cache->dbHandle = issuer->dbhandle;
1776 cache->issuerDERCert = SECITEM_DupItemSECITEM_DupItem_Util(&issuer->derCert);
1777 }
1778 DPCache_UnlockWrite(){ if (readlocked) { NSSRWLock_LockRead_Util(cache->lock); }
NSSRWLock_UnlockWrite_Util(cache->lock); }
;
1779 }
1780
1781 /* verify CRLs that couldn't be checked when inserted into the cache
1782 because the issuer cert or a verification date was unavailable.
1783 These are CRLs that were inserted into the cache through
1784 SEC_FindCrlByName, or through manual insertion, rather than through a
1785 certificate verification (CERT_CheckCRL) */
1786
1787 if (cache->issuerDERCert && vfdate) {
1788 mustunlock = PR_FALSE0;
1789 /* re-process all unverified CRLs */
1790 for (i = 0; i < cache->ncrls; i++) {
1791 CachedCrl* savcrl = cache->crls[i];
1792 if (!savcrl) {
1793 continue;
1794 }
1795 if (PR_TRUE1 != savcrl->sigChecked) {
1796 if (!mustunlock) {
1797 DPCache_LockWrite(){ if (readlocked) { NSSRWLock_UnlockRead_Util(cache->lock)
; } NSSRWLock_LockWrite_Util(cache->lock); }
;
1798 mustunlock = PR_TRUE1;
1799 }
1800 /* first, we need to check if another thread updated
1801 it before we did, and abort if it has been modified since
1802 we acquired the lock. Make sure first that the CRL is still
1803 in the array at the same position */
1804 if ((i < cache->ncrls) && (savcrl == cache->crls[i]) &&
1805 (PR_TRUE1 != savcrl->sigChecked)) {
1806 /* the CRL is still there, unverified. Do it */
1807 CachedCrl_Verify(cache, savcrl, vfdate, wincx);
1808 dirty = PR_TRUE1;
1809 }
1810 /* stay locked here intentionally so we do all the other
1811 updates in this thread for the remaining CRLs */
1812 }
1813 if (mustunlock && !dirty) {
1814 DPCache_UnlockWrite(){ if (readlocked) { NSSRWLock_LockRead_Util(cache->lock); }
NSSRWLock_UnlockWrite_Util(cache->lock); }
;
1815 mustunlock = PR_FALSE0;
1816 }
1817 }
1818 }
1819
1820 if (dirty || cache->mustchoose) {
1821 /* changes to the content of the CRL cache necessitate examining all
1822 CRLs for selection of the most appropriate one to cache */
1823 if (!mustunlock) {
1824 DPCache_LockWrite(){ if (readlocked) { NSSRWLock_UnlockRead_Util(cache->lock)
; } NSSRWLock_LockWrite_Util(cache->lock); }
;
1825 mustunlock = PR_TRUE1;
1826 }
1827 DPCache_SelectCRL(cache);
1828 cache->mustchoose = PR_FALSE0;
1829 }
1830 if (mustunlock)
1831 DPCache_UnlockWrite(){ if (readlocked) { NSSRWLock_LockRead_Util(cache->lock); }
NSSRWLock_UnlockWrite_Util(cache->lock); }
;
1832
1833 return rv;
1834}
1835
1836/* callback for qsort to sort by thisUpdate */
1837static int
1838SortCRLsByThisUpdate(const void* arg1, const void* arg2)
1839{
1840 PRTime timea, timeb;
1841 SECStatus rv = SECSuccess;
1842 CachedCrl *a, *b;
1843
1844 a = *(CachedCrl**)arg1;
1845 b = *(CachedCrl**)arg2;
1846
1847 if (!a || !b) {
1848 PORT_Assert(0)((0)?((void)0):PR_Assert("0","crl.c",1848));
1849 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_LIBRARY_FAILURE);
1850 rv = SECFailure;
1851 }
1852
1853 if (SECSuccess == rv) {
1854 rv = DER_DecodeTimeChoiceDER_DecodeTimeChoice_Util(&timea, &a->crl->crl.lastUpdate);
1855 }
1856 if (SECSuccess == rv) {
1857 rv = DER_DecodeTimeChoiceDER_DecodeTimeChoice_Util(&timeb, &b->crl->crl.lastUpdate);
1858 }
1859 if (SECSuccess == rv) {
1860 if (timea > timeb) {
1861 return 1; /* a is better than b */
1862 }
1863 if (timea < timeb) {
1864 return -1; /* a is not as good as b */
1865 }
1866 }
1867
1868 /* if they are equal, or if all else fails, use pointer differences */
1869 PORT_Assert(a != b)((a != b)?((void)0):PR_Assert("a != b","crl.c",1869)); /* they should never be equal */
1870 return a > b ? 1 : -1;
1871}
1872
1873/* callback for qsort to sort a set of disparate CRLs, some of which are
1874 invalid DER or failed signature check.
1875
1876 Validated CRLs are differentiated by thisUpdate .
1877 Validated CRLs are preferred over non-validated CRLs .
1878 Proper DER CRLs are preferred over non-DER data .
1879*/
1880static int
1881SortImperfectCRLs(const void* arg1, const void* arg2)
1882{
1883 CachedCrl *a, *b;
1884
1885 a = *(CachedCrl**)arg1;
1886 b = *(CachedCrl**)arg2;
1887
1888 if (!a || !b) {
1889 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_LIBRARY_FAILURE);
1890 PORT_Assert(0)((0)?((void)0):PR_Assert("0","crl.c",1890));
1891 } else {
1892 PRBool aDecoded = PR_FALSE0, bDecoded = PR_FALSE0;
1893 if ((PR_TRUE1 == a->sigValid) && (PR_TRUE1 == b->sigValid)) {
1894 /* both CRLs have been validated, choose the latest one */
1895 return SortCRLsByThisUpdate(arg1, arg2);
1896 }
1897 if (PR_TRUE1 == a->sigValid) {
1898 return 1; /* a is greater than b */
1899 }
1900 if (PR_TRUE1 == b->sigValid) {
1901 return -1; /* a is not as good as b */
1902 }
1903 aDecoded = GetOpaqueCRLFields(a->crl)((OpaqueCRLFields*)a->crl->opaque)->decodingError;
1904 bDecoded = GetOpaqueCRLFields(b->crl)((OpaqueCRLFields*)b->crl->opaque)->decodingError;
1905 /* neither CRL had its signature check pass */
1906 if ((PR_FALSE0 == aDecoded) && (PR_FALSE0 == bDecoded)) {
1907 /* both CRLs are proper DER, choose the latest one */
1908 return SortCRLsByThisUpdate(arg1, arg2);
1909 }
1910 if (PR_FALSE0 == aDecoded) {
1911 return 1; /* a is better than b */
1912 }
1913 if (PR_FALSE0 == bDecoded) {
1914 return -1; /* a is not as good as b */
1915 }
1916 /* both are invalid DER. sigh. */
1917 }
1918 /* if they are equal, or if all else fails, use pointer differences */
1919 PORT_Assert(a != b)((a != b)?((void)0):PR_Assert("a != b","crl.c",1919)); /* they should never be equal */
1920 return a > b ? 1 : -1;
1921}
1922
1923/* Pick best CRL to use . needs write access */
1924static SECStatus
1925DPCache_SelectCRL(CRLDPCache* cache)
1926{
1927 PRUint32 i;
1928 PRBool valid = PR_TRUE1;
1929 CachedCrl* selected = NULL((void*)0);
1930
1931 PORT_Assert(cache)((cache)?((void)0):PR_Assert("cache","crl.c",1931));
1932 if (!cache) {
1933 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_LIBRARY_FAILURE);
1934 return SECFailure;
1935 }
1936 /* if any invalid CRL is present, then the CRL cache is
1937 considered invalid, for security reasons */
1938 for (i = 0; i < cache->ncrls; i++) {
1939 if (!cache->crls[i] || !cache->crls[i]->sigChecked ||
1940 !cache->crls[i]->sigValid) {
1941 valid = PR_FALSE0;
1942 break;
1943 }
1944 }
1945 if (PR_TRUE1 == valid) {
1946 /* all CRLs are valid, clear this error */
1947 cache->invalid &= (~CRL_CACHE_INVALID_CRLS0x0001);
1948 } else {
1949 /* some CRLs are invalid, set this error */
1950 cache->invalid |= CRL_CACHE_INVALID_CRLS0x0001;
1951 }
1952
1953 if (cache->invalid) {
1954 /* cache is in an invalid state, so reset it */
1955 if (cache->selected) {
1956 cache->selected = NULL((void*)0);
1957 }
1958 /* also sort the CRLs imperfectly */
1959 qsort(cache->crls, cache->ncrls, sizeof(CachedCrl*), SortImperfectCRLs);
1960 return SECSuccess;
1961 }
1962
1963 if (cache->ncrls) {
1964 /* all CRLs are good, sort them by thisUpdate */
1965 qsort(cache->crls, cache->ncrls, sizeof(CachedCrl*), SortCRLsByThisUpdate);
1966
1967 /* pick the newest CRL */
1968 selected = cache->crls[cache->ncrls - 1];
1969
1970 /* and populate the cache */
1971 if (SECSuccess != CachedCrl_Populate(selected)) {
1972 return SECFailure;
1973 }
1974 }
1975
1976 cache->selected = selected;
1977
1978 return SECSuccess;
1979}
1980
1981/* initialize a DPCache object */
1982static SECStatus
1983DPCache_Create(CRLDPCache** returned, CERTCertificate* issuer,
1984 const SECItem* subject, SECItem* dp)
1985{
1986 CRLDPCache* cache = NULL((void*)0);
1987 PORT_Assert(returned)((returned)?((void)0):PR_Assert("returned","crl.c",1987));
1988 /* issuer and dp are allowed to be NULL */
1989 if (!returned || !subject) {
1990 PORT_Assert(0)((0)?((void)0):PR_Assert("0","crl.c",1990));
1991 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_LIBRARY_FAILURE);
1992 return SECFailure;
1993 }
1994 *returned = NULL((void*)0);
1995 cache = PORT_ZAllocPORT_ZAlloc_Util(sizeof(CRLDPCache));
1996 if (!cache) {
1997 return SECFailure;
1998 }
1999#ifdef DPC_RWLOCK1
2000 cache->lock = NSSRWLock_NewNSSRWLock_New_Util(NSS_RWLOCK_RANK_NONE0, NULL((void*)0));
2001#else
2002 cache->lock = PR_NewLock();
2003#endif
2004 if (!cache->lock) {
2005 PORT_FreePORT_Free_Util(cache);
2006 return SECFailure;
2007 }
2008 if (issuer) {
2009 cache->dbHandle = issuer->dbhandle;
2010 cache->issuerDERCert = SECITEM_DupItemSECITEM_DupItem_Util(&issuer->derCert);
2011 }
2012 cache->distributionPoint = SECITEM_DupItemSECITEM_DupItem_Util(dp);
2013 cache->subject = SECITEM_DupItemSECITEM_DupItem_Util(subject);
2014 cache->lastfetch = 0;
2015 cache->lastcheck = 0;
2016 *returned = cache;
2017 return SECSuccess;
2018}
2019
2020/* create an issuer cache object (per CA subject ) */
2021static SECStatus
2022IssuerCache_Create(CRLIssuerCache** returned, CERTCertificate* issuer,
2023 const SECItem* subject, const SECItem* dp)
2024{
2025 SECStatus rv = SECSuccess;
2026 CRLIssuerCache* cache = NULL((void*)0);
2027 PORT_Assert(returned)((returned)?((void)0):PR_Assert("returned","crl.c",2027));
2028 PORT_Assert(subject)((subject)?((void)0):PR_Assert("subject","crl.c",2028));
2029 /* issuer and dp are allowed to be NULL */
2030 if (!returned || !subject) {
2031 PORT_Assert(0)((0)?((void)0):PR_Assert("0","crl.c",2031));
2032 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_LIBRARY_FAILURE);
2033 return SECFailure;
2034 }
2035 *returned = NULL((void*)0);
2036 cache = (CRLIssuerCache*)PORT_ZAllocPORT_ZAlloc_Util(sizeof(CRLIssuerCache));
2037 if (!cache) {
2038 return SECFailure;
2039 }
2040 cache->subject = SECITEM_DupItemSECITEM_DupItem_Util(subject);
2041#ifdef XCRL
2042 cache->lock = NSSRWLock_NewNSSRWLock_New_Util(NSS_RWLOCK_RANK_NONE0, NULL((void*)0));
2043 if (!cache->lock) {
2044 rv = SECFailure;
2045 }
2046 if (SECSuccess == rv && issuer) {
2047 cache->issuer = CERT_DupCertificate(issuer);
2048 if (!cache->issuer) {
2049 rv = SECFailure;
2050 }
2051 }
2052#endif
2053 if (SECSuccess != rv) {
2054 PORT_Assert(SECSuccess == IssuerCache_Destroy(cache))((SECSuccess == IssuerCache_Destroy(cache))?((void)0):PR_Assert
("SECSuccess == IssuerCache_Destroy(cache)","crl.c",2054))
;
2055 return SECFailure;
2056 }
2057 *returned = cache;
2058 return SECSuccess;
2059}
2060
2061/* add a DPCache to the issuer cache */
2062static SECStatus
2063IssuerCache_AddDP(CRLIssuerCache* cache, CERTCertificate* issuer,
2064 const SECItem* subject, const SECItem* dp,
2065 CRLDPCache** newdpc)
2066{
2067 /* now create the required DP cache object */
2068 if (!cache || !subject || !newdpc) {
2069 PORT_Assert(0)((0)?((void)0):PR_Assert("0","crl.c",2069));
2070 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_LIBRARY_FAILURE);
2071 return SECFailure;
2072 }
2073 if (!dp) {
2074 /* default distribution point */
2075 SECStatus rv = DPCache_Create(&cache->dpp, issuer, subject, NULL((void*)0));
2076 if (SECSuccess == rv) {
2077 *newdpc = cache->dpp;
2078 return SECSuccess;
2079 }
2080 } else {
2081 /* we should never hit this until we support multiple DPs */
2082 PORT_Assert(dp)((dp)?((void)0):PR_Assert("dp","crl.c",2082));
2083 /* XCRL allocate a new distribution point cache object, initialize it,
2084 and add it to the hash table of DPs */
2085 }
2086 return SECFailure;
2087}
2088
2089/* add an IssuerCache to the global hash table of issuers */
2090static SECStatus
2091CRLCache_AddIssuer(CRLIssuerCache* issuer)
2092{
2093 PORT_Assert(issuer)((issuer)?((void)0):PR_Assert("issuer","crl.c",2093));
2094 PORT_Assert(crlcache.issuers)((crlcache.issuers)?((void)0):PR_Assert("crlcache.issuers","crl.c"
,2094))
;
2095 if (!issuer || !crlcache.issuers) {
2096 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_LIBRARY_FAILURE);
2097 return SECFailure;
2098 }
2099 if (NULL((void*)0) == PL_HashTableAdd(crlcache.issuers, (void*)issuer->subject,
2100 (void*)issuer)) {
2101 return SECFailure;
2102 }
2103 return SECSuccess;
2104}
2105
2106/* retrieve the issuer cache object for a given issuer subject */
2107static SECStatus
2108CRLCache_GetIssuerCache(CRLCache* cache, const SECItem* subject,
2109 CRLIssuerCache** returned)
2110{
2111 /* we need to look up the issuer in the hash table */
2112 SECStatus rv = SECSuccess;
2113 PORT_Assert(cache)((cache)?((void)0):PR_Assert("cache","crl.c",2113));
2114 PORT_Assert(subject)((subject)?((void)0):PR_Assert("subject","crl.c",2114));
2115 PORT_Assert(returned)((returned)?((void)0):PR_Assert("returned","crl.c",2115));
2116 PORT_Assert(crlcache.issuers)((crlcache.issuers)?((void)0):PR_Assert("crlcache.issuers","crl.c"
,2116))
;
2117 if (!cache || !subject || !returned || !crlcache.issuers) {
2118 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_LIBRARY_FAILURE);
2119 rv = SECFailure;
2120 }
2121
2122 if (SECSuccess == rv) {
2123 *returned = (CRLIssuerCache*)PL_HashTableLookup(crlcache.issuers,
2124 (void*)subject);
2125 }
2126
2127 return rv;
2128}
2129
2130/* retrieve the full CRL object that best matches the content of a DPCache */
2131static CERTSignedCrl*
2132GetBestCRL(CRLDPCache* cache, PRBool entries)
2133{
2134 CachedCrl* acrl = NULL((void*)0);
2135
2136 PORT_Assert(cache)((cache)?((void)0):PR_Assert("cache","crl.c",2136));
2137 if (!cache) {
2138 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_LIBRARY_FAILURE);
2139 return NULL((void*)0);
2140 }
2141
2142 if (0 == cache->ncrls) {
2143 /* empty cache*/
2144 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_CRL_NOT_FOUND);
2145 return NULL((void*)0);
2146 }
2147
2148 /* if we have a valid full CRL selected, return it */
2149 if (cache->selected) {
2150 return SEC_DupCrl(cache->selected->crl);
2151 }
2152
2153 /* otherwise, use latest valid DER CRL */
2154 acrl = cache->crls[cache->ncrls - 1];
2155
2156 if (acrl && (PR_FALSE0 == GetOpaqueCRLFields(acrl->crl)((OpaqueCRLFields*)acrl->crl->opaque)->decodingError)) {
2157 SECStatus rv = SECSuccess;
2158 if (PR_TRUE1 == entries) {
2159 rv = CERT_CompleteCRLDecodeEntries(acrl->crl);
2160 }
2161 if (SECSuccess == rv) {
2162 return SEC_DupCrl(acrl->crl);
2163 }
2164 }
2165
2166 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_CRL_NOT_FOUND);
2167 return NULL((void*)0);
2168}
2169
2170/* get a particular DPCache object from an IssuerCache */
2171static CRLDPCache*
2172IssuerCache_GetDPCache(CRLIssuerCache* cache, const SECItem* dp)
2173{
2174 CRLDPCache* dpp = NULL((void*)0);
2175 PORT_Assert(cache)((cache)?((void)0):PR_Assert("cache","crl.c",2175));
2176 /* XCRL for now we only support the "default" DP, ie. the
2177 full CRL. So we can return the global one without locking. In
2178 the future we will have a lock */
2179 PORT_Assert(NULL == dp)((((void*)0) == dp)?((void)0):PR_Assert("NULL == dp","crl.c",
2179))
;
2180 if (!cache || dp) {
2181 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_LIBRARY_FAILURE);
2182 return NULL((void*)0);
2183 }
2184#ifdef XCRL
2185 NSSRWLock_LockReadNSSRWLock_LockRead_Util(cache->lock);
2186#endif
2187 dpp = cache->dpp;
2188#ifdef XCRL
2189 NSSRWLock_UnlockReadNSSRWLock_UnlockRead_Util(cache->lock);
2190#endif
2191 return dpp;
2192}
2193
2194/* get a DPCache object for the given issuer subject and dp
2195 Automatically creates the cache object if it doesn't exist yet.
2196 */
2197SECStatus
2198AcquireDPCache(CERTCertificate* issuer, const SECItem* subject,
2199 const SECItem* dp, PRTime t, void* wincx, CRLDPCache** dpcache,
2200 PRBool* writeLocked)
2201{
2202 SECStatus rv = SECSuccess;
2203 CRLIssuerCache* issuercache = NULL((void*)0);
2204#ifdef GLOBAL_RWLOCK
2205 PRBool globalwrite = PR_FALSE0;
2206#endif
2207 PORT_Assert(crlcache.lock)((crlcache.lock)?((void)0):PR_Assert("crlcache.lock","crl.c",
2207))
;
2208 if (!crlcache.lock) {
2209 /* CRL cache is not initialized */
2210 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_LIBRARY_FAILURE);
2211 return SECFailure;
2212 }
2213#ifdef GLOBAL_RWLOCK
2214 NSSRWLock_LockReadNSSRWLock_LockRead_Util(crlcache.lock);
2215#else
2216 PR_Lock(crlcache.lock);
2217#endif
2218 rv = CRLCache_GetIssuerCache(&crlcache, subject, &issuercache);
2219 if (SECSuccess != rv) {
2220#ifdef GLOBAL_RWLOCK
2221 NSSRWLock_UnlockReadNSSRWLock_UnlockRead_Util(crlcache.lock);
2222#else
2223 PR_Unlock(crlcache.lock);
2224#endif
2225 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_LIBRARY_FAILURE);
2226 return SECFailure;
2227 }
2228 if (!issuercache) {
2229 /* there is no cache for this issuer yet. This means this is the
2230 first time we look up a cert from that issuer, and we need to
2231 create the cache. */
2232
2233 rv = IssuerCache_Create(&issuercache, issuer, subject, dp);
2234 if (SECSuccess == rv && !issuercache) {
2235 PORT_Assert(issuercache)((issuercache)?((void)0):PR_Assert("issuercache","crl.c",2235
))
;
2236 rv = SECFailure;
2237 }
2238
2239 if (SECSuccess == rv) {
2240 /* This is the first time we look up a cert of this issuer.
2241 Create the DPCache for this DP . */
2242 rv = IssuerCache_AddDP(issuercache, issuer, subject, dp, dpcache);
2243 }
2244
2245 if (SECSuccess == rv) {
2246 /* lock the DPCache for write to ensure the update happens in this
2247 thread */
2248 *writeLocked = PR_TRUE1;
2249#ifdef DPC_RWLOCK1
2250 NSSRWLock_LockWriteNSSRWLock_LockWrite_Util((*dpcache)->lock);
2251#else
2252 PR_Lock((*dpcache)->lock);
2253#endif
2254 }
2255
2256 if (SECSuccess == rv) {
2257/* now add the new issuer cache to the global hash table of
2258 issuers */
2259#ifdef GLOBAL_RWLOCK
2260 CRLIssuerCache* existing = NULL((void*)0);
2261 NSSRWLock_UnlockReadNSSRWLock_UnlockRead_Util(crlcache.lock);
2262 /* when using a r/w lock for the global cache, check if the issuer
2263 already exists before adding to the hash table */
2264 NSSRWLock_LockWriteNSSRWLock_LockWrite_Util(crlcache.lock);
2265 globalwrite = PR_TRUE1;
2266 rv = CRLCache_GetIssuerCache(&crlcache, subject, &existing);
2267 if (!existing) {
2268#endif
2269 rv = CRLCache_AddIssuer(issuercache);
2270 if (SECSuccess != rv) {
2271 /* failure */
2272 rv = SECFailure;
2273 }
2274#ifdef GLOBAL_RWLOCK
2275 } else {
2276 /* somebody else updated before we did */
2277 IssuerCache_Destroy(issuercache); /* destroy the new object */
2278 issuercache = existing; /* use the existing one */
2279 *dpcache = IssuerCache_GetDPCache(issuercache, dp);
2280 }
2281#endif
2282 }
2283
2284/* now unlock the global cache. We only want to lock the issuer hash
2285 table addition. Holding it longer would hurt scalability */
2286#ifdef GLOBAL_RWLOCK
2287 if (PR_TRUE1 == globalwrite) {
2288 NSSRWLock_UnlockWriteNSSRWLock_UnlockWrite_Util(crlcache.lock);
2289 globalwrite = PR_FALSE0;
2290 } else {
2291 NSSRWLock_UnlockReadNSSRWLock_UnlockRead_Util(crlcache.lock);
2292 }
2293#else
2294 PR_Unlock(crlcache.lock);
2295#endif
2296
2297 /* if there was a failure adding an issuer cache object, destroy it */
2298 if (SECSuccess != rv && issuercache) {
2299 if (PR_TRUE1 == *writeLocked) {
2300#ifdef DPC_RWLOCK1
2301 NSSRWLock_UnlockWriteNSSRWLock_UnlockWrite_Util((*dpcache)->lock);
2302#else
2303 PR_Unlock((*dpcache)->lock);
2304#endif
2305 }
2306 IssuerCache_Destroy(issuercache);
2307 issuercache = NULL((void*)0);
2308 }
2309
2310 if (SECSuccess != rv) {
2311 return SECFailure;
2312 }
2313 } else {
2314#ifdef GLOBAL_RWLOCK
2315 NSSRWLock_UnlockReadNSSRWLock_UnlockRead_Util(crlcache.lock);
2316#else
2317 PR_Unlock(crlcache.lock);
2318#endif
2319 *dpcache = IssuerCache_GetDPCache(issuercache, dp);
2320 }
2321 /* we now have a DPCache that we can use for lookups */
2322 /* lock it for read, unless we already locked for write */
2323 if (PR_FALSE0 == *writeLocked) {
2324#ifdef DPC_RWLOCK1
2325 NSSRWLock_LockReadNSSRWLock_LockRead_Util((*dpcache)->lock);
2326#else
2327 PR_Lock((*dpcache)->lock);
2328#endif
2329 }
2330
2331 if (SECSuccess == rv) {
2332 /* currently there is always one and only one DPCache per issuer */
2333 PORT_Assert(*dpcache)((*dpcache)?((void)0):PR_Assert("*dpcache","crl.c",2333));
2334 if (*dpcache) {
2335 /* make sure the DP cache is up to date before using it */
2336 rv = DPCache_GetUpToDate(*dpcache, issuer, PR_FALSE0 == *writeLocked,
2337 t, wincx);
2338 } else {
2339 rv = SECFailure;
2340 }
2341 }
2342 return rv;
2343}
2344
2345/* unlock access to the DPCache */
2346void
2347ReleaseDPCache(CRLDPCache* dpcache, PRBool writeLocked)
2348{
2349 if (!dpcache) {
2350 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_LIBRARY_FAILURE);
2351 return;
2352 }
2353#ifdef DPC_RWLOCK1
2354 if (PR_TRUE1 == writeLocked) {
2355 NSSRWLock_UnlockWriteNSSRWLock_UnlockWrite_Util(dpcache->lock);
2356 } else {
2357 NSSRWLock_UnlockReadNSSRWLock_UnlockRead_Util(dpcache->lock);
2358 }
2359#else
2360 PR_Unlock(dpcache->lock);
2361#endif
2362}
2363
2364SECStatus
2365cert_CheckCertRevocationStatus(CERTCertificate* cert, CERTCertificate* issuer,
2366 const SECItem* dp, PRTime t, void* wincx,
2367 CERTRevocationStatus* revStatus,
2368 CERTCRLEntryReasonCode* revReason)
2369{
2370 PRBool lockedwrite = PR_FALSE0;
2371 SECStatus rv = SECSuccess;
2372 CRLDPCache* dpcache = NULL((void*)0);
2373 CERTRevocationStatus status = certRevocationStatusRevoked;
2374 CERTCRLEntryReasonCode reason = crlEntryReasonUnspecified;
2375 CERTCrlEntry* entry = NULL((void*)0);
2376 dpcacheStatus ds;
2377
2378 if (!cert || !issuer) {
2379 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_LIBRARY_FAILURE);
2380 return SECFailure;
2381 }
2382
2383 if (revStatus) {
2384 *revStatus = status;
2385 }
2386 if (revReason) {
2387 *revReason = reason;
2388 }
2389
2390 if (t &&
2391 secCertTimeValid != CERT_CheckCertValidTimes(issuer, t, PR_FALSE0)) {
2392 /* we won't be able to check the CRL's signature if the issuer cert
2393 is expired as of the time we are verifying. This may cause a valid
2394 CRL to be cached as bad. short-circuit to avoid this case. */
2395 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_EXPIRED_ISSUER_CERTIFICATE);
2396 return SECFailure;
2397 }
2398
2399 rv = AcquireDPCache(issuer, &issuer->derSubject, dp, t, wincx, &dpcache,
2400 &lockedwrite);
2401 PORT_Assert(SECSuccess == rv)((SECSuccess == rv)?((void)0):PR_Assert("SECSuccess == rv","crl.c"
,2401))
;
2402 if (SECSuccess != rv) {
2403 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_LIBRARY_FAILURE);
2404 return SECFailure;
2405 }
2406 /* now look up the certificate SN in the DP cache's CRL */
2407 ds = DPCache_Lookup(dpcache, &cert->serialNumber, &entry);
2408 switch (ds) {
2409 case dpcacheFoundEntry:
2410 PORT_Assert(entry)((entry)?((void)0):PR_Assert("entry","crl.c",2410));
2411 /* check the time if we have one */
2412 if (entry->revocationDate.data && entry->revocationDate.len) {
2413 PRTime revocationDate = 0;
2414 if (SECSuccess ==
2415 DER_DecodeTimeChoiceDER_DecodeTimeChoice_Util(&revocationDate,
2416 &entry->revocationDate)) {
2417 /* we got a good revocation date, only consider the
2418 certificate revoked if the time we are inquiring about
2419 is past the revocation date */
2420 if (t >= revocationDate) {
2421 rv = SECFailure;
2422 } else {
2423 status = certRevocationStatusValid;
2424 }
2425 } else {
2426 /* invalid revocation date, consider the certificate
2427 permanently revoked */
2428 rv = SECFailure;
2429 }
2430 } else {
2431 /* no revocation date, certificate is permanently revoked */
2432 rv = SECFailure;
2433 }
2434 if (SECFailure == rv) {
2435 (void)CERT_FindCRLEntryReasonExten(entry, &reason);
2436 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_REVOKED_CERTIFICATE);
2437 }
2438 break;
2439
2440 case dpcacheEmpty:
2441 /* useful for NIST policy */
2442 status = certRevocationStatusUnknown;
2443 break;
2444
2445 case dpcacheNoEntry:
2446 status = certRevocationStatusValid;
2447 break;
2448
2449 case dpcacheInvalidCacheError:
2450 /* treat it as unknown and let the caller decide based on
2451 the policy */
2452 status = certRevocationStatusUnknown;
2453 break;
2454
2455 default:
2456 /* leave status as revoked */
2457 break;
2458 }
2459
2460 ReleaseDPCache(dpcache, lockedwrite);
2461 if (revStatus) {
2462 *revStatus = status;
2463 }
2464 if (revReason) {
2465 *revReason = reason;
2466 }
2467 return rv;
2468}
2469
2470/* check CRL revocation status of given certificate and issuer */
2471SECStatus
2472CERT_CheckCRL(CERTCertificate* cert, CERTCertificate* issuer, const SECItem* dp,
2473 PRTime t, void* wincx)
2474{
2475 return cert_CheckCertRevocationStatus(cert, issuer, dp, t, wincx, NULL((void*)0),
2476 NULL((void*)0));
2477}
2478
2479/* retrieve full CRL object that best matches the cache status */
2480CERTSignedCrl*
2481SEC_FindCrlByName(CERTCertDBHandle* handle, SECItem* crlKey, int type)
2482{
2483 CERTSignedCrl* acrl = NULL((void*)0);
2484 CRLDPCache* dpcache = NULL((void*)0);
2485 SECStatus rv = SECSuccess;
2486 PRBool writeLocked = PR_FALSE0;
2487
2488 if (!crlKey) {
2489 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_INVALID_ARGS);
2490 return NULL((void*)0);
2491 }
2492
2493 rv = AcquireDPCache(NULL((void*)0), crlKey, NULL((void*)0), 0, NULL((void*)0), &dpcache, &writeLocked);
2494 if (SECSuccess == rv) {
2495 acrl = GetBestCRL(dpcache, PR_TRUE1); /* decode entries, because
2496 SEC_FindCrlByName always returned fully decoded CRLs in the past */
2497 ReleaseDPCache(dpcache, writeLocked);
2498 }
2499 return acrl;
2500}
2501
2502/* invalidate the CRL cache for a given issuer, which forces a refetch of
2503 CRL objects from PKCS#11 tokens */
2504void
2505CERT_CRLCacheRefreshIssuer(CERTCertDBHandle* dbhandle, SECItem* crlKey)
2506{
2507 CRLDPCache* cache = NULL((void*)0);
2508 SECStatus rv = SECSuccess;
2509 PRBool writeLocked = PR_FALSE0;
2510 PRBool readlocked;
2511
2512 (void)dbhandle; /* silence compiler warnings */
2513
2514 /* XCRL we will need to refresh all the DPs of the issuer in the future,
2515 not just the default one */
2516 rv = AcquireDPCache(NULL((void*)0), crlKey, NULL((void*)0), 0, NULL((void*)0), &cache, &writeLocked);
2517 if (SECSuccess != rv) {
2518 return;
2519 }
2520 /* we need to invalidate the DPCache here */
2521 readlocked = (writeLocked == PR_TRUE1 ? PR_FALSE0 : PR_TRUE1);
2522 DPCache_LockWrite(){ if (readlocked) { NSSRWLock_UnlockRead_Util(cache->lock)
; } NSSRWLock_LockWrite_Util(cache->lock); }
;
2523 cache->refresh = PR_TRUE1;
2524 DPCache_UnlockWrite(){ if (readlocked) { NSSRWLock_LockRead_Util(cache->lock); }
NSSRWLock_UnlockWrite_Util(cache->lock); }
;
2525 ReleaseDPCache(cache, writeLocked);
2526 return;
2527}
2528
2529/* add the specified RAM CRL object to the cache */
2530SECStatus
2531CERT_CacheCRL(CERTCertDBHandle* dbhandle, SECItem* newdercrl)
2532{
2533 CRLDPCache* cache = NULL((void*)0);
2534 SECStatus rv = SECSuccess;
2535 PRBool writeLocked = PR_FALSE0;
2536 PRBool readlocked;
2537 CachedCrl* returned = NULL((void*)0);
2538 PRBool added = PR_FALSE0;
2539 CERTSignedCrl* newcrl = NULL((void*)0);
2540 int realerror = 0;
2541
2542 if (!dbhandle || !newdercrl) {
2543 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_INVALID_ARGS);
2544 return SECFailure;
2545 }
2546
2547 /* first decode the DER CRL to make sure it's OK */
2548 newcrl = CERT_DecodeDERCrlWithFlags(NULL((void*)0), newdercrl, SEC_CRL_TYPE1,
2549 CRL_DECODE_DONT_COPY_DER0x00000001 |
2550 CRL_DECODE_SKIP_ENTRIES0x00000002);
2551
2552 if (!newcrl) {
2553 return SECFailure;
2554 }
2555
2556 /* XXX check if it has IDP extension. If so, do not proceed and set error */
2557
2558 rv = AcquireDPCache(NULL((void*)0), &newcrl->crl.derName, NULL((void*)0), 0, NULL((void*)0), &cache,
2559 &writeLocked);
2560 if (SECSuccess == rv) {
2561 readlocked = (writeLocked == PR_TRUE1 ? PR_FALSE0 : PR_TRUE1);
2562
2563 rv = CachedCrl_Create(&returned, newcrl, CRL_OriginExplicit);
2564 if (SECSuccess == rv && returned) {
2565 DPCache_LockWrite(){ if (readlocked) { NSSRWLock_UnlockRead_Util(cache->lock)
; } NSSRWLock_LockWrite_Util(cache->lock); }
;
2566 rv = DPCache_AddCRL(cache, returned, &added);
2567 if (PR_TRUE1 != added) {
2568 realerror = PORT_GetErrorPORT_GetError_Util();
2569 CachedCrl_Destroy(returned);
2570 returned = NULL((void*)0);
2571 }
2572 DPCache_UnlockWrite(){ if (readlocked) { NSSRWLock_LockRead_Util(cache->lock); }
NSSRWLock_UnlockWrite_Util(cache->lock); }
;
2573 }
2574
2575 ReleaseDPCache(cache, writeLocked);
2576
2577 if (!added) {
2578 rv = SECFailure;
2579 }
2580 }
2581 SEC_DestroyCrl(newcrl); /* free the CRL. Either it got added to the cache
2582 and the refcount got bumped, or not, and thus we need to free its
2583 RAM */
2584 if (realerror) {
2585 PORT_SetErrorPORT_SetError_Util(realerror);
2586 }
2587 return rv;
2588}
2589
2590/* remove the specified RAM CRL object from the cache */
2591SECStatus
2592CERT_UncacheCRL(CERTCertDBHandle* dbhandle, SECItem* olddercrl)
2593{
2594 CRLDPCache* cache = NULL((void*)0);
2595 SECStatus rv = SECSuccess;
2596 PRBool writeLocked = PR_FALSE0;
2597 PRBool readlocked;
2598 PRBool removed = PR_FALSE0;
2599 PRUint32 i;
2600 CERTSignedCrl* oldcrl = NULL((void*)0);
2601
2602 if (!dbhandle || !olddercrl) {
2603 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_INVALID_ARGS);
2604 return SECFailure;
2605 }
2606
2607 /* first decode the DER CRL to make sure it's OK */
2608 oldcrl = CERT_DecodeDERCrlWithFlags(NULL((void*)0), olddercrl, SEC_CRL_TYPE1,
2609 CRL_DECODE_DONT_COPY_DER0x00000001 |
2610 CRL_DECODE_SKIP_ENTRIES0x00000002);
2611
2612 if (!oldcrl) {
2613 /* if this DER CRL can't decode, it can't be in the cache */
2614 return SECFailure;
2615 }
2616
2617 rv = AcquireDPCache(NULL((void*)0), &oldcrl->crl.derName, NULL((void*)0), 0, NULL((void*)0), &cache,
2618 &writeLocked);
2619 if (SECSuccess == rv) {
2620 CachedCrl* returned = NULL((void*)0);
2621
2622 readlocked = (writeLocked == PR_TRUE1 ? PR_FALSE0 : PR_TRUE1);
2623
2624 rv = CachedCrl_Create(&returned, oldcrl, CRL_OriginExplicit);
2625 if (SECSuccess == rv && returned) {
2626 DPCache_LockWrite(){ if (readlocked) { NSSRWLock_UnlockRead_Util(cache->lock)
; } NSSRWLock_LockWrite_Util(cache->lock); }
;
2627 for (i = 0; i < cache->ncrls; i++) {
2628 PRBool dupe = PR_FALSE0, updated = PR_FALSE0;
2629 rv = CachedCrl_Compare(returned, cache->crls[i], &dupe,
2630 &updated);
2631 if (SECSuccess != rv) {
2632 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_LIBRARY_FAILURE);
2633 break;
2634 }
2635 if (PR_TRUE1 == dupe) {
2636 rv = DPCache_RemoveCRL(cache, i); /* got a match */
2637 if (SECSuccess == rv) {
2638 cache->mustchoose = PR_TRUE1;
2639 removed = PR_TRUE1;
2640 }
2641 break;
2642 }
2643 }
2644
2645 DPCache_UnlockWrite(){ if (readlocked) { NSSRWLock_LockRead_Util(cache->lock); }
NSSRWLock_UnlockWrite_Util(cache->lock); }
;
2646
2647 if (SECSuccess != CachedCrl_Destroy(returned)) {
2648 rv = SECFailure;
2649 }
2650 }
2651
2652 ReleaseDPCache(cache, writeLocked);
2653 }
2654 if (SECSuccess != SEC_DestroyCrl(oldcrl)) {
2655 /* need to do this because object is refcounted */
2656 rv = SECFailure;
2657 }
2658 if (SECSuccess == rv && PR_TRUE1 != removed) {
2659 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_CRL_NOT_FOUND);
2660 }
2661 return rv;
2662}
2663
2664SECStatus
2665cert_AcquireNamedCRLCache(NamedCRLCache** returned)
2666{
2667 PORT_Assert(returned)((returned)?((void)0):PR_Assert("returned","crl.c",2667));
9
'?' condition is true
2668 if (!namedCRLCache.lock
9.1
Field 'lock' is non-null, which participates in a condition later
) {
10
Taking false branch
2669 PORT_Assert(0)((0)?((void)0):PR_Assert("0","crl.c",2669));
2670 return SECFailure;
2671 }
2672 PR_Lock(namedCRLCache.lock);
2673 *returned = &namedCRLCache;
11
Value assigned to 'ncc', which participates in a condition later
2674 return SECSuccess;
2675}
2676
2677/* This must be called only while cache is acquired, and the entry is only
2678 * valid until cache is released.
2679 */
2680SECStatus
2681cert_FindCRLByGeneralName(NamedCRLCache* ncc, const SECItem* canonicalizedName,
2682 NamedCRLCacheEntry** retEntry)
2683{
2684 if (!ncc
15.1
'ncc' is non-null
|| !canonicalizedName
15.2
'canonicalizedName' is non-null, which participates in a condition later
|| !retEntry
15.3
'retEntry' is non-null
) {
16
Taking false branch
2685 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_INVALID_ARGS);
2686 return SECFailure;
2687 }
2688 *retEntry = (NamedCRLCacheEntry*)PL_HashTableLookup(
17
Value assigned to 'oldEntry', which participates in a condition later
2689 namedCRLCache.entries, (void*)canonicalizedName);
2690 return SECSuccess;
2691}
2692
2693SECStatus
2694cert_ReleaseNamedCRLCache(NamedCRLCache* ncc)
2695{
2696 if (!ncc) {
2697 return SECFailure;
2698 }
2699 if (!ncc->lock) {
2700 PORT_Assert(0)((0)?((void)0):PR_Assert("0","crl.c",2700));
2701 return SECFailure;
2702 }
2703 PR_Unlock(namedCRLCache.lock);
2704 return SECSuccess;
2705}
2706
2707/* creates new named cache entry from CRL, and tries to add it to CRL cache */
2708static SECStatus
2709addCRLToCache(CERTCertDBHandle* dbhandle, SECItem* crl,
2710 const SECItem* canonicalizedName, NamedCRLCacheEntry** newEntry)
2711{
2712 SECStatus rv = SECSuccess;
2713 NamedCRLCacheEntry* entry = NULL((void*)0);
2714
2715 /* create new named entry */
2716 if (SECSuccess != NamedCRLCacheEntry_Create(newEntry) || !*newEntry) {
22
Calling 'NamedCRLCacheEntry_Create'
27
Returning from 'NamedCRLCacheEntry_Create'
2717 /* no need to keep unused CRL around */
2718 SECITEM_ZfreeItemSECITEM_ZfreeItem_Util(crl, PR_TRUE1);
2719 return SECFailure;
2720 }
2721 entry = *newEntry;
2722 entry->crl = crl; /* named CRL cache owns DER */
2723 entry->lastAttemptTime = PR_Now();
2724 entry->canonicalizedName = SECITEM_DupItemSECITEM_DupItem_Util(canonicalizedName);
2725 if (!entry->canonicalizedName) {
2726 rv = NamedCRLCacheEntry_Destroy(entry); /* destroys CRL too */
2727 PORT_Assert(SECSuccess == rv)((SECSuccess == rv)?((void)0):PR_Assert("SECSuccess == rv","crl.c"
,2727))
;
2728 return SECFailure;
2729 }
2730 /* now, attempt to insert CRL into CRL cache */
2731 if (SECSuccess == CERT_CacheCRL(dbhandle, entry->crl)) {
2732 entry->inCRLCache = PR_TRUE1;
2733 entry->successfulInsertionTime = entry->lastAttemptTime;
2734 } else {
2735 switch (PR_GetError()) {
2736 case SEC_ERROR_CRL_ALREADY_EXISTS:
2737 entry->dupe = PR_TRUE1;
2738 break;
2739
2740 case SEC_ERROR_BAD_DER:
2741 entry->badDER = PR_TRUE1;
2742 break;
2743
2744 /* all other reasons */
2745 default:
2746 entry->unsupported = PR_TRUE1;
2747 break;
2748 }
2749 rv = SECFailure;
2750 /* no need to keep unused CRL around */
2751 SECITEM_ZfreeItemSECITEM_ZfreeItem_Util(entry->crl, PR_TRUE1);
2752 entry->crl = NULL((void*)0);
2753 }
2754 return rv;
2755}
2756
2757/* take ownership of CRL, and insert it into the named CRL cache
2758 * and indexed CRL cache
2759 */
2760SECStatus
2761cert_CacheCRLByGeneralName(CERTCertDBHandle* dbhandle, SECItem* crl,
2762 const SECItem* canonicalizedName)
2763{
2764 NamedCRLCacheEntry *oldEntry, *newEntry = NULL((void*)0);
2765 NamedCRLCache* ncc = NULL((void*)0);
2766 SECStatus rv = SECSuccess;
2767
2768 PORT_Assert(namedCRLCache.lock)((namedCRLCache.lock)?((void)0):PR_Assert("namedCRLCache.lock"
,"crl.c",2768))
;
1
Assuming field 'lock' is non-null
2
'?' condition is true
2769 PORT_Assert(namedCRLCache.entries)((namedCRLCache.entries)?((void)0):PR_Assert("namedCRLCache.entries"
,"crl.c",2769))
;
3
Assuming field 'entries' is non-null
4
'?' condition is true
2770
2771 if (!crl || !canonicalizedName) {
5
Assuming 'crl' is non-null
6
Assuming 'canonicalizedName' is non-null
7
Taking false branch
2772 PORT_Assert(0)((0)?((void)0):PR_Assert("0","crl.c",2772));
2773 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_INVALID_ARGS);
2774 return SECFailure;
2775 }
2776
2777 rv = cert_AcquireNamedCRLCache(&ncc);
8
Calling 'cert_AcquireNamedCRLCache'
12
Returning from 'cert_AcquireNamedCRLCache'
2778 PORT_Assert(SECSuccess == rv)((SECSuccess == rv)?((void)0):PR_Assert("SECSuccess == rv","crl.c"
,2778))
;
13
'?' condition is true
2779 if (SECSuccess != rv
13.1
'rv' is equal to SECSuccess
) {
14
Taking false branch
2780 SECITEM_ZfreeItemSECITEM_ZfreeItem_Util(crl, PR_TRUE1);
2781 return SECFailure;
2782 }
2783 rv = cert_FindCRLByGeneralName(ncc, canonicalizedName, &oldEntry);
15
Calling 'cert_FindCRLByGeneralName'
18
Returning from 'cert_FindCRLByGeneralName'
2784 PORT_Assert(SECSuccess == rv)((SECSuccess == rv)?((void)0):PR_Assert("SECSuccess == rv","crl.c"
,2784))
;
19
'?' condition is true
2785 if (SECSuccess != rv
19.1
'rv' is equal to SECSuccess
) {
20
Taking false branch
2786 (void)cert_ReleaseNamedCRLCache(ncc);
2787 SECITEM_ZfreeItemSECITEM_ZfreeItem_Util(crl, PR_TRUE1);
2788 return SECFailure;
2789 }
2790 if (SECSuccess ==
29
Taking false branch
2791 addCRLToCache(dbhandle, crl, canonicalizedName, &newEntry)) {
21
Calling 'addCRLToCache'
28
Returning from 'addCRLToCache'
2792 if (!oldEntry) {
2793 /* add new good entry to the hash table */
2794 if (NULL((void*)0) == PL_HashTableAdd(namedCRLCache.entries,
2795 (void*)newEntry->canonicalizedName,
2796 (void*)newEntry)) {
2797 PORT_Assert(0)((0)?((void)0):PR_Assert("0","crl.c",2797));
2798 NamedCRLCacheEntry_Destroy(newEntry);
2799 rv = SECFailure;
2800 }
2801 } else {
2802 PRBool removed;
2803 /* remove the old CRL from the cache if needed */
2804 if (oldEntry->inCRLCache) {
2805 rv = CERT_UncacheCRL(dbhandle, oldEntry->crl);
2806 PORT_Assert(SECSuccess == rv)((SECSuccess == rv)?((void)0):PR_Assert("SECSuccess == rv","crl.c"
,2806))
;
2807 }
2808 removed = PL_HashTableRemove(namedCRLCache.entries,
2809 (void*)oldEntry->canonicalizedName);
2810 PORT_Assert(removed)((removed)?((void)0):PR_Assert("removed","crl.c",2810));
2811 if (!removed) {
2812 rv = SECFailure;
2813 /* leak old entry since we couldn't remove it from the hash
2814 * table */
2815 } else {
2816 PORT_CheckSuccess(NamedCRLCacheEntry_Destroy(oldEntry))(((NamedCRLCacheEntry_Destroy(oldEntry)) == SECSuccess)?((void
)0):PR_Assert("(NamedCRLCacheEntry_Destroy(oldEntry)) == SECSuccess"
,"crl.c",2816))
;
2817 }
2818 if (NULL((void*)0) == PL_HashTableAdd(namedCRLCache.entries,
2819 (void*)newEntry->canonicalizedName,
2820 (void*)newEntry)) {
2821 PORT_Assert(0)((0)?((void)0):PR_Assert("0","crl.c",2821));
2822 rv = SECFailure;
2823 }
2824 }
2825 } else {
2826 /* error adding new CRL to cache */
2827 if (!oldEntry) {
30
Assuming 'oldEntry' is null
31
Taking true branch
2828 /* no old cache entry, use the new one even though it's bad */
2829 if (NULL((void*)0) == PL_HashTableAdd(namedCRLCache.entries,
2830 (void*)newEntry->canonicalizedName,
32
Access to field 'canonicalizedName' results in a dereference of a null pointer (loaded from variable 'newEntry')
2831 (void*)newEntry)) {
2832 PORT_Assert(0)((0)?((void)0):PR_Assert("0","crl.c",2832));
2833 rv = SECFailure;
2834 }
2835 } else {
2836 if (oldEntry->inCRLCache) {
2837 /* previous cache entry was good, keep it and update time */
2838 oldEntry->lastAttemptTime = newEntry->lastAttemptTime;
2839 /* throw away new bad entry */
2840 rv = NamedCRLCacheEntry_Destroy(newEntry);
2841 PORT_Assert(SECSuccess == rv)((SECSuccess == rv)?((void)0):PR_Assert("SECSuccess == rv","crl.c"
,2841))
;
2842 } else {
2843 /* previous cache entry was bad, just replace it */
2844 PRBool removed = PL_HashTableRemove(
2845 namedCRLCache.entries, (void*)oldEntry->canonicalizedName);
2846 PORT_Assert(removed)((removed)?((void)0):PR_Assert("removed","crl.c",2846));
2847 if (!removed) {
2848 /* leak old entry since we couldn't remove it from the hash
2849 * table */
2850 rv = SECFailure;
2851 } else {
2852 PORT_CheckSuccess(NamedCRLCacheEntry_Destroy(oldEntry))(((NamedCRLCacheEntry_Destroy(oldEntry)) == SECSuccess)?((void
)0):PR_Assert("(NamedCRLCacheEntry_Destroy(oldEntry)) == SECSuccess"
,"crl.c",2852))
;
2853 }
2854 if (NULL((void*)0) == PL_HashTableAdd(namedCRLCache.entries,
2855 (void*)newEntry->canonicalizedName,
2856 (void*)newEntry)) {
2857 PORT_Assert(0)((0)?((void)0):PR_Assert("0","crl.c",2857));
2858 rv = SECFailure;
2859 }
2860 }
2861 }
2862 }
2863 PORT_CheckSuccess(cert_ReleaseNamedCRLCache(ncc))(((cert_ReleaseNamedCRLCache(ncc)) == SECSuccess)?((void)0):PR_Assert
("(cert_ReleaseNamedCRLCache(ncc)) == SECSuccess","crl.c",2863
))
;
2864
2865 return rv;
2866}
2867
2868static SECStatus
2869CachedCrl_Create(CachedCrl** returned, CERTSignedCrl* crl, CRLOrigin origin)
2870{
2871 CachedCrl* newcrl = NULL((void*)0);
2872 if (!returned) {
2873 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_LIBRARY_FAILURE);
2874 return SECFailure;
2875 }
2876 newcrl = PORT_ZAllocPORT_ZAlloc_Util(sizeof(CachedCrl));
2877 if (!newcrl) {
2878 return SECFailure;
2879 }
2880 newcrl->crl = SEC_DupCrl(crl);
2881 newcrl->origin = origin;
2882 *returned = newcrl;
2883 return SECSuccess;
2884}
2885
2886/* empty the cache content */
2887static SECStatus
2888CachedCrl_Depopulate(CachedCrl* crl)
2889{
2890 if (!crl) {
2891 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_LIBRARY_FAILURE);
2892 return SECFailure;
2893 }
2894 /* destroy the hash table */
2895 if (crl->entries) {
2896 PL_HashTableDestroy(crl->entries);
2897 crl->entries = NULL((void*)0);
2898 }
2899
2900 /* free the pre buffer */
2901 if (crl->prebuffer) {
2902 PreAllocator_Destroy(crl->prebuffer);
2903 crl->prebuffer = NULL((void*)0);
2904 }
2905 return SECSuccess;
2906}
2907
2908static SECStatus
2909CachedCrl_Destroy(CachedCrl* crl)
2910{
2911 if (!crl) {
2912 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_LIBRARY_FAILURE);
2913 return SECFailure;
2914 }
2915 CachedCrl_Depopulate(crl);
2916 SEC_DestroyCrl(crl->crl);
2917 PORT_FreePORT_Free_Util(crl);
2918 return SECSuccess;
2919}
2920
2921/* create hash table of CRL entries */
2922static SECStatus
2923CachedCrl_Populate(CachedCrl* crlobject)
2924{
2925 SECStatus rv = SECFailure;
2926 CERTCrlEntry** crlEntry = NULL((void*)0);
2927 PRUint32 numEntries = 0;
2928
2929 if (!crlobject) {
2930 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_LIBRARY_FAILURE);
2931 return SECFailure;
2932 }
2933 /* complete the entry decoding . XXX thread-safety of CRL object */
2934 rv = CERT_CompleteCRLDecodeEntries(crlobject->crl);
2935 if (SECSuccess != rv) {
2936 crlobject->unbuildable = PR_TRUE1; /* don't try to build this again */
2937 return SECFailure;
2938 }
2939
2940 if (crlobject->entries && crlobject->prebuffer) {
2941 /* cache is already built */
2942 return SECSuccess;
2943 }
2944
2945 /* build the hash table from the full CRL */
2946 /* count CRL entries so we can pre-allocate space for hash table entries */
2947 for (crlEntry = crlobject->crl->crl.entries; crlEntry && *crlEntry;
2948 crlEntry++) {
2949 numEntries++;
2950 }
2951 crlobject->prebuffer =
2952 PreAllocator_Create(numEntries * sizeof(PLHashEntry));
2953 PORT_Assert(crlobject->prebuffer)((crlobject->prebuffer)?((void)0):PR_Assert("crlobject->prebuffer"
,"crl.c",2953))
;
2954 if (!crlobject->prebuffer) {
2955 return SECFailure;
2956 }
2957 /* create a new hash table */
2958 crlobject->entries =
2959 PL_NewHashTable(0, SECITEM_Hash, SECITEM_HashCompare, PL_CompareValues,
2960 &preAllocOps, crlobject->prebuffer);
2961 PORT_Assert(crlobject->entries)((crlobject->entries)?((void)0):PR_Assert("crlobject->entries"
,"crl.c",2961))
;
2962 if (!crlobject->entries) {
2963 return SECFailure;
2964 }
2965 /* add all serial numbers to the hash table */
2966 for (crlEntry = crlobject->crl->crl.entries; crlEntry && *crlEntry;
2967 crlEntry++) {
2968 PL_HashTableAdd(crlobject->entries, &(*crlEntry)->serialNumber,
2969 *crlEntry);
2970 }
2971
2972 return SECSuccess;
2973}
2974
2975/* returns true if there are CRLs from PKCS#11 slots */
2976static PRBool
2977DPCache_HasTokenCRLs(CRLDPCache* cache)
2978{
2979 PRBool answer = PR_FALSE0;
2980 PRUint32 i;
2981 for (i = 0; i < cache->ncrls; i++) {
2982 if (cache->crls[i] && (CRL_OriginToken == cache->crls[i]->origin)) {
2983 answer = PR_TRUE1;
2984 break;
2985 }
2986 }
2987 return answer;
2988}
2989
2990/* are these CRLs the same, as far as the cache is concerned ? */
2991/* are these CRLs the same token object but with different DER ?
2992 This can happen if the DER CRL got updated in the token, but the PKCS#11
2993 object ID did not change. NSS softoken has the unfortunate property to
2994 never change the object ID for CRL objects. */
2995static SECStatus
2996CachedCrl_Compare(CachedCrl* a, CachedCrl* b, PRBool* isDupe, PRBool* isUpdated)
2997{
2998 PORT_Assert(a)((a)?((void)0):PR_Assert("a","crl.c",2998));
2999 PORT_Assert(b)((b)?((void)0):PR_Assert("b","crl.c",2999));
3000 PORT_Assert(isDupe)((isDupe)?((void)0):PR_Assert("isDupe","crl.c",3000));
3001 PORT_Assert(isUpdated)((isUpdated)?((void)0):PR_Assert("isUpdated","crl.c",3001));
3002 if (!a || !b || !isDupe || !isUpdated || !a->crl || !b->crl) {
3003 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_LIBRARY_FAILURE);
3004 return SECFailure;
3005 }
3006
3007 *isDupe = *isUpdated = PR_FALSE0;
3008
3009 if (a == b) {
3010 /* dupe */
3011 *isDupe = PR_TRUE1;
3012 *isUpdated = PR_FALSE0;
3013 return SECSuccess;
3014 }
3015 if (b->origin != a->origin) {
3016 /* CRLs of different origins are not considered dupes,
3017 and can't be updated either */
3018 return SECSuccess;
3019 }
3020 if (CRL_OriginToken == b->origin) {
3021 /* for token CRLs, slot and PKCS#11 object handle must match for CRL
3022 to truly be a dupe */
3023 if ((b->crl->slot == a->crl->slot) &&
3024 (b->crl->pkcs11ID == a->crl->pkcs11ID)) {
3025 /* ASN.1 DER needs to match for dupe check */
3026 /* could optimize by just checking a few fields like thisUpdate */
3027 if (SECEqual ==
3028 SECITEM_CompareItemSECITEM_CompareItem_Util(b->crl->derCrl, a->crl->derCrl)) {
3029 *isDupe = PR_TRUE1;
3030 } else {
3031 *isUpdated = PR_TRUE1;
3032 }
3033 }
3034 return SECSuccess;
3035 }
3036 if (CRL_OriginExplicit == b->origin) {
3037 /* We need to make sure this is the same object that the user provided
3038 to CERT_CacheCRL previously. That API takes a SECItem*, thus, we
3039 just do a pointer comparison here.
3040 */
3041 if (b->crl->derCrl == a->crl->derCrl) {
3042 *isDupe = PR_TRUE1;
3043 }
3044 }
3045 return SECSuccess;
3046}