Bug Summary

File:s/lib/pki/pkibase.c
Warning:line 769, column 9
Value stored to 'status' is never read

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 pkibase.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/pki -ffunction-sections -fdata-sections -fcoverage-compilation-dir=/var/lib/jenkins/workspace/nss-scan-build/nss/lib/pki -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 -I ../../../dist/public/nspr -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 pkibase.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#ifndef DEV_H
6#include "dev.h"
7#endif /* DEV_H */
8
9#ifndef PKIM_H
10#include "pkim.h"
11#endif /* PKIM_H */
12
13#include "pki3hack.h"
14
15extern const NSSError NSS_ERROR_NOT_FOUND;
16
17NSS_IMPLEMENT void
18nssPKIObject_Lock(nssPKIObject *object)
19{
20 switch (object->lockType) {
21 case nssPKIMonitor:
22 PZ_EnterMonitor(object->sync.mlock)PR_EnterMonitor((object->sync.mlock));
23 break;
24 case nssPKILock:
25 PZ_Lock(object->sync.lock)PR_Lock((object->sync.lock));
26 break;
27 default:
28 PORT_Assert(0)((0)?((void)0):PR_Assert("0","pkibase.c",28));
29 }
30}
31
32NSS_IMPLEMENT void
33nssPKIObject_Unlock(nssPKIObject *object)
34{
35 switch (object->lockType) {
36 case nssPKIMonitor:
37 PZ_ExitMonitor(object->sync.mlock)PR_ExitMonitor((object->sync.mlock));
38 break;
39 case nssPKILock:
40 PZ_Unlock(object->sync.lock)PR_Unlock((object->sync.lock));
41 break;
42 default:
43 PORT_Assert(0)((0)?((void)0):PR_Assert("0","pkibase.c",43));
44 }
45}
46
47NSS_IMPLEMENT PRStatus
48nssPKIObject_NewLock(nssPKIObject *object, nssPKILockType lockType)
49{
50 object->lockType = lockType;
51 switch (lockType) {
52 case nssPKIMonitor:
53 object->sync.mlock = PZ_NewMonitor(nssILockSSL)PR_NewMonitor();
54 return (object->sync.mlock ? PR_SUCCESS : PR_FAILURE);
55 case nssPKILock:
56 object->sync.lock = PZ_NewLock(nssILockSSL)PR_NewLock();
57 return (object->sync.lock ? PR_SUCCESS : PR_FAILURE);
58 default:
59 PORT_Assert(0)((0)?((void)0):PR_Assert("0","pkibase.c",59));
60 return PR_FAILURE;
61 }
62}
63
64NSS_IMPLEMENT void
65nssPKIObject_DestroyLock(nssPKIObject *object)
66{
67 switch (object->lockType) {
68 case nssPKIMonitor:
69 PZ_DestroyMonitor(object->sync.mlock)PR_DestroyMonitor((object->sync.mlock));
70 object->sync.mlock = NULL((void*)0);
71 break;
72 case nssPKILock:
73 PZ_DestroyLock(object->sync.lock)PR_DestroyLock((object->sync.lock));
74 object->sync.lock = NULL((void*)0);
75 break;
76 default:
77 PORT_Assert(0)((0)?((void)0):PR_Assert("0","pkibase.c",77));
78 }
79}
80
81NSS_IMPLEMENT nssPKIObject *
82nssPKIObject_Create(
83 NSSArena *arenaOpt,
84 nssCryptokiObject *instanceOpt,
85 NSSTrustDomain *td,
86 NSSCryptoContext *cc,
87 nssPKILockType lockType)
88{
89 NSSArena *arena;
90 nssArenaMark *mark = NULL((void*)0);
91 nssPKIObject *object;
92 if (arenaOpt) {
93 arena = arenaOpt;
94 mark = nssArena_Mark(arena);
95 } else {
96 arena = nssArena_Create();
97 if (!arena) {
98 return (nssPKIObject *)NULL((void*)0);
99 }
100 }
101 object = nss_ZNEW(arena, nssPKIObject)((nssPKIObject *)nss_ZAlloc((arena), sizeof(nssPKIObject)));
102 if (!object) {
103 goto loser;
104 }
105 object->arena = arena;
106 object->trustDomain = td; /* XXX */
107 object->cryptoContext = cc;
108 if (PR_SUCCESS != nssPKIObject_NewLock(object, lockType)) {
109 goto loser;
110 }
111 if (instanceOpt) {
112 if (nssPKIObject_AddInstance(object, instanceOpt) != PR_SUCCESS) {
113 goto loser;
114 }
115 }
116 PR_ATOMIC_INCREMENT(&object->refCount)__sync_add_and_fetch(&object->refCount, 1);
117 if (mark) {
118 nssArena_Unmark(arena, mark);
119 }
120 return object;
121loser:
122 if (mark) {
123 nssArena_Release(arena, mark);
124 } else {
125 nssArena_Destroy(arena);
126 }
127 return (nssPKIObject *)NULL((void*)0);
128}
129
130NSS_IMPLEMENT PRBool
131nssPKIObject_Destroy(
132 nssPKIObject *object)
133{
134 PRUint32 i;
135 PR_ASSERT(object->refCount > 0)((object->refCount > 0)?((void)0):PR_Assert("object->refCount > 0"
,"pkibase.c",135))
;
136 if (PR_ATOMIC_DECREMENT(&object->refCount)__sync_sub_and_fetch(&object->refCount, 1) == 0) {
137 for (i = 0; i < object->numInstances; i++) {
138 nssCryptokiObject_Destroy(object->instances[i]);
139 }
140 nssPKIObject_DestroyLock(object);
141 nssArena_Destroy(object->arena);
142 return PR_TRUE1;
143 }
144 return PR_FALSE0;
145}
146
147NSS_IMPLEMENT nssPKIObject *
148nssPKIObject_AddRef(
149 nssPKIObject *object)
150{
151 PR_ATOMIC_INCREMENT(&object->refCount)__sync_add_and_fetch(&object->refCount, 1);
152 return object;
153}
154
155NSS_IMPLEMENT PRStatus
156nssPKIObject_AddInstance(
157 nssPKIObject *object,
158 nssCryptokiObject *instance)
159{
160 nssCryptokiObject **newInstances = NULL((void*)0);
161
162 nssPKIObject_Lock(object);
163 if (object->numInstances == 0) {
164 newInstances = nss_ZNEWARRAY(object->arena,((nssCryptokiObject * *)nss_ZAlloc((object->arena), sizeof
(nssCryptokiObject *) * (object->numInstances + 1)))
165 nssCryptokiObject *,((nssCryptokiObject * *)nss_ZAlloc((object->arena), sizeof
(nssCryptokiObject *) * (object->numInstances + 1)))
166 object->numInstances + 1)((nssCryptokiObject * *)nss_ZAlloc((object->arena), sizeof
(nssCryptokiObject *) * (object->numInstances + 1)))
;
167 } else {
168 PRBool found = PR_FALSE0;
169 PRUint32 i;
170 for (i = 0; i < object->numInstances; i++) {
171 if (nssCryptokiObject_Equal(object->instances[i], instance)) {
172 found = PR_TRUE1;
173 break;
174 }
175 }
176 if (found) {
177 /* The new instance is identical to one in the array, except
178 * perhaps that the label may be different. So replace
179 * the label in the array instance with the label from the
180 * new instance, and discard the new instance.
181 */
182 nss_ZFreeIf(object->instances[i]->label);
183 object->instances[i]->label = instance->label;
184 nssPKIObject_Unlock(object);
185 instance->label = NULL((void*)0);
186 nssCryptokiObject_Destroy(instance);
187 return PR_SUCCESS;
188 }
189 newInstances = nss_ZREALLOCARRAY(object->instances,((nssCryptokiObject * *)nss_ZRealloc((object->instances), sizeof
(nssCryptokiObject *) * (object->numInstances + 1)))
190 nssCryptokiObject *,((nssCryptokiObject * *)nss_ZRealloc((object->instances), sizeof
(nssCryptokiObject *) * (object->numInstances + 1)))
191 object->numInstances + 1)((nssCryptokiObject * *)nss_ZRealloc((object->instances), sizeof
(nssCryptokiObject *) * (object->numInstances + 1)))
;
192 }
193 if (newInstances) {
194 object->instances = newInstances;
195 newInstances[object->numInstances++] = instance;
196 }
197 nssPKIObject_Unlock(object);
198 return (newInstances ? PR_SUCCESS : PR_FAILURE);
199}
200
201NSS_IMPLEMENT PRBool
202nssPKIObject_HasInstance(
203 nssPKIObject *object,
204 nssCryptokiObject *instance)
205{
206 PRUint32 i;
207 PRBool hasIt = PR_FALSE0;
208 ;
209 nssPKIObject_Lock(object);
210 for (i = 0; i < object->numInstances; i++) {
211 if (nssCryptokiObject_Equal(object->instances[i], instance)) {
212 hasIt = PR_TRUE1;
213 break;
214 }
215 }
216 nssPKIObject_Unlock(object);
217 return hasIt;
218}
219
220NSS_IMPLEMENT PRStatus
221nssPKIObject_RemoveInstanceForToken(
222 nssPKIObject *object,
223 NSSToken *token)
224{
225 PRUint32 i;
226 nssCryptokiObject *instanceToRemove = NULL((void*)0);
227 nssPKIObject_Lock(object);
228 if (object->numInstances == 0) {
229 nssPKIObject_Unlock(object);
230 return PR_SUCCESS;
231 }
232 for (i = 0; i < object->numInstances; i++) {
233 if (object->instances[i]->token == token) {
234 instanceToRemove = object->instances[i];
235 object->instances[i] = object->instances[object->numInstances - 1];
236 object->instances[object->numInstances - 1] = NULL((void*)0);
237 break;
238 }
239 }
240 if (--object->numInstances > 0) {
241 nssCryptokiObject **instances = nss_ZREALLOCARRAY(object->instances,((nssCryptokiObject * *)nss_ZRealloc((object->instances), sizeof
(nssCryptokiObject *) * (object->numInstances)))
242 nssCryptokiObject *,((nssCryptokiObject * *)nss_ZRealloc((object->instances), sizeof
(nssCryptokiObject *) * (object->numInstances)))
243 object->numInstances)((nssCryptokiObject * *)nss_ZRealloc((object->instances), sizeof
(nssCryptokiObject *) * (object->numInstances)))
;
244 if (instances) {
245 object->instances = instances;
246 }
247 } else {
248 nss_ZFreeIf(object->instances);
249 }
250 nssCryptokiObject_Destroy(instanceToRemove);
251 nssPKIObject_Unlock(object);
252 return PR_SUCCESS;
253}
254
255/* this needs more thought on what will happen when there are multiple
256 * instances
257 */
258NSS_IMPLEMENT PRStatus
259nssPKIObject_DeleteStoredObject(
260 nssPKIObject *object,
261 NSSCallback *uhh,
262 PRBool isFriendly)
263{
264 PRUint32 i, numNotDestroyed;
265 PRStatus status = PR_SUCCESS;
266 numNotDestroyed = 0;
267 nssPKIObject_Lock(object);
268 for (i = 0; i < object->numInstances; i++) {
269 nssCryptokiObject *instance = object->instances[i];
270 status = nssToken_DeleteStoredObject(instance);
271 object->instances[i] = NULL((void*)0);
272 if (status == PR_SUCCESS) {
273 nssCryptokiObject_Destroy(instance);
274 } else {
275 object->instances[numNotDestroyed++] = instance;
276 }
277 }
278 if (numNotDestroyed == 0) {
279 nss_ZFreeIf(object->instances);
280 object->numInstances = 0;
281 } else {
282 object->numInstances = numNotDestroyed;
283 }
284 nssPKIObject_Unlock(object);
285 return status;
286}
287
288NSS_IMPLEMENT NSSToken **
289nssPKIObject_GetTokens(
290 nssPKIObject *object,
291 PRStatus *statusOpt)
292{
293 NSSToken **tokens = NULL((void*)0);
294 nssPKIObject_Lock(object);
295 if (object->numInstances > 0) {
296 tokens = nss_ZNEWARRAY(NULL, NSSToken *, object->numInstances + 1)((NSSToken * *)nss_ZAlloc((((void*)0)), sizeof(NSSToken *) * (
object->numInstances + 1)))
;
297 if (tokens) {
298 PRUint32 i;
299 for (i = 0; i < object->numInstances; i++) {
300 tokens[i] = nssToken_AddRef(object->instances[i]->token);
301 }
302 }
303 }
304 nssPKIObject_Unlock(object);
305 if (statusOpt)
306 *statusOpt = PR_SUCCESS; /* until more logic here */
307 return tokens;
308}
309
310NSS_IMPLEMENT NSSUTF8 *
311nssPKIObject_GetNicknameForToken(
312 nssPKIObject *object,
313 NSSToken *tokenOpt)
314{
315 PRUint32 i;
316 NSSUTF8 *nickname = NULL((void*)0);
317 nssPKIObject_Lock(object);
318 for (i = 0; i < object->numInstances; i++) {
319 if ((!tokenOpt && object->instances[i]->label) ||
320 (object->instances[i]->token == tokenOpt)) {
321 /* Must copy, see bug 745548 */
322 nickname = nssUTF8_Duplicate(object->instances[i]->label, NULL((void*)0));
323 break;
324 }
325 }
326 nssPKIObject_Unlock(object);
327 return nickname;
328}
329
330NSS_IMPLEMENT nssCryptokiObject **
331nssPKIObject_GetInstances(
332 nssPKIObject *object)
333{
334 nssCryptokiObject **instances = NULL((void*)0);
335 PRUint32 i;
336 if (object->numInstances == 0) {
337 return (nssCryptokiObject **)NULL((void*)0);
338 }
339 nssPKIObject_Lock(object);
340 instances = nss_ZNEWARRAY(NULL, nssCryptokiObject *,((nssCryptokiObject * *)nss_ZAlloc((((void*)0)), sizeof(nssCryptokiObject
*) * (object->numInstances + 1)))
341 object->numInstances + 1)((nssCryptokiObject * *)nss_ZAlloc((((void*)0)), sizeof(nssCryptokiObject
*) * (object->numInstances + 1)))
;
342 if (instances) {
343 for (i = 0; i < object->numInstances; i++) {
344 instances[i] = nssCryptokiObject_Clone(object->instances[i]);
345 }
346 }
347 nssPKIObject_Unlock(object);
348 return instances;
349}
350
351NSS_IMPLEMENT void
352nssCertificateArray_Destroy(
353 NSSCertificate **certs)
354{
355 if (certs) {
356 NSSCertificate **certp;
357 for (certp = certs; *certp; certp++) {
358 if ((*certp)->decoding) {
359 CERTCertificate *cc = STAN_GetCERTCertificate(*certp);
360 if (cc) {
361 CERT_DestroyCertificate(cc);
362 }
363 continue;
364 }
365 nssCertificate_Destroy(*certp);
366 }
367 nss_ZFreeIf(certs);
368 }
369}
370
371NSS_IMPLEMENT void
372NSSCertificateArray_Destroy(
373 NSSCertificate **certs)
374{
375 nssCertificateArray_Destroy(certs);
376}
377
378NSS_IMPLEMENT NSSCertificate **
379nssCertificateArray_Join(
380 NSSCertificate **certs1,
381 NSSCertificate **certs2)
382{
383 if (certs1 && certs2) {
384 NSSCertificate **certs, **cp;
385 PRUint32 count = 0;
386 PRUint32 count1 = 0;
387 cp = certs1;
388 while (*cp++)
389 count1++;
390 count = count1;
391 cp = certs2;
392 while (*cp++)
393 count++;
394 certs = nss_ZREALLOCARRAY(certs1, NSSCertificate *, count + 1)((NSSCertificate * *)nss_ZRealloc((certs1), sizeof(NSSCertificate
*) * (count + 1)))
;
395 if (!certs) {
396 nss_ZFreeIf(certs1);
397 nss_ZFreeIf(certs2);
398 return (NSSCertificate **)NULL((void*)0);
399 }
400 for (cp = certs2; *cp; cp++, count1++) {
401 certs[count1] = *cp;
402 }
403 nss_ZFreeIf(certs2);
404 return certs;
405 } else if (certs1) {
406 return certs1;
407 } else {
408 return certs2;
409 }
410}
411
412NSS_IMPLEMENT NSSCertificate *
413nssCertificateArray_FindBestCertificate(
414 NSSCertificate **certs,
415 NSSTime *timeOpt,
416 const NSSUsage *usage,
417 NSSPolicies *policiesOpt)
418{
419 NSSCertificate *bestCert = NULL((void*)0);
420 nssDecodedCert *bestdc = NULL((void*)0);
421 NSSTime *time, sTime;
422 PRBool bestCertMatches = PR_FALSE0;
423 PRBool thisCertMatches;
424 PRBool bestCertIsValidAtTime = PR_FALSE0;
425 PRBool bestCertIsTrusted = PR_FALSE0;
426
427 if (timeOpt) {
428 time = timeOpt;
429 } else {
430 NSSTime_Now(&sTime);
431 time = &sTime;
432 }
433 if (!certs) {
434 return (NSSCertificate *)NULL((void*)0);
435 }
436 for (; *certs; certs++) {
437 nssDecodedCert *dc;
438 NSSCertificate *c = *certs;
439 dc = nssCertificate_GetDecoding(c);
440 if (!dc)
441 continue;
442 thisCertMatches = dc->matchUsage(dc, usage);
443 if (!bestCert) {
444 /* always take the first cert, but remember whether or not
445 * the usage matched
446 */
447 bestCert = nssCertificate_AddRef(c);
448 bestCertMatches = thisCertMatches;
449 bestdc = dc;
450 continue;
451 } else {
452 if (bestCertMatches && !thisCertMatches) {
453 /* if already have a cert for this usage, and if this cert
454 * doesn't have the correct usage, continue
455 */
456 continue;
457 } else if (!bestCertMatches && thisCertMatches) {
458 /* this one does match usage, replace the other */
459 nssCertificate_Destroy(bestCert);
460 bestCert = nssCertificate_AddRef(c);
461 bestCertMatches = thisCertMatches;
462 bestdc = dc;
463 continue;
464 }
465 /* this cert match as well as any cert we've found so far,
466 * defer to time/policies
467 * */
468 }
469 /* time */
470 if (bestCertIsValidAtTime || bestdc->isValidAtTime(bestdc, time)) {
471 /* The current best cert is valid at time */
472 bestCertIsValidAtTime = PR_TRUE1;
473 if (!dc->isValidAtTime(dc, time)) {
474 /* If the new cert isn't valid at time, it's not better */
475 continue;
476 }
477 } else {
478 /* The current best cert is not valid at time */
479 if (dc->isValidAtTime(dc, time)) {
480 /* If the new cert is valid at time, it's better */
481 nssCertificate_Destroy(bestCert);
482 bestCert = nssCertificate_AddRef(c);
483 bestdc = dc;
484 bestCertIsValidAtTime = PR_TRUE1;
485 continue;
486 }
487 }
488 /* Either they are both valid at time, or neither valid.
489 * If only one is trusted for this usage, take it.
490 */
491 if (bestCertIsTrusted || bestdc->isTrustedForUsage(bestdc, usage)) {
492 bestCertIsTrusted = PR_TRUE1;
493 if (!dc->isTrustedForUsage(dc, usage)) {
494 continue;
495 }
496 } else {
497 /* The current best cert is not trusted */
498 if (dc->isTrustedForUsage(dc, usage)) {
499 /* If the new cert is trusted, it's better */
500 nssCertificate_Destroy(bestCert);
501 bestCert = nssCertificate_AddRef(c);
502 bestdc = dc;
503 bestCertIsTrusted = PR_TRUE1;
504 continue;
505 }
506 }
507 /* Otherwise, take the newer one. */
508 if (!bestdc->isNewerThan(bestdc, dc)) {
509 nssCertificate_Destroy(bestCert);
510 bestCert = nssCertificate_AddRef(c);
511 bestdc = dc;
512 continue;
513 }
514 /* policies */
515 /* XXX later -- defer to policies */
516 }
517 return bestCert;
518}
519
520NSS_IMPLEMENT PRStatus
521nssCertificateArray_Traverse(
522 NSSCertificate **certs,
523 PRStatus (*callback)(NSSCertificate *c, void *arg),
524 void *arg)
525{
526 PRStatus status = PR_SUCCESS;
527 if (certs) {
528 NSSCertificate **certp;
529 for (certp = certs; *certp; certp++) {
530 status = (*callback)(*certp, arg);
531 if (status != PR_SUCCESS) {
532 break;
533 }
534 }
535 }
536 return status;
537}
538
539NSS_IMPLEMENT void
540nssCRLArray_Destroy(
541 NSSCRL **crls)
542{
543 if (crls) {
544 NSSCRL **crlp;
545 for (crlp = crls; *crlp; crlp++) {
546 nssCRL_Destroy(*crlp);
547 }
548 nss_ZFreeIf(crls);
549 }
550}
551
552/*
553 * Object collections
554 */
555
556typedef enum {
557 pkiObjectType_Certificate = 0,
558 pkiObjectType_CRL = 1,
559 pkiObjectType_PrivateKey = 2,
560 pkiObjectType_PublicKey = 3
561} pkiObjectType;
562
563/* Each object is defined by a set of items that uniquely identify it.
564 * Here are the uid sets:
565 *
566 * NSSCertificate ==> { issuer, serial }
567 * NSSPrivateKey
568 * (RSA) ==> { modulus, public exponent }
569 *
570 */
571#define MAX_ITEMS_FOR_UID2 2
572
573/* pkiObjectCollectionNode
574 *
575 * A node in the collection is the set of unique identifiers for a single
576 * object, along with either the actual object or a proto-object.
577 */
578typedef struct
579{
580 PRCList link;
581 PRBool haveObject;
582 nssPKIObject *object;
583 NSSItem uid[MAX_ITEMS_FOR_UID2];
584} pkiObjectCollectionNode;
585
586/* nssPKIObjectCollection
587 *
588 * The collection is the set of all objects, plus the interfaces needed
589 * to manage the objects.
590 *
591 */
592struct nssPKIObjectCollectionStr {
593 NSSArena *arena;
594 NSSTrustDomain *td;
595 NSSCryptoContext *cc;
596 PRCList head; /* list of pkiObjectCollectionNode's */
597 PRUint32 size;
598 pkiObjectType objectType;
599 void (*destroyObject)(nssPKIObject *o);
600 PRStatus (*getUIDFromObject)(nssPKIObject *o, NSSItem *uid);
601 PRStatus (*getUIDFromInstance)(nssCryptokiObject *co, NSSItem *uid,
602 NSSArena *arena);
603 nssPKIObject *(*createObject)(nssPKIObject *o);
604 nssPKILockType lockType; /* type of lock to use for new proto-objects */
605};
606
607static nssPKIObjectCollection *
608nssPKIObjectCollection_Create(
609 NSSTrustDomain *td,
610 NSSCryptoContext *ccOpt,
611 nssPKILockType lockType)
612{
613 NSSArena *arena;
614 nssPKIObjectCollection *rvCollection = NULL((void*)0);
615 arena = nssArena_Create();
616 if (!arena) {
617 return (nssPKIObjectCollection *)NULL((void*)0);
618 }
619 rvCollection = nss_ZNEW(arena, nssPKIObjectCollection)((nssPKIObjectCollection *)nss_ZAlloc((arena), sizeof(nssPKIObjectCollection
)))
;
620 if (!rvCollection) {
621 goto loser;
622 }
623 PR_INIT_CLIST(&rvCollection->head)do { (&rvCollection->head)->next = (&rvCollection
->head); (&rvCollection->head)->prev = (&rvCollection
->head); } while (0)
;
624 rvCollection->arena = arena;
625 rvCollection->td = td; /* XXX */
626 rvCollection->cc = ccOpt;
627 rvCollection->lockType = lockType;
628 return rvCollection;
629loser:
630 nssArena_Destroy(arena);
631 return (nssPKIObjectCollection *)NULL((void*)0);
632}
633
634NSS_IMPLEMENT void
635nssPKIObjectCollection_Destroy(
636 nssPKIObjectCollection *collection)
637{
638 if (collection) {
639 PRCList *link;
640 pkiObjectCollectionNode *node;
641 /* first destroy any objects in the collection */
642 link = PR_NEXT_LINK(&collection->head)((&collection->head)->next);
643 while (link != &collection->head) {
644 node = (pkiObjectCollectionNode *)link;
645 if (node->haveObject) {
646 (*collection->destroyObject)(node->object);
647 } else {
648 nssPKIObject_Destroy(node->object);
649 }
650 link = PR_NEXT_LINK(link)((link)->next);
651 }
652 /* then destroy it */
653 nssArena_Destroy(collection->arena);
654 }
655}
656
657NSS_IMPLEMENT PRUint32
658nssPKIObjectCollection_Count(
659 nssPKIObjectCollection *collection)
660{
661 return collection->size;
662}
663
664NSS_IMPLEMENT PRStatus
665nssPKIObjectCollection_AddObject(
666 nssPKIObjectCollection *collection,
667 nssPKIObject *object)
668{
669 pkiObjectCollectionNode *node;
670 node = nss_ZNEW(collection->arena, pkiObjectCollectionNode)((pkiObjectCollectionNode *)nss_ZAlloc((collection->arena)
, sizeof(pkiObjectCollectionNode)))
;
671 if (!node) {
672 return PR_FAILURE;
673 }
674 node->haveObject = PR_TRUE1;
675 node->object = nssPKIObject_AddRef(object);
676 (*collection->getUIDFromObject)(object, node->uid);
677 PR_INIT_CLIST(&node->link)do { (&node->link)->next = (&node->link); (&
node->link)->prev = (&node->link); } while (0)
;
678 PR_INSERT_BEFORE(&node->link, &collection->head)do { (&node->link)->next = (&collection->head
); (&node->link)->prev = (&collection->head)
->prev; (&collection->head)->prev->next = (&
node->link); (&collection->head)->prev = (&node
->link); } while (0)
;
679 collection->size++;
680 return PR_SUCCESS;
681}
682
683static pkiObjectCollectionNode *
684find_instance_in_collection(
685 nssPKIObjectCollection *collection,
686 nssCryptokiObject *instance)
687{
688 PRCList *link;
689 pkiObjectCollectionNode *node;
690 link = PR_NEXT_LINK(&collection->head)((&collection->head)->next);
691 while (link != &collection->head) {
692 node = (pkiObjectCollectionNode *)link;
693 if (nssPKIObject_HasInstance(node->object, instance)) {
694 return node;
695 }
696 link = PR_NEXT_LINK(link)((link)->next);
697 }
698 return (pkiObjectCollectionNode *)NULL((void*)0);
699}
700
701static pkiObjectCollectionNode *
702find_object_in_collection(
703 nssPKIObjectCollection *collection,
704 NSSItem *uid)
705{
706 PRUint32 i;
707 PRStatus status;
708 PRCList *link;
709 pkiObjectCollectionNode *node;
710 link = PR_NEXT_LINK(&collection->head)((&collection->head)->next);
711 while (link != &collection->head) {
712 node = (pkiObjectCollectionNode *)link;
713 for (i = 0; i < MAX_ITEMS_FOR_UID2; i++) {
714 if (!nssItem_Equal(&node->uid[i], &uid[i], &status)) {
715 break;
716 }
717 }
718 if (i == MAX_ITEMS_FOR_UID2) {
719 return node;
720 }
721 link = PR_NEXT_LINK(link)((link)->next);
722 }
723 return (pkiObjectCollectionNode *)NULL((void*)0);
724}
725
726static pkiObjectCollectionNode *
727add_object_instance(
728 nssPKIObjectCollection *collection,
729 nssCryptokiObject *instance,
730 PRBool *foundIt)
731{
732 PRUint32 i;
733 PRStatus status;
734 pkiObjectCollectionNode *node;
735 nssArenaMark *mark = NULL((void*)0);
736 NSSItem uid[MAX_ITEMS_FOR_UID2];
737 nsslibc_memset(uid, 0, sizeof uid);
738 /* The list is traversed twice, first (here) looking to match the
739 * { token, handle } tuple, and if that is not found, below a search
740 * for unique identifier is done. Here, a match means this exact object
741 * instance is already in the collection, and we have nothing to do.
742 */
743 *foundIt = PR_FALSE0;
744 node = find_instance_in_collection(collection, instance);
745 if (node) {
746 /* The collection is assumed to take over the instance. Since we
747 * are not using it, it must be destroyed.
748 */
749 nssCryptokiObject_Destroy(instance);
750 *foundIt = PR_TRUE1;
751 return node;
752 }
753 mark = nssArena_Mark(collection->arena);
754 if (!mark) {
755 goto loser;
756 }
757 status = (*collection->getUIDFromInstance)(instance, uid,
758 collection->arena);
759 if (status != PR_SUCCESS) {
760 goto loser;
761 }
762 /* Search for unique identifier. A match here means the object exists
763 * in the collection, but does not have this instance, so the instance
764 * needs to be added.
765 */
766 node = find_object_in_collection(collection, uid);
767 if (node) {
768 /* This is an object with multiple instances */
769 status = nssPKIObject_AddInstance(node->object, instance);
Value stored to 'status' is never read
770 } else {
771 /* This is a completely new object. Create a node for it. */
772 node = nss_ZNEW(collection->arena, pkiObjectCollectionNode)((pkiObjectCollectionNode *)nss_ZAlloc((collection->arena)
, sizeof(pkiObjectCollectionNode)))
;
773 if (!node) {
774 goto loser;
775 }
776 node->object = nssPKIObject_Create(NULL((void*)0), instance,
777 collection->td, collection->cc,
778 collection->lockType);
779 if (!node->object) {
780 goto loser;
781 }
782 for (i = 0; i < MAX_ITEMS_FOR_UID2; i++) {
783 node->uid[i] = uid[i];
784 }
785 node->haveObject = PR_FALSE0;
786 PR_INIT_CLIST(&node->link)do { (&node->link)->next = (&node->link); (&
node->link)->prev = (&node->link); } while (0)
;
787 PR_INSERT_BEFORE(&node->link, &collection->head)do { (&node->link)->next = (&collection->head
); (&node->link)->prev = (&collection->head)
->prev; (&collection->head)->prev->next = (&
node->link); (&collection->head)->prev = (&node
->link); } while (0)
;
788 collection->size++;
789 status = PR_SUCCESS;
790 }
791 nssArena_Unmark(collection->arena, mark);
792 return node;
793loser:
794 if (mark) {
795 nssArena_Release(collection->arena, mark);
796 }
797 nssCryptokiObject_Destroy(instance);
798 return (pkiObjectCollectionNode *)NULL((void*)0);
799}
800
801NSS_IMPLEMENT PRStatus
802nssPKIObjectCollection_AddInstances(
803 nssPKIObjectCollection *collection,
804 nssCryptokiObject **instances,
805 PRUint32 numInstances)
806{
807 PRStatus status = PR_SUCCESS;
808 PRUint32 i = 0;
809 PRBool foundIt;
810 pkiObjectCollectionNode *node;
811 if (instances) {
812 while ((!numInstances || i < numInstances) && *instances) {
813 if (status == PR_SUCCESS) {
814 node = add_object_instance(collection, *instances, &foundIt);
815 if (node == NULL((void*)0)) {
816 /* add_object_instance freed the current instance */
817 /* free the remaining instances */
818 status = PR_FAILURE;
819 }
820 } else {
821 nssCryptokiObject_Destroy(*instances);
822 }
823 instances++;
824 i++;
825 }
826 }
827 return status;
828}
829
830static void
831nssPKIObjectCollection_RemoveNode(
832 nssPKIObjectCollection *collection,
833 pkiObjectCollectionNode *node)
834{
835 PR_REMOVE_LINK(&node->link)do { (&node->link)->prev->next = (&node->
link)->next; (&node->link)->next->prev = (&
node->link)->prev; } while (0)
;
836 collection->size--;
837}
838
839static PRStatus
840nssPKIObjectCollection_GetObjects(
841 nssPKIObjectCollection *collection,
842 nssPKIObject **rvObjects,
843 PRUint32 rvSize)
844{
845 PRUint32 i = 0;
846 PRCList *link = PR_NEXT_LINK(&collection->head)((&collection->head)->next);
847 pkiObjectCollectionNode *node;
848 int error = 0;
849 while ((i < rvSize) && (link != &collection->head)) {
850 node = (pkiObjectCollectionNode *)link;
851 if (!node->haveObject) {
852 /* Convert the proto-object to an object */
853 node->object = (*collection->createObject)(node->object);
854 if (!node->object) {
855 link = PR_NEXT_LINK(link)((link)->next);
856 /*remove bogus object from list*/
857 nssPKIObjectCollection_RemoveNode(collection, node);
858 error++;
859 continue;
860 }
861 node->haveObject = PR_TRUE1;
862 }
863 rvObjects[i++] = nssPKIObject_AddRef(node->object);
864 link = PR_NEXT_LINK(link)((link)->next);
865 }
866 if (!error && *rvObjects == NULL((void*)0)) {
867 nss_SetError(NSS_ERROR_NOT_FOUND);
868 }
869 return PR_SUCCESS;
870}
871
872NSS_IMPLEMENT PRStatus
873nssPKIObjectCollection_Traverse(
874 nssPKIObjectCollection *collection,
875 nssPKIObjectCallback *callback)
876{
877 PRCList *link = PR_NEXT_LINK(&collection->head)((&collection->head)->next);
878 pkiObjectCollectionNode *node;
879 while (link != &collection->head) {
880 node = (pkiObjectCollectionNode *)link;
881 if (!node->haveObject) {
882 node->object = (*collection->createObject)(node->object);
883 if (!node->object) {
884 link = PR_NEXT_LINK(link)((link)->next);
885 /*remove bogus object from list*/
886 nssPKIObjectCollection_RemoveNode(collection, node);
887 continue;
888 }
889 node->haveObject = PR_TRUE1;
890 }
891 switch (collection->objectType) {
892 case pkiObjectType_Certificate:
893 (void)(*callback->func.cert)((NSSCertificate *)node->object,
894 callback->arg);
895 break;
896 case pkiObjectType_CRL:
897 (void)(*callback->func.crl)((NSSCRL *)node->object,
898 callback->arg);
899 break;
900 case pkiObjectType_PrivateKey:
901 (void)(*callback->func.pvkey)((NSSPrivateKey *)node->object,
902 callback->arg);
903 break;
904 case pkiObjectType_PublicKey:
905 (void)(*callback->func.pbkey)((NSSPublicKey *)node->object,
906 callback->arg);
907 break;
908 }
909 link = PR_NEXT_LINK(link)((link)->next);
910 }
911 return PR_SUCCESS;
912}
913
914NSS_IMPLEMENT PRStatus
915nssPKIObjectCollection_AddInstanceAsObject(
916 nssPKIObjectCollection *collection,
917 nssCryptokiObject *instance)
918{
919 pkiObjectCollectionNode *node;
920 PRBool foundIt;
921 node = add_object_instance(collection, instance, &foundIt);
922 if (node == NULL((void*)0)) {
923 return PR_FAILURE;
924 }
925 if (!node->haveObject) {
926 nssPKIObject *original = node->object;
927 node->object = (*collection->createObject)(node->object);
928 if (!node->object) {
929 /*remove bogus object from list*/
930 nssPKIObject_Destroy(original);
931 nssPKIObjectCollection_RemoveNode(collection, node);
932 return PR_FAILURE;
933 }
934 node->haveObject = PR_TRUE1;
935 } else if (!foundIt) {
936 /* The instance was added to a pre-existing node. This
937 * function is *only* being used for certificates, and having
938 * multiple instances of certs in 3.X requires updating the
939 * CERTCertificate.
940 * But only do it if it was a new instance!!! If the same instance
941 * is encountered, we set *foundIt to true. Detect that here and
942 * ignore it.
943 */
944 STAN_ForceCERTCertificateUpdate((NSSCertificate *)node->object);
945 }
946 return PR_SUCCESS;
947}
948
949/*
950 * Certificate collections
951 */
952
953static void
954cert_destroyObject(nssPKIObject *o)
955{
956 NSSCertificate *c = (NSSCertificate *)o;
957 if (c->decoding) {
958 CERTCertificate *cc = STAN_GetCERTCertificate(c);
959 if (cc) {
960 CERT_DestroyCertificate(cc);
961 return;
962 } /* else destroy it as NSSCertificate below */
963 }
964 nssCertificate_Destroy(c);
965}
966
967static PRStatus
968cert_getUIDFromObject(nssPKIObject *o, NSSItem *uid)
969{
970 NSSCertificate *c = (NSSCertificate *)o;
971 /* The builtins are still returning decoded serial numbers. Until
972 * this compatibility issue is resolved, use the full DER of the
973 * cert to uniquely identify it.
974 */
975 NSSDER *derCert;
976 derCert = nssCertificate_GetEncoding(c);
977 uid[0].data = NULL((void*)0);
978 uid[0].size = 0;
979 uid[1].data = NULL((void*)0);
980 uid[1].size = 0;
981 if (derCert != NULL((void*)0)) {
982 uid[0] = *derCert;
983 }
984 return PR_SUCCESS;
985}
986
987static PRStatus
988cert_getUIDFromInstance(nssCryptokiObject *instance, NSSItem *uid,
989 NSSArena *arena)
990{
991 /* The builtins are still returning decoded serial numbers. Until
992 * this compatibility issue is resolved, use the full DER of the
993 * cert to uniquely identify it.
994 */
995 uid[1].data = NULL((void*)0);
996 uid[1].size = 0;
997 return nssCryptokiCertificate_GetAttributes(instance,
998 NULL((void*)0), /* XXX sessionOpt */
999 arena, /* arena */
1000 NULL((void*)0), /* type */
1001 NULL((void*)0), /* id */
1002 &uid[0], /* encoding */
1003 NULL((void*)0), /* issuer */
1004 NULL((void*)0), /* serial */
1005 NULL((void*)0)); /* subject */
1006}
1007
1008static nssPKIObject *
1009cert_createObject(nssPKIObject *o)
1010{
1011 NSSCertificate *cert;
1012 cert = nssCertificate_Create(o);
1013 /* if (STAN_GetCERTCertificate(cert) == NULL) {
1014 nssCertificate_Destroy(cert);
1015 return (nssPKIObject *)NULL;
1016 } */
1017 /* In 3.4, have to maintain uniqueness of cert pointers by caching all
1018 * certs. Cache the cert here, before returning. If it is already
1019 * cached, take the cached entry.
1020 */
1021 {
1022 NSSTrustDomain *td = o->trustDomain;
1023 nssTrustDomain_AddCertsToCache(td, &cert, 1);
1024 }
1025 return (nssPKIObject *)cert;
1026}
1027
1028NSS_IMPLEMENT nssPKIObjectCollection *
1029nssCertificateCollection_Create(
1030 NSSTrustDomain *td,
1031 NSSCertificate **certsOpt)
1032{
1033 nssPKIObjectCollection *collection;
1034 collection = nssPKIObjectCollection_Create(td, NULL((void*)0), nssPKIMonitor);
1035 if (!collection) {
1036 return NULL((void*)0);
1037 }
1038 collection->objectType = pkiObjectType_Certificate;
1039 collection->destroyObject = cert_destroyObject;
1040 collection->getUIDFromObject = cert_getUIDFromObject;
1041 collection->getUIDFromInstance = cert_getUIDFromInstance;
1042 collection->createObject = cert_createObject;
1043 if (certsOpt) {
1044 for (; *certsOpt; certsOpt++) {
1045 nssPKIObject *object = (nssPKIObject *)(*certsOpt);
1046 (void)nssPKIObjectCollection_AddObject(collection, object);
1047 }
1048 }
1049 return collection;
1050}
1051
1052NSS_IMPLEMENT NSSCertificate **
1053nssPKIObjectCollection_GetCertificates(
1054 nssPKIObjectCollection *collection,
1055 NSSCertificate **rvOpt,
1056 PRUint32 maximumOpt,
1057 NSSArena *arenaOpt)
1058{
1059 PRStatus status;
1060 PRUint32 rvSize;
1061 PRBool allocated = PR_FALSE0;
1062 if (collection->size == 0) {
1063 return (NSSCertificate **)NULL((void*)0);
1064 }
1065 if (maximumOpt == 0) {
1066 rvSize = collection->size;
1067 } else {
1068 rvSize = PR_MIN(collection->size, maximumOpt)((collection->size)<(maximumOpt)?(collection->size):
(maximumOpt))
;
1069 }
1070 if (!rvOpt) {
1071 rvOpt = nss_ZNEWARRAY(arenaOpt, NSSCertificate *, rvSize + 1)((NSSCertificate * *)nss_ZAlloc((arenaOpt), sizeof(NSSCertificate
*) * (rvSize + 1)))
;
1072 if (!rvOpt) {
1073 return (NSSCertificate **)NULL((void*)0);
1074 }
1075 allocated = PR_TRUE1;
1076 }
1077 status = nssPKIObjectCollection_GetObjects(collection,
1078 (nssPKIObject **)rvOpt,
1079 rvSize);
1080 if (status != PR_SUCCESS) {
1081 if (allocated) {
1082 nss_ZFreeIf(rvOpt);
1083 }
1084 return (NSSCertificate **)NULL((void*)0);
1085 }
1086 return rvOpt;
1087}
1088
1089/*
1090 * CRL/KRL collections
1091 */
1092
1093static void
1094crl_destroyObject(nssPKIObject *o)
1095{
1096 NSSCRL *crl = (NSSCRL *)o;
1097 nssCRL_Destroy(crl);
1098}
1099
1100static PRStatus
1101crl_getUIDFromObject(nssPKIObject *o, NSSItem *uid)
1102{
1103 NSSCRL *crl = (NSSCRL *)o;
1104 NSSDER *encoding;
1105 encoding = nssCRL_GetEncoding(crl);
1106 if (!encoding) {
1107 nss_SetError(NSS_ERROR_INVALID_ARGUMENT);
1108 return PR_FALSE0;
1109 }
1110 uid[0] = *encoding;
1111 uid[1].data = NULL((void*)0);
1112 uid[1].size = 0;
1113 return PR_SUCCESS;
1114}
1115
1116static PRStatus
1117crl_getUIDFromInstance(nssCryptokiObject *instance, NSSItem *uid,
1118 NSSArena *arena)
1119{
1120 return nssCryptokiCRL_GetAttributes(instance,
1121 NULL((void*)0), /* XXX sessionOpt */
1122 arena, /* arena */
1123 &uid[0], /* encoding */
1124 NULL((void*)0), /* subject */
1125 NULL((void*)0), /* class */
1126 NULL((void*)0), /* url */
1127 NULL((void*)0)); /* isKRL */
1128}
1129
1130static nssPKIObject *
1131crl_createObject(nssPKIObject *o)
1132{
1133 return (nssPKIObject *)nssCRL_Create(o);
1134}
1135
1136NSS_IMPLEMENT nssPKIObjectCollection *
1137nssCRLCollection_Create(
1138 NSSTrustDomain *td,
1139 NSSCRL **crlsOpt)
1140{
1141 nssPKIObjectCollection *collection;
1142 collection = nssPKIObjectCollection_Create(td, NULL((void*)0), nssPKILock);
1143 if (!collection) {
1144 return NULL((void*)0);
1145 }
1146 collection->objectType = pkiObjectType_CRL;
1147 collection->destroyObject = crl_destroyObject;
1148 collection->getUIDFromObject = crl_getUIDFromObject;
1149 collection->getUIDFromInstance = crl_getUIDFromInstance;
1150 collection->createObject = crl_createObject;
1151 if (crlsOpt) {
1152 for (; *crlsOpt; crlsOpt++) {
1153 nssPKIObject *object = (nssPKIObject *)(*crlsOpt);
1154 (void)nssPKIObjectCollection_AddObject(collection, object);
1155 }
1156 }
1157 return collection;
1158}
1159
1160NSS_IMPLEMENT NSSCRL **
1161nssPKIObjectCollection_GetCRLs(
1162 nssPKIObjectCollection *collection,
1163 NSSCRL **rvOpt,
1164 PRUint32 maximumOpt,
1165 NSSArena *arenaOpt)
1166{
1167 PRStatus status;
1168 PRUint32 rvSize;
1169 PRBool allocated = PR_FALSE0;
1170 if (collection->size == 0) {
1171 return (NSSCRL **)NULL((void*)0);
1172 }
1173 if (maximumOpt == 0) {
1174 rvSize = collection->size;
1175 } else {
1176 rvSize = PR_MIN(collection->size, maximumOpt)((collection->size)<(maximumOpt)?(collection->size):
(maximumOpt))
;
1177 }
1178 if (!rvOpt) {
1179 rvOpt = nss_ZNEWARRAY(arenaOpt, NSSCRL *, rvSize + 1)((NSSCRL * *)nss_ZAlloc((arenaOpt), sizeof(NSSCRL *) * (rvSize
+ 1)))
;
1180 if (!rvOpt) {
1181 return (NSSCRL **)NULL((void*)0);
1182 }
1183 allocated = PR_TRUE1;
1184 }
1185 status = nssPKIObjectCollection_GetObjects(collection,
1186 (nssPKIObject **)rvOpt,
1187 rvSize);
1188 if (status != PR_SUCCESS) {
1189 if (allocated) {
1190 nss_ZFreeIf(rvOpt);
1191 }
1192 return (NSSCRL **)NULL((void*)0);
1193 }
1194 return rvOpt;
1195}
1196
1197/* how bad would it be to have a static now sitting around, updated whenever
1198 * this was called? would avoid repeated allocs...
1199 */
1200NSS_IMPLEMENT NSSTime *
1201NSSTime_Now(NSSTime *timeOpt)
1202{
1203 return NSSTime_SetPRTime(timeOpt, PR_Now());
1204}
1205
1206NSS_IMPLEMENT NSSTime *
1207NSSTime_SetPRTime(
1208 NSSTime *timeOpt,
1209 PRTime prTime)
1210{
1211 NSSTime *rvTime;
1212 rvTime = (timeOpt) ? timeOpt : nss_ZNEW(NULL, NSSTime)((NSSTime *)nss_ZAlloc((((void*)0)), sizeof(NSSTime)));
1213 if (rvTime) {
1214 rvTime->prTime = prTime;
1215 }
1216 return rvTime;
1217}
1218
1219NSS_IMPLEMENT PRTime
1220NSSTime_GetPRTime(
1221 NSSTime *time)
1222{
1223 return time->prTime;
1224}