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  * sessobj.c
7  *
8  * This file contains an NSSCKMDObject implementation for session
9  * objects.  The framework uses this implementation to manage
10  * session objects when a Module doesn't wish to be bothered.
11  */
12 
13 #ifndef CK_T
14 #include "ck.h"
15 #endif /* CK_T */
16 
17 /*
18  * nssCKMDSessionObject
19  *
20  *  -- create --
21  *  nssCKMDSessionObject_Create
22  *
23  *  -- EPV calls --
24  *  nss_ckmdSessionObject_Finalize
25  *  nss_ckmdSessionObject_IsTokenObject
26  *  nss_ckmdSessionObject_GetAttributeCount
27  *  nss_ckmdSessionObject_GetAttributeTypes
28  *  nss_ckmdSessionObject_GetAttributeSize
29  *  nss_ckmdSessionObject_GetAttribute
30  *  nss_ckmdSessionObject_SetAttribute
31  *  nss_ckmdSessionObject_GetObjectSize
32  */
33 
34 struct nssCKMDSessionObjectStr {
35     CK_ULONG n;
36     NSSArena *arena;
37     NSSItem *attributes;
38     CK_ATTRIBUTE_TYPE_PTR types;
39     nssCKFWHash *hash;
40 };
41 typedef struct nssCKMDSessionObjectStr nssCKMDSessionObject;
42 
43 #ifdef DEBUG
44 /*
45  * But first, the pointer-tracking stuff.
46  *
47  * NOTE: the pointer-tracking support in NSS/base currently relies
48  * upon NSPR's CallOnce support.  That, however, relies upon NSPR's
49  * locking, which is tied into the runtime.  We need a pointer-tracker
50  * implementation that uses the locks supplied through C_Initialize.
51  * That support, however, can be filled in later.  So for now, I'll
52  * just do this routines as no-ops.
53  */
54 
55 static CK_RV
nss_ckmdSessionObject_add_pointer(const NSSCKMDObject * mdObject)56 nss_ckmdSessionObject_add_pointer(
57     const NSSCKMDObject *mdObject)
58 {
59     return CKR_OK;
60 }
61 
62 static CK_RV
nss_ckmdSessionObject_remove_pointer(const NSSCKMDObject * mdObject)63 nss_ckmdSessionObject_remove_pointer(
64     const NSSCKMDObject *mdObject)
65 {
66     return CKR_OK;
67 }
68 
69 #ifdef NSS_DEBUG
70 static CK_RV
nss_ckmdSessionObject_verifyPointer(const NSSCKMDObject * mdObject)71 nss_ckmdSessionObject_verifyPointer(
72     const NSSCKMDObject *mdObject)
73 {
74     return CKR_OK;
75 }
76 #endif
77 
78 #endif /* DEBUG */
79 
80 /*
81  * We must forward-declare these routines
82  */
83 static void
84 nss_ckmdSessionObject_Finalize(
85     NSSCKMDObject *mdObject,
86     NSSCKFWObject *fwObject,
87     NSSCKMDSession *mdSession,
88     NSSCKFWSession *fwSession,
89     NSSCKMDToken *mdToken,
90     NSSCKFWToken *fwToken,
91     NSSCKMDInstance *mdInstance,
92     NSSCKFWInstance *fwInstance);
93 
94 static CK_RV
95 nss_ckmdSessionObject_Destroy(
96     NSSCKMDObject *mdObject,
97     NSSCKFWObject *fwObject,
98     NSSCKMDSession *mdSession,
99     NSSCKFWSession *fwSession,
100     NSSCKMDToken *mdToken,
101     NSSCKFWToken *fwToken,
102     NSSCKMDInstance *mdInstance,
103     NSSCKFWInstance *fwInstance);
104 
105 static CK_BBOOL
106 nss_ckmdSessionObject_IsTokenObject(
107     NSSCKMDObject *mdObject,
108     NSSCKFWObject *fwObject,
109     NSSCKMDSession *mdSession,
110     NSSCKFWSession *fwSession,
111     NSSCKMDToken *mdToken,
112     NSSCKFWToken *fwToken,
113     NSSCKMDInstance *mdInstance,
114     NSSCKFWInstance *fwInstance);
115 
116 static CK_ULONG
117 nss_ckmdSessionObject_GetAttributeCount(
118     NSSCKMDObject *mdObject,
119     NSSCKFWObject *fwObject,
120     NSSCKMDSession *mdSession,
121     NSSCKFWSession *fwSession,
122     NSSCKMDToken *mdToken,
123     NSSCKFWToken *fwToken,
124     NSSCKMDInstance *mdInstance,
125     NSSCKFWInstance *fwInstance,
126     CK_RV *pError);
127 
128 static CK_RV
129 nss_ckmdSessionObject_GetAttributeTypes(
130     NSSCKMDObject *mdObject,
131     NSSCKFWObject *fwObject,
132     NSSCKMDSession *mdSession,
133     NSSCKFWSession *fwSession,
134     NSSCKMDToken *mdToken,
135     NSSCKFWToken *fwToken,
136     NSSCKMDInstance *mdInstance,
137     NSSCKFWInstance *fwInstance,
138     CK_ATTRIBUTE_TYPE_PTR typeArray,
139     CK_ULONG ulCount);
140 
141 static CK_ULONG
142 nss_ckmdSessionObject_GetAttributeSize(
143     NSSCKMDObject *mdObject,
144     NSSCKFWObject *fwObject,
145     NSSCKMDSession *mdSession,
146     NSSCKFWSession *fwSession,
147     NSSCKMDToken *mdToken,
148     NSSCKFWToken *fwToken,
149     NSSCKMDInstance *mdInstance,
150     NSSCKFWInstance *fwInstance,
151     CK_ATTRIBUTE_TYPE attribute,
152     CK_RV *pError);
153 
154 static NSSCKFWItem
155 nss_ckmdSessionObject_GetAttribute(
156     NSSCKMDObject *mdObject,
157     NSSCKFWObject *fwObject,
158     NSSCKMDSession *mdSession,
159     NSSCKFWSession *fwSession,
160     NSSCKMDToken *mdToken,
161     NSSCKFWToken *fwToken,
162     NSSCKMDInstance *mdInstance,
163     NSSCKFWInstance *fwInstance,
164     CK_ATTRIBUTE_TYPE attribute,
165     CK_RV *pError);
166 
167 static CK_RV
168 nss_ckmdSessionObject_SetAttribute(
169     NSSCKMDObject *mdObject,
170     NSSCKFWObject *fwObject,
171     NSSCKMDSession *mdSession,
172     NSSCKFWSession *fwSession,
173     NSSCKMDToken *mdToken,
174     NSSCKFWToken *fwToken,
175     NSSCKMDInstance *mdInstance,
176     NSSCKFWInstance *fwInstance,
177     CK_ATTRIBUTE_TYPE attribute,
178     NSSItem *value);
179 
180 static CK_ULONG
181 nss_ckmdSessionObject_GetObjectSize(
182     NSSCKMDObject *mdObject,
183     NSSCKFWObject *fwObject,
184     NSSCKMDSession *mdSession,
185     NSSCKFWSession *fwSession,
186     NSSCKMDToken *mdToken,
187     NSSCKFWToken *fwToken,
188     NSSCKMDInstance *mdInstance,
189     NSSCKFWInstance *fwInstance,
190     CK_RV *pError);
191 
192 /*
193  * nssCKMDSessionObject_Create
194  *
195  */
196 NSS_IMPLEMENT NSSCKMDObject *
nssCKMDSessionObject_Create(NSSCKFWToken * fwToken,NSSArena * arena,CK_ATTRIBUTE_PTR attributes,CK_ULONG ulCount,CK_RV * pError)197 nssCKMDSessionObject_Create(
198     NSSCKFWToken *fwToken,
199     NSSArena *arena,
200     CK_ATTRIBUTE_PTR attributes,
201     CK_ULONG ulCount,
202     CK_RV *pError)
203 {
204     NSSCKMDObject *mdObject = (NSSCKMDObject *)NULL;
205     nssCKMDSessionObject *mdso = (nssCKMDSessionObject *)NULL;
206     CK_ULONG i;
207     nssCKFWHash *hash;
208 
209     *pError = CKR_OK;
210 
211     mdso = nss_ZNEW(arena, nssCKMDSessionObject);
212     if (!mdso) {
213         goto loser;
214     }
215 
216     mdso->arena = arena;
217     mdso->n = ulCount;
218     mdso->attributes = nss_ZNEWARRAY(arena, NSSItem, ulCount);
219     if (!mdso->attributes) {
220         goto loser;
221     }
222 
223     mdso->types = nss_ZNEWARRAY(arena, CK_ATTRIBUTE_TYPE, ulCount);
224     if (!mdso->types) {
225         goto loser;
226     }
227     for (i = 0; i < ulCount; i++) {
228         mdso->types[i] = attributes[i].type;
229         mdso->attributes[i].size = attributes[i].ulValueLen;
230         mdso->attributes[i].data = nss_ZAlloc(arena, attributes[i].ulValueLen);
231         if (!mdso->attributes[i].data) {
232             goto loser;
233         }
234         (void)nsslibc_memcpy(mdso->attributes[i].data, attributes[i].pValue,
235                              attributes[i].ulValueLen);
236     }
237 
238     mdObject = nss_ZNEW(arena, NSSCKMDObject);
239     if (!mdObject) {
240         goto loser;
241     }
242 
243     mdObject->etc = (void *)mdso;
244     mdObject->Finalize = nss_ckmdSessionObject_Finalize;
245     mdObject->Destroy = nss_ckmdSessionObject_Destroy;
246     mdObject->IsTokenObject = nss_ckmdSessionObject_IsTokenObject;
247     mdObject->GetAttributeCount = nss_ckmdSessionObject_GetAttributeCount;
248     mdObject->GetAttributeTypes = nss_ckmdSessionObject_GetAttributeTypes;
249     mdObject->GetAttributeSize = nss_ckmdSessionObject_GetAttributeSize;
250     mdObject->GetAttribute = nss_ckmdSessionObject_GetAttribute;
251     mdObject->SetAttribute = nss_ckmdSessionObject_SetAttribute;
252     mdObject->GetObjectSize = nss_ckmdSessionObject_GetObjectSize;
253 
254     hash = nssCKFWToken_GetSessionObjectHash(fwToken);
255     if (!hash) {
256         *pError = CKR_GENERAL_ERROR;
257         goto loser;
258     }
259 
260     mdso->hash = hash;
261 
262     *pError = nssCKFWHash_Add(hash, mdObject, mdObject);
263     if (CKR_OK != *pError) {
264         goto loser;
265     }
266 
267 #ifdef DEBUG
268     if ((*pError = nss_ckmdSessionObject_add_pointer(mdObject)) != CKR_OK) {
269         goto loser;
270     }
271 #endif /* DEBUG */
272 
273     return mdObject;
274 
275 loser:
276     if (mdso) {
277         if (mdso->attributes) {
278             for (i = 0; i < ulCount; i++) {
279                 nss_ZFreeIf(mdso->attributes[i].data);
280             }
281             nss_ZFreeIf(mdso->attributes);
282         }
283         nss_ZFreeIf(mdso->types);
284         nss_ZFreeIf(mdso);
285     }
286 
287     nss_ZFreeIf(mdObject);
288     if (*pError == CKR_OK) {
289         *pError = CKR_HOST_MEMORY;
290     }
291     return (NSSCKMDObject *)NULL;
292 }
293 
294 /*
295  * nss_ckmdSessionObject_Finalize
296  *
297  */
298 static void
nss_ckmdSessionObject_Finalize(NSSCKMDObject * mdObject,NSSCKFWObject * fwObject,NSSCKMDSession * mdSession,NSSCKFWSession * fwSession,NSSCKMDToken * mdToken,NSSCKFWToken * fwToken,NSSCKMDInstance * mdInstance,NSSCKFWInstance * fwInstance)299 nss_ckmdSessionObject_Finalize(
300     NSSCKMDObject *mdObject,
301     NSSCKFWObject *fwObject,
302     NSSCKMDSession *mdSession,
303     NSSCKFWSession *fwSession,
304     NSSCKMDToken *mdToken,
305     NSSCKFWToken *fwToken,
306     NSSCKMDInstance *mdInstance,
307     NSSCKFWInstance *fwInstance)
308 {
309     /* This shouldn't ever be called */
310     return;
311 }
312 
313 /*
314  * nss_ckmdSessionObject_Destroy
315  *
316  */
317 
318 static CK_RV
nss_ckmdSessionObject_Destroy(NSSCKMDObject * mdObject,NSSCKFWObject * fwObject,NSSCKMDSession * mdSession,NSSCKFWSession * fwSession,NSSCKMDToken * mdToken,NSSCKFWToken * fwToken,NSSCKMDInstance * mdInstance,NSSCKFWInstance * fwInstance)319 nss_ckmdSessionObject_Destroy(
320     NSSCKMDObject *mdObject,
321     NSSCKFWObject *fwObject,
322     NSSCKMDSession *mdSession,
323     NSSCKFWSession *fwSession,
324     NSSCKMDToken *mdToken,
325     NSSCKFWToken *fwToken,
326     NSSCKMDInstance *mdInstance,
327     NSSCKFWInstance *fwInstance)
328 {
329 #ifdef NSSDEBUG
330     CK_RV error = CKR_OK;
331 #endif /* NSSDEBUG */
332     nssCKMDSessionObject *mdso;
333     CK_ULONG i;
334 
335 #ifdef NSSDEBUG
336     error = nss_ckmdSessionObject_verifyPointer(mdObject);
337     if (CKR_OK != error) {
338         return error;
339     }
340 #endif /* NSSDEBUG */
341 
342     mdso = (nssCKMDSessionObject *)mdObject->etc;
343 
344     nssCKFWHash_Remove(mdso->hash, mdObject);
345 
346     for (i = 0; i < mdso->n; i++) {
347         nss_ZFreeIf(mdso->attributes[i].data);
348     }
349     nss_ZFreeIf(mdso->attributes);
350     nss_ZFreeIf(mdso->types);
351     nss_ZFreeIf(mdso);
352     nss_ZFreeIf(mdObject);
353 
354 #ifdef DEBUG
355     (void)nss_ckmdSessionObject_remove_pointer(mdObject);
356 #endif /* DEBUG */
357 
358     return CKR_OK;
359 }
360 
361 /*
362  * nss_ckmdSessionObject_IsTokenObject
363  *
364  */
365 
366 static CK_BBOOL
nss_ckmdSessionObject_IsTokenObject(NSSCKMDObject * mdObject,NSSCKFWObject * fwObject,NSSCKMDSession * mdSession,NSSCKFWSession * fwSession,NSSCKMDToken * mdToken,NSSCKFWToken * fwToken,NSSCKMDInstance * mdInstance,NSSCKFWInstance * fwInstance)367 nss_ckmdSessionObject_IsTokenObject(
368     NSSCKMDObject *mdObject,
369     NSSCKFWObject *fwObject,
370     NSSCKMDSession *mdSession,
371     NSSCKFWSession *fwSession,
372     NSSCKMDToken *mdToken,
373     NSSCKFWToken *fwToken,
374     NSSCKMDInstance *mdInstance,
375     NSSCKFWInstance *fwInstance)
376 {
377 #ifdef NSSDEBUG
378     if (CKR_OK != nss_ckmdSessionObject_verifyPointer(mdObject)) {
379         return CK_FALSE;
380     }
381 #endif /* NSSDEBUG */
382 
383     /*
384      * This implementation is only ever used for session objects.
385      */
386     return CK_FALSE;
387 }
388 
389 /*
390  * nss_ckmdSessionObject_GetAttributeCount
391  *
392  */
393 static CK_ULONG
nss_ckmdSessionObject_GetAttributeCount(NSSCKMDObject * mdObject,NSSCKFWObject * fwObject,NSSCKMDSession * mdSession,NSSCKFWSession * fwSession,NSSCKMDToken * mdToken,NSSCKFWToken * fwToken,NSSCKMDInstance * mdInstance,NSSCKFWInstance * fwInstance,CK_RV * pError)394 nss_ckmdSessionObject_GetAttributeCount(
395     NSSCKMDObject *mdObject,
396     NSSCKFWObject *fwObject,
397     NSSCKMDSession *mdSession,
398     NSSCKFWSession *fwSession,
399     NSSCKMDToken *mdToken,
400     NSSCKFWToken *fwToken,
401     NSSCKMDInstance *mdInstance,
402     NSSCKFWInstance *fwInstance,
403     CK_RV *pError)
404 {
405     nssCKMDSessionObject *obj;
406 
407 #ifdef NSSDEBUG
408     if (!pError) {
409         return 0;
410     }
411 
412     *pError = nss_ckmdSessionObject_verifyPointer(mdObject);
413     if (CKR_OK != *pError) {
414         return 0;
415     }
416 
417 /* We could even check all the other arguments, for sanity. */
418 #endif /* NSSDEBUG */
419 
420     obj = (nssCKMDSessionObject *)mdObject->etc;
421 
422     return obj->n;
423 }
424 
425 /*
426  * nss_ckmdSessionObject_GetAttributeTypes
427  *
428  */
429 static CK_RV
nss_ckmdSessionObject_GetAttributeTypes(NSSCKMDObject * mdObject,NSSCKFWObject * fwObject,NSSCKMDSession * mdSession,NSSCKFWSession * fwSession,NSSCKMDToken * mdToken,NSSCKFWToken * fwToken,NSSCKMDInstance * mdInstance,NSSCKFWInstance * fwInstance,CK_ATTRIBUTE_TYPE_PTR typeArray,CK_ULONG ulCount)430 nss_ckmdSessionObject_GetAttributeTypes(
431     NSSCKMDObject *mdObject,
432     NSSCKFWObject *fwObject,
433     NSSCKMDSession *mdSession,
434     NSSCKFWSession *fwSession,
435     NSSCKMDToken *mdToken,
436     NSSCKFWToken *fwToken,
437     NSSCKMDInstance *mdInstance,
438     NSSCKFWInstance *fwInstance,
439     CK_ATTRIBUTE_TYPE_PTR typeArray,
440     CK_ULONG ulCount)
441 {
442 #ifdef NSSDEBUG
443     CK_RV error = CKR_OK;
444 #endif /* NSSDEBUG */
445     nssCKMDSessionObject *obj;
446 
447 #ifdef NSSDEBUG
448     error = nss_ckmdSessionObject_verifyPointer(mdObject);
449     if (CKR_OK != error) {
450         return error;
451     }
452 
453 /* We could even check all the other arguments, for sanity. */
454 #endif /* NSSDEBUG */
455 
456     obj = (nssCKMDSessionObject *)mdObject->etc;
457 
458     if (ulCount < obj->n) {
459         return CKR_BUFFER_TOO_SMALL;
460     }
461 
462     (void)nsslibc_memcpy(typeArray, obj->types,
463                          sizeof(CK_ATTRIBUTE_TYPE) *
464                              obj->n);
465 
466     return CKR_OK;
467 }
468 
469 /*
470  * nss_ckmdSessionObject_GetAttributeSize
471  *
472  */
473 static CK_ULONG
nss_ckmdSessionObject_GetAttributeSize(NSSCKMDObject * mdObject,NSSCKFWObject * fwObject,NSSCKMDSession * mdSession,NSSCKFWSession * fwSession,NSSCKMDToken * mdToken,NSSCKFWToken * fwToken,NSSCKMDInstance * mdInstance,NSSCKFWInstance * fwInstance,CK_ATTRIBUTE_TYPE attribute,CK_RV * pError)474 nss_ckmdSessionObject_GetAttributeSize(
475     NSSCKMDObject *mdObject,
476     NSSCKFWObject *fwObject,
477     NSSCKMDSession *mdSession,
478     NSSCKFWSession *fwSession,
479     NSSCKMDToken *mdToken,
480     NSSCKFWToken *fwToken,
481     NSSCKMDInstance *mdInstance,
482     NSSCKFWInstance *fwInstance,
483     CK_ATTRIBUTE_TYPE attribute,
484     CK_RV *pError)
485 {
486     nssCKMDSessionObject *obj;
487     CK_ULONG i;
488 
489 #ifdef NSSDEBUG
490     if (!pError) {
491         return 0;
492     }
493 
494     *pError = nss_ckmdSessionObject_verifyPointer(mdObject);
495     if (CKR_OK != *pError) {
496         return 0;
497     }
498 
499 /* We could even check all the other arguments, for sanity. */
500 #endif /* NSSDEBUG */
501 
502     obj = (nssCKMDSessionObject *)mdObject->etc;
503 
504     for (i = 0; i < obj->n; i++) {
505         if (attribute == obj->types[i]) {
506             return (CK_ULONG)(obj->attributes[i].size);
507         }
508     }
509 
510     *pError = CKR_ATTRIBUTE_TYPE_INVALID;
511     return 0;
512 }
513 
514 /*
515  * nss_ckmdSessionObject_GetAttribute
516  *
517  */
518 static NSSCKFWItem
nss_ckmdSessionObject_GetAttribute(NSSCKMDObject * mdObject,NSSCKFWObject * fwObject,NSSCKMDSession * mdSession,NSSCKFWSession * fwSession,NSSCKMDToken * mdToken,NSSCKFWToken * fwToken,NSSCKMDInstance * mdInstance,NSSCKFWInstance * fwInstance,CK_ATTRIBUTE_TYPE attribute,CK_RV * pError)519 nss_ckmdSessionObject_GetAttribute(
520     NSSCKMDObject *mdObject,
521     NSSCKFWObject *fwObject,
522     NSSCKMDSession *mdSession,
523     NSSCKFWSession *fwSession,
524     NSSCKMDToken *mdToken,
525     NSSCKFWToken *fwToken,
526     NSSCKMDInstance *mdInstance,
527     NSSCKFWInstance *fwInstance,
528     CK_ATTRIBUTE_TYPE attribute,
529     CK_RV *pError)
530 {
531     NSSCKFWItem item;
532     nssCKMDSessionObject *obj;
533     CK_ULONG i;
534 
535     item.needsFreeing = PR_FALSE;
536     item.item = NULL;
537 #ifdef NSSDEBUG
538     if (!pError) {
539         return item;
540     }
541 
542     *pError = nss_ckmdSessionObject_verifyPointer(mdObject);
543     if (CKR_OK != *pError) {
544         return item;
545     }
546 
547 /* We could even check all the other arguments, for sanity. */
548 #endif /* NSSDEBUG */
549 
550     obj = (nssCKMDSessionObject *)mdObject->etc;
551 
552     for (i = 0; i < obj->n; i++) {
553         if (attribute == obj->types[i]) {
554             item.item = &obj->attributes[i];
555             return item;
556         }
557     }
558 
559     *pError = CKR_ATTRIBUTE_TYPE_INVALID;
560     return item;
561 }
562 
563 /*
564  * nss_ckmdSessionObject_SetAttribute
565  *
566  */
567 
568 /*
569  * Okay, so this implementation sucks.  It doesn't support removing
570  * an attribute (if value == NULL), and could be more graceful about
571  * memory.  It should allow "blank" slots in the arrays, with some
572  * invalid attribute type, and then it could support removal much
573  * more easily.  Do this later.
574  */
575 static CK_RV
nss_ckmdSessionObject_SetAttribute(NSSCKMDObject * mdObject,NSSCKFWObject * fwObject,NSSCKMDSession * mdSession,NSSCKFWSession * fwSession,NSSCKMDToken * mdToken,NSSCKFWToken * fwToken,NSSCKMDInstance * mdInstance,NSSCKFWInstance * fwInstance,CK_ATTRIBUTE_TYPE attribute,NSSItem * value)576 nss_ckmdSessionObject_SetAttribute(
577     NSSCKMDObject *mdObject,
578     NSSCKFWObject *fwObject,
579     NSSCKMDSession *mdSession,
580     NSSCKFWSession *fwSession,
581     NSSCKMDToken *mdToken,
582     NSSCKFWToken *fwToken,
583     NSSCKMDInstance *mdInstance,
584     NSSCKFWInstance *fwInstance,
585     CK_ATTRIBUTE_TYPE attribute,
586     NSSItem *value)
587 {
588     nssCKMDSessionObject *obj;
589     CK_ULONG i;
590     NSSItem n;
591     NSSItem *ra;
592     CK_ATTRIBUTE_TYPE_PTR rt;
593 #ifdef NSSDEBUG
594     CK_RV error;
595 #endif /* NSSDEBUG */
596 
597 #ifdef NSSDEBUG
598     error = nss_ckmdSessionObject_verifyPointer(mdObject);
599     if (CKR_OK != error) {
600         return 0;
601     }
602 
603 /* We could even check all the other arguments, for sanity. */
604 #endif /* NSSDEBUG */
605 
606     obj = (nssCKMDSessionObject *)mdObject->etc;
607 
608     n.size = value->size;
609     n.data = nss_ZAlloc(obj->arena, n.size);
610     if (!n.data) {
611         return CKR_HOST_MEMORY;
612     }
613     (void)nsslibc_memcpy(n.data, value->data, n.size);
614 
615     for (i = 0; i < obj->n; i++) {
616         if (attribute == obj->types[i]) {
617             nss_ZFreeIf(obj->attributes[i].data);
618             obj->attributes[i] = n;
619             return CKR_OK;
620         }
621     }
622 
623     /*
624      * It's new.
625      */
626 
627     ra = (NSSItem *)nss_ZRealloc(obj->attributes, sizeof(NSSItem) * (obj->n + 1));
628     if (!ra) {
629         nss_ZFreeIf(n.data);
630         return CKR_HOST_MEMORY;
631     }
632     obj->attributes = ra;
633 
634     rt = (CK_ATTRIBUTE_TYPE_PTR)nss_ZRealloc(obj->types,
635                                              sizeof(CK_ATTRIBUTE_TYPE) * (obj->n + 1));
636     if (!rt) {
637         nss_ZFreeIf(n.data);
638         return CKR_HOST_MEMORY;
639     }
640 
641     obj->types = rt;
642     obj->attributes[obj->n] = n;
643     obj->types[obj->n] = attribute;
644     obj->n++;
645 
646     return CKR_OK;
647 }
648 
649 /*
650  * nss_ckmdSessionObject_GetObjectSize
651  *
652  */
653 static CK_ULONG
nss_ckmdSessionObject_GetObjectSize(NSSCKMDObject * mdObject,NSSCKFWObject * fwObject,NSSCKMDSession * mdSession,NSSCKFWSession * fwSession,NSSCKMDToken * mdToken,NSSCKFWToken * fwToken,NSSCKMDInstance * mdInstance,NSSCKFWInstance * fwInstance,CK_RV * pError)654 nss_ckmdSessionObject_GetObjectSize(
655     NSSCKMDObject *mdObject,
656     NSSCKFWObject *fwObject,
657     NSSCKMDSession *mdSession,
658     NSSCKFWSession *fwSession,
659     NSSCKMDToken *mdToken,
660     NSSCKFWToken *fwToken,
661     NSSCKMDInstance *mdInstance,
662     NSSCKFWInstance *fwInstance,
663     CK_RV *pError)
664 {
665     nssCKMDSessionObject *obj;
666     CK_ULONG i;
667     CK_ULONG rv = (CK_ULONG)0;
668 
669 #ifdef NSSDEBUG
670     if (!pError) {
671         return 0;
672     }
673 
674     *pError = nss_ckmdSessionObject_verifyPointer(mdObject);
675     if (CKR_OK != *pError) {
676         return 0;
677     }
678 
679 /* We could even check all the other arguments, for sanity. */
680 #endif /* NSSDEBUG */
681 
682     obj = (nssCKMDSessionObject *)mdObject->etc;
683 
684     for (i = 0; i < obj->n; i++) {
685         rv += obj->attributes[i].size;
686     }
687 
688     rv += sizeof(NSSItem) * obj->n;
689     rv += sizeof(CK_ATTRIBUTE_TYPE) * obj->n;
690     rv += sizeof(nssCKMDSessionObject);
691 
692     return rv;
693 }
694 
695 /*
696  * nssCKMDFindSessionObjects
697  *
698  *  -- create --
699  *  nssCKMDFindSessionObjects_Create
700  *
701  *  -- EPV calls --
702  *  nss_ckmdFindSessionObjects_Final
703  *  nss_ckmdFindSessionObjects_Next
704  */
705 
706 struct nodeStr {
707     struct nodeStr *next;
708     NSSCKMDObject *mdObject;
709 };
710 
711 struct nssCKMDFindSessionObjectsStr {
712     NSSArena *arena;
713     CK_RV error;
714     CK_ATTRIBUTE_PTR pTemplate;
715     CK_ULONG ulCount;
716     struct nodeStr *list;
717     nssCKFWHash *hash;
718 };
719 typedef struct nssCKMDFindSessionObjectsStr nssCKMDFindSessionObjects;
720 
721 #ifdef DEBUG
722 /*
723  * But first, the pointer-tracking stuff.
724  *
725  * NOTE: the pointer-tracking support in NSS/base currently relies
726  * upon NSPR's CallOnce support.  That, however, relies upon NSPR's
727  * locking, which is tied into the runtime.  We need a pointer-tracker
728  * implementation that uses the locks supplied through C_Initialize.
729  * That support, however, can be filled in later.  So for now, I'll
730  * just do this routines as no-ops.
731  */
732 
733 static CK_RV
nss_ckmdFindSessionObjects_add_pointer(const NSSCKMDFindObjects * mdFindObjects)734 nss_ckmdFindSessionObjects_add_pointer(
735     const NSSCKMDFindObjects *mdFindObjects)
736 {
737     return CKR_OK;
738 }
739 
740 static CK_RV
nss_ckmdFindSessionObjects_remove_pointer(const NSSCKMDFindObjects * mdFindObjects)741 nss_ckmdFindSessionObjects_remove_pointer(
742     const NSSCKMDFindObjects *mdFindObjects)
743 {
744     return CKR_OK;
745 }
746 
747 #ifdef NSS_DEBUG
748 static CK_RV
nss_ckmdFindSessionObjects_verifyPointer(const NSSCKMDFindObjects * mdFindObjects)749 nss_ckmdFindSessionObjects_verifyPointer(
750     const NSSCKMDFindObjects *mdFindObjects)
751 {
752     return CKR_OK;
753 }
754 #endif
755 
756 #endif /* DEBUG */
757 
758 /*
759  * We must forward-declare these routines.
760  */
761 static void
762 nss_ckmdFindSessionObjects_Final(
763     NSSCKMDFindObjects *mdFindObjects,
764     NSSCKFWFindObjects *fwFindObjects,
765     NSSCKMDSession *mdSession,
766     NSSCKFWSession *fwSession,
767     NSSCKMDToken *mdToken,
768     NSSCKFWToken *fwToken,
769     NSSCKMDInstance *mdInstance,
770     NSSCKFWInstance *fwInstance);
771 
772 static NSSCKMDObject *
773 nss_ckmdFindSessionObjects_Next(
774     NSSCKMDFindObjects *mdFindObjects,
775     NSSCKFWFindObjects *fwFindObjects,
776     NSSCKMDSession *mdSession,
777     NSSCKFWSession *fwSession,
778     NSSCKMDToken *mdToken,
779     NSSCKFWToken *fwToken,
780     NSSCKMDInstance *mdInstance,
781     NSSCKFWInstance *fwInstance,
782     NSSArena *arena,
783     CK_RV *pError);
784 
785 static CK_BBOOL
items_match(NSSItem * a,CK_VOID_PTR pValue,CK_ULONG ulValueLen)786 items_match(
787     NSSItem *a,
788     CK_VOID_PTR pValue,
789     CK_ULONG ulValueLen)
790 {
791     if (a->size != ulValueLen) {
792         return CK_FALSE;
793     }
794 
795     if (PR_TRUE == nsslibc_memequal(a->data, pValue, ulValueLen, (PRStatus *)NULL)) {
796         return CK_TRUE;
797     } else {
798         return CK_FALSE;
799     }
800 }
801 
802 /*
803  * Our hashtable iterator
804  */
805 static void
findfcn(const void * key,void * value,void * closure)806 findfcn(
807     const void *key,
808     void *value,
809     void *closure)
810 {
811     NSSCKMDObject *mdObject = (NSSCKMDObject *)value;
812     nssCKMDSessionObject *mdso = (nssCKMDSessionObject *)mdObject->etc;
813     nssCKMDFindSessionObjects *mdfso = (nssCKMDFindSessionObjects *)closure;
814     CK_ULONG i, j;
815     struct nodeStr *node;
816 
817     if (CKR_OK != mdfso->error) {
818         return;
819     }
820 
821     for (i = 0; i < mdfso->ulCount; i++) {
822         CK_ATTRIBUTE_PTR p = &mdfso->pTemplate[i];
823 
824         for (j = 0; j < mdso->n; j++) {
825             if (mdso->types[j] == p->type) {
826                 if (!items_match(&mdso->attributes[j], p->pValue, p->ulValueLen)) {
827                     return;
828                 } else {
829                     break;
830                 }
831             }
832         }
833 
834         if (j == mdso->n) {
835             /* Attribute not found */
836             return;
837         }
838     }
839 
840     /* Matches */
841     node = nss_ZNEW(mdfso->arena, struct nodeStr);
842     if ((struct nodeStr *)NULL == node) {
843         mdfso->error = CKR_HOST_MEMORY;
844         return;
845     }
846 
847     node->mdObject = mdObject;
848     node->next = mdfso->list;
849     mdfso->list = node;
850 
851     return;
852 }
853 
854 /*
855  * nssCKMDFindSessionObjects_Create
856  *
857  */
858 NSS_IMPLEMENT NSSCKMDFindObjects *
nssCKMDFindSessionObjects_Create(NSSCKFWToken * fwToken,CK_ATTRIBUTE_PTR pTemplate,CK_ULONG ulCount,CK_RV * pError)859 nssCKMDFindSessionObjects_Create(
860     NSSCKFWToken *fwToken,
861     CK_ATTRIBUTE_PTR pTemplate,
862     CK_ULONG ulCount,
863     CK_RV *pError)
864 {
865     NSSArena *arena;
866     nssCKMDFindSessionObjects *mdfso;
867     nssCKFWHash *hash;
868     NSSCKMDFindObjects *rv;
869 
870 #ifdef NSSDEBUG
871     if (!pError) {
872         return (NSSCKMDFindObjects *)NULL;
873     }
874 
875     *pError = nssCKFWToken_verifyPointer(fwToken);
876     if (CKR_OK != *pError) {
877         return (NSSCKMDFindObjects *)NULL;
878     }
879 
880     if ((CK_ATTRIBUTE_PTR)NULL == pTemplate) {
881         *pError = CKR_ARGUMENTS_BAD;
882         return (NSSCKMDFindObjects *)NULL;
883     }
884 #endif /* NSSDEBUG */
885 
886     *pError = CKR_OK;
887 
888     hash = nssCKFWToken_GetSessionObjectHash(fwToken);
889     if (!hash) {
890         *pError = CKR_GENERAL_ERROR;
891         return (NSSCKMDFindObjects *)NULL;
892     }
893 
894     arena = NSSArena_Create();
895     if (!arena) {
896         *pError = CKR_HOST_MEMORY;
897         return (NSSCKMDFindObjects *)NULL;
898     }
899 
900     mdfso = nss_ZNEW(arena, nssCKMDFindSessionObjects);
901     if (!mdfso) {
902         goto loser;
903     }
904 
905     rv = nss_ZNEW(arena, NSSCKMDFindObjects);
906     if (rv == NULL) {
907         goto loser;
908     }
909 
910     mdfso->error = CKR_OK;
911     mdfso->pTemplate = pTemplate;
912     mdfso->ulCount = ulCount;
913     mdfso->hash = hash;
914 
915     nssCKFWHash_Iterate(hash, findfcn, mdfso);
916 
917     if (CKR_OK != mdfso->error) {
918         goto loser;
919     }
920 
921     rv->etc = (void *)mdfso;
922     rv->Final = nss_ckmdFindSessionObjects_Final;
923     rv->Next = nss_ckmdFindSessionObjects_Next;
924 
925 #ifdef DEBUG
926     if ((*pError = nss_ckmdFindSessionObjects_add_pointer(rv)) != CKR_OK) {
927         goto loser;
928     }
929 #endif /* DEBUG */
930     mdfso->arena = arena;
931 
932     return rv;
933 
934 loser:
935     if (arena) {
936         NSSArena_Destroy(arena);
937     }
938     if (*pError == CKR_OK) {
939         *pError = CKR_HOST_MEMORY;
940     }
941     return NULL;
942 }
943 
944 static void
nss_ckmdFindSessionObjects_Final(NSSCKMDFindObjects * mdFindObjects,NSSCKFWFindObjects * fwFindObjects,NSSCKMDSession * mdSession,NSSCKFWSession * fwSession,NSSCKMDToken * mdToken,NSSCKFWToken * fwToken,NSSCKMDInstance * mdInstance,NSSCKFWInstance * fwInstance)945 nss_ckmdFindSessionObjects_Final(
946     NSSCKMDFindObjects *mdFindObjects,
947     NSSCKFWFindObjects *fwFindObjects,
948     NSSCKMDSession *mdSession,
949     NSSCKFWSession *fwSession,
950     NSSCKMDToken *mdToken,
951     NSSCKFWToken *fwToken,
952     NSSCKMDInstance *mdInstance,
953     NSSCKFWInstance *fwInstance)
954 {
955     nssCKMDFindSessionObjects *mdfso;
956 
957 #ifdef NSSDEBUG
958     if (CKR_OK != nss_ckmdFindSessionObjects_verifyPointer(mdFindObjects)) {
959         return;
960     }
961 #endif /* NSSDEBUG */
962 
963     mdfso = (nssCKMDFindSessionObjects *)mdFindObjects->etc;
964     if (mdfso->arena)
965         NSSArena_Destroy(mdfso->arena);
966 
967 #ifdef DEBUG
968     (void)nss_ckmdFindSessionObjects_remove_pointer(mdFindObjects);
969 #endif /* DEBUG */
970 
971     return;
972 }
973 
974 static NSSCKMDObject *
nss_ckmdFindSessionObjects_Next(NSSCKMDFindObjects * mdFindObjects,NSSCKFWFindObjects * fwFindObjects,NSSCKMDSession * mdSession,NSSCKFWSession * fwSession,NSSCKMDToken * mdToken,NSSCKFWToken * fwToken,NSSCKMDInstance * mdInstance,NSSCKFWInstance * fwInstance,NSSArena * arena,CK_RV * pError)975 nss_ckmdFindSessionObjects_Next(
976     NSSCKMDFindObjects *mdFindObjects,
977     NSSCKFWFindObjects *fwFindObjects,
978     NSSCKMDSession *mdSession,
979     NSSCKFWSession *fwSession,
980     NSSCKMDToken *mdToken,
981     NSSCKFWToken *fwToken,
982     NSSCKMDInstance *mdInstance,
983     NSSCKFWInstance *fwInstance,
984     NSSArena *arena,
985     CK_RV *pError)
986 {
987     nssCKMDFindSessionObjects *mdfso;
988     NSSCKMDObject *rv = (NSSCKMDObject *)NULL;
989 
990 #ifdef NSSDEBUG
991     if (CKR_OK != nss_ckmdFindSessionObjects_verifyPointer(mdFindObjects)) {
992         return (NSSCKMDObject *)NULL;
993     }
994 #endif /* NSSDEBUG */
995 
996     mdfso = (nssCKMDFindSessionObjects *)mdFindObjects->etc;
997 
998     while (!rv) {
999         if ((struct nodeStr *)NULL == mdfso->list) {
1000             *pError = CKR_OK;
1001             return (NSSCKMDObject *)NULL;
1002         }
1003 
1004         if (nssCKFWHash_Exists(mdfso->hash, mdfso->list->mdObject)) {
1005             rv = mdfso->list->mdObject;
1006         }
1007 
1008         mdfso->list = mdfso->list->next;
1009     }
1010 
1011     return rv;
1012 }
1013