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 * Internal PKCS #11 functions. Should only be called by pkcs11.c
6 */
7 #include "pkcs11.h"
8 #include "pkcs11i.h"
9 #include "lowkeyi.h"
10 #include "secasn1.h"
11 #include "blapi.h"
12 #include "secerr.h"
13 #include "prnetdb.h" /* for PR_ntohl */
14 #include "sftkdb.h"
15 #include "softoken.h"
16 #include "secoid.h"
17
18 #if !defined(NSS_FIPS_DISABLED) && defined(NSS_ENABLE_FIPS_INDICATORS)
19 /* this file should be supplied by the vendor and include all the
20 * algorithms which have Algorithm certs and have been reviewed by
21 * the lab. A blank file is included for the base so that FIPS mode
22 * will still be compiled and run, but FIPS indicators will always
23 * return PR_FALSE
24 */
25 #include "fips_algorithms.h"
26 #define NSS_HAS_FIPS_INDICATORS 1
27 #endif
28
29 /*
30 * ******************** Error mapping *******************************
31 */
32 /*
33 * map all the SEC_ERROR_xxx error codes that may be returned by freebl
34 * functions to CKR_xxx. return CKR_DEVICE_ERROR by default for backward
35 * compatibility.
36 */
37 CK_RV
sftk_MapCryptError(int error)38 sftk_MapCryptError(int error)
39 {
40 switch (error) {
41 case SEC_ERROR_INVALID_ARGS:
42 case SEC_ERROR_BAD_DATA: /* MP_RANGE gets mapped to this */
43 return CKR_ARGUMENTS_BAD;
44 case SEC_ERROR_INPUT_LEN:
45 return CKR_DATA_LEN_RANGE;
46 case SEC_ERROR_OUTPUT_LEN:
47 return CKR_BUFFER_TOO_SMALL;
48 case SEC_ERROR_LIBRARY_FAILURE:
49 return CKR_GENERAL_ERROR;
50 case SEC_ERROR_NO_MEMORY:
51 return CKR_HOST_MEMORY;
52 case SEC_ERROR_BAD_SIGNATURE:
53 return CKR_SIGNATURE_INVALID;
54 case SEC_ERROR_INVALID_KEY:
55 return CKR_KEY_SIZE_RANGE;
56 case SEC_ERROR_BAD_KEY: /* an EC public key that fails validation */
57 return CKR_KEY_SIZE_RANGE; /* the closest error code */
58 case SEC_ERROR_UNSUPPORTED_EC_POINT_FORM:
59 return CKR_TEMPLATE_INCONSISTENT;
60 case SEC_ERROR_UNSUPPORTED_KEYALG:
61 return CKR_MECHANISM_INVALID;
62 case SEC_ERROR_UNSUPPORTED_ELLIPTIC_CURVE:
63 return CKR_DOMAIN_PARAMS_INVALID;
64 /* key pair generation failed after max number of attempts */
65 case SEC_ERROR_NEED_RANDOM:
66 return CKR_FUNCTION_FAILED;
67 }
68 return CKR_DEVICE_ERROR;
69 }
70
71 /*
72 * functions which adjust the mapping based on different contexts
73 * (Decrypt or Verify).
74 */
75
76 /* used by Decrypt and UnwrapKey (indirectly) and Decrypt message */
77 CK_RV
sftk_MapDecryptError(int error)78 sftk_MapDecryptError(int error)
79 {
80 switch (error) {
81 /* usually a padding error, or aead tag mismatch */
82 case SEC_ERROR_BAD_DATA:
83 return CKR_ENCRYPTED_DATA_INVALID;
84 default:
85 return sftk_MapCryptError(error);
86 }
87 }
88
89 /*
90 * return CKR_SIGNATURE_INVALID instead of CKR_DEVICE_ERROR by default for
91 * backward compatibilty.
92 */
93 CK_RV
sftk_MapVerifyError(int error)94 sftk_MapVerifyError(int error)
95 {
96 CK_RV crv = sftk_MapCryptError(error);
97 if (crv == CKR_DEVICE_ERROR)
98 crv = CKR_SIGNATURE_INVALID;
99 return crv;
100 }
101
102 /*
103 * ******************** Attribute Utilities *******************************
104 */
105
106 /*
107 * create a new attribute with type, value, and length. Space is allocated
108 * to hold value.
109 */
110 static SFTKAttribute *
sftk_NewAttribute(SFTKObject * object,CK_ATTRIBUTE_TYPE type,const void * value,CK_ULONG len)111 sftk_NewAttribute(SFTKObject *object,
112 CK_ATTRIBUTE_TYPE type, const void *value, CK_ULONG len)
113 {
114 SFTKAttribute *attribute;
115
116 SFTKSessionObject *so = sftk_narrowToSessionObject(object);
117 int index;
118
119 if (so == NULL) {
120 /* allocate new attribute in a buffer */
121 PORT_Assert(0);
122 return NULL;
123 }
124 /*
125 * We attempt to keep down contention on Malloc and Arena locks by
126 * limiting the number of these calls on high traversed paths. This
127 * is done for attributes by 'allocating' them from a pool already
128 * allocated by the parent object.
129 */
130 PZ_Lock(so->attributeLock);
131 index = so->nextAttr++;
132 PZ_Unlock(so->attributeLock);
133 PORT_Assert(index < MAX_OBJS_ATTRS);
134 if (index >= MAX_OBJS_ATTRS)
135 return NULL;
136
137 attribute = &so->attrList[index];
138 attribute->attrib.type = type;
139 attribute->freeAttr = PR_FALSE;
140 attribute->freeData = PR_FALSE;
141 if (value) {
142 if (len <= ATTR_SPACE) {
143 attribute->attrib.pValue = attribute->space;
144 } else {
145 attribute->attrib.pValue = PORT_Alloc(len);
146 attribute->freeData = PR_TRUE;
147 }
148 if (attribute->attrib.pValue == NULL) {
149 return NULL;
150 }
151 PORT_Memcpy(attribute->attrib.pValue, value, len);
152 attribute->attrib.ulValueLen = len;
153 } else {
154 attribute->attrib.pValue = NULL;
155 attribute->attrib.ulValueLen = 0;
156 }
157 attribute->attrib.type = type;
158 attribute->handle = type;
159 attribute->next = attribute->prev = NULL;
160 return attribute;
161 }
162
163 /*
164 * Free up all the memory associated with an attribute. Reference count
165 * must be zero to call this.
166 */
167 static void
sftk_DestroyAttribute(SFTKAttribute * attribute)168 sftk_DestroyAttribute(SFTKAttribute *attribute)
169 {
170 if (attribute->attrib.pValue) {
171 /* clear out the data in the attribute value... it may have been
172 * sensitive data */
173 PORT_Memset(attribute->attrib.pValue, 0, attribute->attrib.ulValueLen);
174 if (attribute->freeData) {
175 PORT_Free(attribute->attrib.pValue);
176 attribute->attrib.pValue = NULL;
177 attribute->freeData = PR_FALSE;
178 }
179 }
180 if (attribute->freeAttr) {
181 PORT_Free(attribute);
182 }
183 }
184
185 /*
186 * release a reference to an attribute structure
187 */
188 void
sftk_FreeAttribute(SFTKAttribute * attribute)189 sftk_FreeAttribute(SFTKAttribute *attribute)
190 {
191 if (attribute && attribute->freeAttr) {
192 sftk_DestroyAttribute(attribute);
193 return;
194 }
195 }
196
197 static SFTKAttribute *
sftk_FindTokenAttribute(SFTKTokenObject * object,CK_ATTRIBUTE_TYPE type)198 sftk_FindTokenAttribute(SFTKTokenObject *object, CK_ATTRIBUTE_TYPE type)
199 {
200 SFTKAttribute *myattribute = NULL;
201 SFTKDBHandle *dbHandle = NULL;
202 CK_RV crv = CKR_HOST_MEMORY;
203
204 myattribute = (SFTKAttribute *)PORT_Alloc(sizeof(SFTKAttribute));
205 if (myattribute == NULL) {
206 goto loser;
207 }
208
209 dbHandle = sftk_getDBForTokenObject(object->obj.slot, object->obj.handle);
210
211 myattribute->handle = type;
212 myattribute->attrib.type = type;
213 myattribute->attrib.pValue = myattribute->space;
214 myattribute->attrib.ulValueLen = ATTR_SPACE;
215 myattribute->next = myattribute->prev = NULL;
216 myattribute->freeAttr = PR_TRUE;
217 myattribute->freeData = PR_FALSE;
218
219 crv = sftkdb_GetAttributeValue(dbHandle, object->obj.handle,
220 &myattribute->attrib, 1);
221
222 /* attribute is bigger than our attribute space buffer, malloc it */
223 if (crv == CKR_BUFFER_TOO_SMALL) {
224 myattribute->attrib.pValue = NULL;
225 crv = sftkdb_GetAttributeValue(dbHandle, object->obj.handle,
226 &myattribute->attrib, 1);
227 if (crv != CKR_OK) {
228 goto loser;
229 }
230 myattribute->attrib.pValue = PORT_Alloc(myattribute->attrib.ulValueLen);
231 if (myattribute->attrib.pValue == NULL) {
232 crv = CKR_HOST_MEMORY;
233 goto loser;
234 }
235 myattribute->freeData = PR_TRUE;
236 crv = sftkdb_GetAttributeValue(dbHandle, object->obj.handle,
237 &myattribute->attrib, 1);
238 }
239 loser:
240 if (dbHandle) {
241 sftk_freeDB(dbHandle);
242 }
243 if (crv != CKR_OK) {
244 if (myattribute) {
245 myattribute->attrib.ulValueLen = 0;
246 sftk_FreeAttribute(myattribute);
247 myattribute = NULL;
248 }
249 }
250 return myattribute;
251 }
252
253 /*
254 * look up and attribute structure from a type and Object structure.
255 * The returned attribute is referenced and needs to be freed when
256 * it is no longer needed.
257 */
258 SFTKAttribute *
sftk_FindAttribute(SFTKObject * object,CK_ATTRIBUTE_TYPE type)259 sftk_FindAttribute(SFTKObject *object, CK_ATTRIBUTE_TYPE type)
260 {
261 SFTKAttribute *attribute;
262 SFTKSessionObject *sessObject = sftk_narrowToSessionObject(object);
263
264 if (sessObject == NULL) {
265 return sftk_FindTokenAttribute(sftk_narrowToTokenObject(object), type);
266 }
267
268 PZ_Lock(sessObject->attributeLock);
269 sftkqueue_find(attribute, type, sessObject->head, sessObject->hashSize);
270 PZ_Unlock(sessObject->attributeLock);
271
272 return (attribute);
273 }
274
275 /*
276 * Take a buffer and it's length and return it's true size in bits;
277 */
278 unsigned int
sftk_GetLengthInBits(unsigned char * buf,unsigned int bufLen)279 sftk_GetLengthInBits(unsigned char *buf, unsigned int bufLen)
280 {
281 unsigned int size = bufLen * 8;
282 unsigned int i;
283
284 /* Get the real length in bytes */
285 for (i = 0; i < bufLen; i++) {
286 unsigned char c = *buf++;
287 if (c != 0) {
288 unsigned char m;
289 for (m = 0x80; m > 0; m = m >> 1) {
290 if ((c & m) != 0) {
291 break;
292 }
293 size--;
294 }
295 break;
296 }
297 size -= 8;
298 }
299 return size;
300 }
301
302 /*
303 * Constrain a big num attribute. to size and padding
304 * minLength means length of the object must be greater than equal to minLength
305 * maxLength means length of the object must be less than equal to maxLength
306 * minMultiple means that object length mod minMultiple must equal 0.
307 * all input sizes are in bits.
308 * if any constraint is '0' that constraint is not checked.
309 */
310 CK_RV
sftk_ConstrainAttribute(SFTKObject * object,CK_ATTRIBUTE_TYPE type,int minLength,int maxLength,int minMultiple)311 sftk_ConstrainAttribute(SFTKObject *object, CK_ATTRIBUTE_TYPE type,
312 int minLength, int maxLength, int minMultiple)
313 {
314 SFTKAttribute *attribute;
315 int size;
316 unsigned char *ptr;
317
318 attribute = sftk_FindAttribute(object, type);
319 if (!attribute) {
320 return CKR_TEMPLATE_INCOMPLETE;
321 }
322 ptr = (unsigned char *)attribute->attrib.pValue;
323 if (ptr == NULL) {
324 sftk_FreeAttribute(attribute);
325 return CKR_ATTRIBUTE_VALUE_INVALID;
326 }
327 size = sftk_GetLengthInBits(ptr, attribute->attrib.ulValueLen);
328 sftk_FreeAttribute(attribute);
329
330 if ((minLength != 0) && (size < minLength)) {
331 return CKR_ATTRIBUTE_VALUE_INVALID;
332 }
333 if ((maxLength != 0) && (size > maxLength)) {
334 return CKR_ATTRIBUTE_VALUE_INVALID;
335 }
336 if ((minMultiple != 0) && ((size % minMultiple) != 0)) {
337 return CKR_ATTRIBUTE_VALUE_INVALID;
338 }
339 return CKR_OK;
340 }
341
342 PRBool
sftk_hasAttributeToken(SFTKTokenObject * object,CK_ATTRIBUTE_TYPE type)343 sftk_hasAttributeToken(SFTKTokenObject *object, CK_ATTRIBUTE_TYPE type)
344 {
345 CK_ATTRIBUTE template;
346 CK_RV crv;
347 SFTKDBHandle *dbHandle;
348
349 dbHandle = sftk_getDBForTokenObject(object->obj.slot, object->obj.handle);
350 template.type = type;
351 template.pValue = NULL;
352 template.ulValueLen = 0;
353
354 crv = sftkdb_GetAttributeValue(dbHandle, object->obj.handle, &template, 1);
355 sftk_freeDB(dbHandle);
356
357 /* attribute is bigger than our attribute space buffer, malloc it */
358 return (crv == CKR_OK) ? PR_TRUE : PR_FALSE;
359 }
360
361 /*
362 * return true if object has attribute
363 */
364 PRBool
sftk_hasAttribute(SFTKObject * object,CK_ATTRIBUTE_TYPE type)365 sftk_hasAttribute(SFTKObject *object, CK_ATTRIBUTE_TYPE type)
366 {
367 SFTKAttribute *attribute;
368 SFTKSessionObject *sessObject = sftk_narrowToSessionObject(object);
369
370 if (sessObject == NULL) {
371 return sftk_hasAttributeToken(sftk_narrowToTokenObject(object), type);
372 }
373
374 PZ_Lock(sessObject->attributeLock);
375 sftkqueue_find(attribute, type, sessObject->head, sessObject->hashSize);
376 PZ_Unlock(sessObject->attributeLock);
377
378 return (PRBool)(attribute != NULL);
379 }
380
381 /*
382 * add an attribute to an object
383 */
384 static void
sftk_AddAttribute(SFTKObject * object,SFTKAttribute * attribute)385 sftk_AddAttribute(SFTKObject *object, SFTKAttribute *attribute)
386 {
387 SFTKSessionObject *sessObject = sftk_narrowToSessionObject(object);
388
389 if (sessObject == NULL)
390 return;
391 PZ_Lock(sessObject->attributeLock);
392 sftkqueue_add(attribute, attribute->handle,
393 sessObject->head, sessObject->hashSize);
394 PZ_Unlock(sessObject->attributeLock);
395 }
396
397 /*
398 * copy an unsigned attribute into a SECItem. Secitem is allocated in
399 * the specified arena.
400 */
401 CK_RV
sftk_Attribute2SSecItem(PLArenaPool * arena,SECItem * item,SFTKObject * object,CK_ATTRIBUTE_TYPE type)402 sftk_Attribute2SSecItem(PLArenaPool *arena, SECItem *item, SFTKObject *object,
403 CK_ATTRIBUTE_TYPE type)
404 {
405 SFTKAttribute *attribute;
406
407 item->data = NULL;
408
409 attribute = sftk_FindAttribute(object, type);
410 if (attribute == NULL)
411 return CKR_TEMPLATE_INCOMPLETE;
412
413 (void)SECITEM_AllocItem(arena, item, attribute->attrib.ulValueLen);
414 if (item->data == NULL) {
415 sftk_FreeAttribute(attribute);
416 return CKR_HOST_MEMORY;
417 }
418 PORT_Memcpy(item->data, attribute->attrib.pValue, item->len);
419 sftk_FreeAttribute(attribute);
420 return CKR_OK;
421 }
422
423 /*
424 * fetch multiple attributes into SECItems. Secitem data is allocated in
425 * the specified arena.
426 */
427 CK_RV
sftk_MultipleAttribute2SecItem(PLArenaPool * arena,SFTKObject * object,SFTKItemTemplate * itemTemplate,int itemTemplateCount)428 sftk_MultipleAttribute2SecItem(PLArenaPool *arena, SFTKObject *object,
429 SFTKItemTemplate *itemTemplate, int itemTemplateCount)
430 {
431
432 CK_RV crv = CKR_OK;
433 CK_ATTRIBUTE templateSpace[SFTK_MAX_ITEM_TEMPLATE];
434 CK_ATTRIBUTE *template;
435 SFTKTokenObject *tokObject;
436 SFTKDBHandle *dbHandle = NULL;
437 int i;
438
439 tokObject = sftk_narrowToTokenObject(object);
440
441 /* session objects, just loop through the list */
442 if (tokObject == NULL) {
443 for (i = 0; i < itemTemplateCount; i++) {
444 crv = sftk_Attribute2SecItem(arena, itemTemplate[i].item, object,
445 itemTemplate[i].type);
446 if (crv != CKR_OK) {
447 return crv;
448 }
449 }
450 return CKR_OK;
451 }
452
453 /* don't do any work if none is required */
454 if (itemTemplateCount == 0) {
455 return CKR_OK;
456 }
457
458 /* don't allocate the template unless we need it */
459 if (itemTemplateCount > SFTK_MAX_ITEM_TEMPLATE) {
460 template = PORT_NewArray(CK_ATTRIBUTE, itemTemplateCount);
461 } else {
462 template = templateSpace;
463 }
464
465 if (template == NULL) {
466 crv = CKR_HOST_MEMORY;
467 goto loser;
468 }
469
470 dbHandle = sftk_getDBForTokenObject(object->slot, object->handle);
471 if (dbHandle == NULL) {
472 crv = CKR_OBJECT_HANDLE_INVALID;
473 goto loser;
474 }
475
476 /* set up the PKCS #11 template */
477 for (i = 0; i < itemTemplateCount; i++) {
478 template[i].type = itemTemplate[i].type;
479 template[i].pValue = NULL;
480 template[i].ulValueLen = 0;
481 }
482
483 /* fetch the attribute lengths */
484 crv = sftkdb_GetAttributeValue(dbHandle, object->handle,
485 template, itemTemplateCount);
486 if (crv != CKR_OK) {
487 goto loser;
488 }
489
490 /* allocate space for the attributes */
491 for (i = 0; i < itemTemplateCount; i++) {
492 template[i].pValue = PORT_ArenaAlloc(arena, template[i].ulValueLen);
493 if (template[i].pValue == NULL) {
494 crv = CKR_HOST_MEMORY;
495 goto loser;
496 }
497 }
498
499 /* fetch the attributes */
500 crv = sftkdb_GetAttributeValue(dbHandle, object->handle,
501 template, itemTemplateCount);
502 if (crv != CKR_OK) {
503 goto loser;
504 }
505
506 /* Fill in the items */
507 for (i = 0; i < itemTemplateCount; i++) {
508 itemTemplate[i].item->data = template[i].pValue;
509 itemTemplate[i].item->len = template[i].ulValueLen;
510 }
511
512 loser:
513 if (template != templateSpace) {
514 PORT_Free(template);
515 }
516 if (dbHandle) {
517 sftk_freeDB(dbHandle);
518 }
519
520 return crv;
521 }
522
523 /*
524 * delete an attribute from an object
525 */
526 static void
sftk_DeleteAttribute(SFTKObject * object,SFTKAttribute * attribute)527 sftk_DeleteAttribute(SFTKObject *object, SFTKAttribute *attribute)
528 {
529 SFTKSessionObject *sessObject = sftk_narrowToSessionObject(object);
530
531 if (sessObject == NULL) {
532 return;
533 }
534 PZ_Lock(sessObject->attributeLock);
535 if (sftkqueue_is_queued(attribute, attribute->handle,
536 sessObject->head, sessObject->hashSize)) {
537 sftkqueue_delete(attribute, attribute->handle,
538 sessObject->head, sessObject->hashSize);
539 }
540 PZ_Unlock(sessObject->attributeLock);
541 }
542
543 /*
544 * this is only valid for CK_BBOOL type attributes. Return the state
545 * of that attribute.
546 */
547 PRBool
sftk_isTrue(SFTKObject * object,CK_ATTRIBUTE_TYPE type)548 sftk_isTrue(SFTKObject *object, CK_ATTRIBUTE_TYPE type)
549 {
550 SFTKAttribute *attribute;
551 PRBool tok = PR_FALSE;
552
553 attribute = sftk_FindAttribute(object, type);
554 if (attribute == NULL) {
555 return PR_FALSE;
556 }
557 tok = (PRBool)(*(CK_BBOOL *)attribute->attrib.pValue);
558 sftk_FreeAttribute(attribute);
559
560 return tok;
561 }
562
563 /*
564 * force an attribute to null.
565 * this is for sensitive keys which are stored in the database, we don't
566 * want to keep this info around in memory in the clear.
567 */
568 void
sftk_nullAttribute(SFTKObject * object,CK_ATTRIBUTE_TYPE type)569 sftk_nullAttribute(SFTKObject *object, CK_ATTRIBUTE_TYPE type)
570 {
571 SFTKAttribute *attribute;
572
573 attribute = sftk_FindAttribute(object, type);
574 if (attribute == NULL)
575 return;
576
577 if (attribute->attrib.pValue != NULL) {
578 PORT_Memset(attribute->attrib.pValue, 0, attribute->attrib.ulValueLen);
579 if (attribute->freeData) {
580 PORT_Free(attribute->attrib.pValue);
581 }
582 attribute->freeData = PR_FALSE;
583 attribute->attrib.pValue = NULL;
584 attribute->attrib.ulValueLen = 0;
585 }
586 sftk_FreeAttribute(attribute);
587 }
588
589 static CK_RV
sftk_forceTokenAttribute(SFTKObject * object,CK_ATTRIBUTE_TYPE type,const void * value,unsigned int len)590 sftk_forceTokenAttribute(SFTKObject *object, CK_ATTRIBUTE_TYPE type,
591 const void *value, unsigned int len)
592 {
593 CK_ATTRIBUTE attribute;
594 SFTKDBHandle *dbHandle = NULL;
595 SFTKTokenObject *to = sftk_narrowToTokenObject(object);
596 CK_RV crv;
597
598 PORT_Assert(to);
599 if (to == NULL) {
600 return CKR_DEVICE_ERROR;
601 }
602
603 dbHandle = sftk_getDBForTokenObject(object->slot, object->handle);
604
605 attribute.type = type;
606 attribute.pValue = (void *)value;
607 attribute.ulValueLen = len;
608
609 crv = sftkdb_SetAttributeValue(dbHandle, object, &attribute, 1);
610 sftk_freeDB(dbHandle);
611 return crv;
612 }
613
614 /*
615 * force an attribute to a specifc value.
616 */
617 CK_RV
sftk_forceAttribute(SFTKObject * object,CK_ATTRIBUTE_TYPE type,const void * value,unsigned int len)618 sftk_forceAttribute(SFTKObject *object, CK_ATTRIBUTE_TYPE type,
619 const void *value, unsigned int len)
620 {
621 SFTKAttribute *attribute;
622 void *att_val = NULL;
623 PRBool freeData = PR_FALSE;
624
625 PORT_Assert(object);
626 PORT_Assert(object->refCount);
627 PORT_Assert(object->slot);
628 if (!object ||
629 !object->refCount ||
630 !object->slot) {
631 return CKR_DEVICE_ERROR;
632 }
633 if (sftk_isToken(object->handle)) {
634 return sftk_forceTokenAttribute(object, type, value, len);
635 }
636 attribute = sftk_FindAttribute(object, type);
637 if (attribute == NULL)
638 return sftk_AddAttributeType(object, type, value, len);
639
640 if (value) {
641 if (len <= ATTR_SPACE) {
642 att_val = attribute->space;
643 } else {
644 att_val = PORT_Alloc(len);
645 freeData = PR_TRUE;
646 }
647 if (att_val == NULL) {
648 return CKR_HOST_MEMORY;
649 }
650 if (attribute->attrib.pValue == att_val) {
651 PORT_Memset(attribute->attrib.pValue, 0,
652 attribute->attrib.ulValueLen);
653 }
654 PORT_Memcpy(att_val, value, len);
655 }
656 if (attribute->attrib.pValue != NULL) {
657 if (attribute->attrib.pValue != att_val) {
658 PORT_Memset(attribute->attrib.pValue, 0,
659 attribute->attrib.ulValueLen);
660 }
661 if (attribute->freeData) {
662 PORT_Free(attribute->attrib.pValue);
663 }
664 attribute->freeData = PR_FALSE;
665 attribute->attrib.pValue = NULL;
666 attribute->attrib.ulValueLen = 0;
667 }
668 if (att_val) {
669 attribute->attrib.pValue = att_val;
670 attribute->attrib.ulValueLen = len;
671 attribute->freeData = freeData;
672 }
673 sftk_FreeAttribute(attribute);
674 return CKR_OK;
675 }
676
677 /*
678 * return a null terminated string from attribute 'type'. This string
679 * is allocated and needs to be freed with PORT_Free() When complete.
680 */
681 char *
sftk_getString(SFTKObject * object,CK_ATTRIBUTE_TYPE type)682 sftk_getString(SFTKObject *object, CK_ATTRIBUTE_TYPE type)
683 {
684 SFTKAttribute *attribute;
685 char *label = NULL;
686
687 attribute = sftk_FindAttribute(object, type);
688 if (attribute == NULL)
689 return NULL;
690
691 if (attribute->attrib.pValue != NULL) {
692 label = (char *)PORT_Alloc(attribute->attrib.ulValueLen + 1);
693 if (label == NULL) {
694 sftk_FreeAttribute(attribute);
695 return NULL;
696 }
697
698 PORT_Memcpy(label, attribute->attrib.pValue,
699 attribute->attrib.ulValueLen);
700 label[attribute->attrib.ulValueLen] = 0;
701 }
702 sftk_FreeAttribute(attribute);
703 return label;
704 }
705
706 /*
707 * decode when a particular attribute may be modified
708 * SFTK_NEVER: This attribute must be set at object creation time and
709 * can never be modified.
710 * SFTK_ONCOPY: This attribute may be modified only when you copy the
711 * object.
712 * SFTK_SENSITIVE: The CKA_SENSITIVE attribute can only be changed from
713 * CK_FALSE to CK_TRUE.
714 * SFTK_ALWAYS: This attribute can always be modified.
715 * Some attributes vary their modification type based on the class of the
716 * object.
717 */
718 SFTKModifyType
sftk_modifyType(CK_ATTRIBUTE_TYPE type,CK_OBJECT_CLASS inClass)719 sftk_modifyType(CK_ATTRIBUTE_TYPE type, CK_OBJECT_CLASS inClass)
720 {
721 /* if we don't know about it, user user defined, always allow modify */
722 SFTKModifyType mtype = SFTK_ALWAYS;
723
724 switch (type) {
725 /* NEVER */
726 case CKA_CLASS:
727 case CKA_CERTIFICATE_TYPE:
728 case CKA_KEY_TYPE:
729 case CKA_MODULUS:
730 case CKA_MODULUS_BITS:
731 case CKA_PUBLIC_EXPONENT:
732 case CKA_PRIVATE_EXPONENT:
733 case CKA_PRIME:
734 case CKA_BASE:
735 case CKA_PRIME_1:
736 case CKA_PRIME_2:
737 case CKA_EXPONENT_1:
738 case CKA_EXPONENT_2:
739 case CKA_COEFFICIENT:
740 case CKA_VALUE_LEN:
741 case CKA_ALWAYS_SENSITIVE:
742 case CKA_NEVER_EXTRACTABLE:
743 case CKA_NSS_DB:
744 mtype = SFTK_NEVER;
745 break;
746
747 /* ONCOPY */
748 case CKA_TOKEN:
749 case CKA_PRIVATE:
750 case CKA_MODIFIABLE:
751 mtype = SFTK_ONCOPY;
752 break;
753
754 /* SENSITIVE */
755 case CKA_SENSITIVE:
756 case CKA_EXTRACTABLE:
757 mtype = SFTK_SENSITIVE;
758 break;
759
760 /* ALWAYS */
761 case CKA_LABEL:
762 case CKA_APPLICATION:
763 case CKA_ID:
764 case CKA_SERIAL_NUMBER:
765 case CKA_START_DATE:
766 case CKA_END_DATE:
767 case CKA_DERIVE:
768 case CKA_ENCRYPT:
769 case CKA_DECRYPT:
770 case CKA_SIGN:
771 case CKA_VERIFY:
772 case CKA_SIGN_RECOVER:
773 case CKA_VERIFY_RECOVER:
774 case CKA_WRAP:
775 case CKA_UNWRAP:
776 mtype = SFTK_ALWAYS;
777 break;
778
779 /* DEPENDS ON CLASS */
780 case CKA_VALUE:
781 mtype = (inClass == CKO_DATA) ? SFTK_ALWAYS : SFTK_NEVER;
782 break;
783
784 case CKA_SUBPRIME:
785 /* allow the CKA_SUBPRIME to be added to dh private keys */
786 mtype = (inClass == CKO_PRIVATE_KEY) ? SFTK_ALWAYS : SFTK_NEVER;
787 break;
788
789 case CKA_SUBJECT:
790 mtype = (inClass == CKO_CERTIFICATE) ? SFTK_NEVER : SFTK_ALWAYS;
791 break;
792 default:
793 break;
794 }
795 return mtype;
796 }
797
798 /* decode if a particular attribute is sensitive (cannot be read
799 * back to the user of if the object is set to SENSITIVE) */
800 PRBool
sftk_isSensitive(CK_ATTRIBUTE_TYPE type,CK_OBJECT_CLASS inClass)801 sftk_isSensitive(CK_ATTRIBUTE_TYPE type, CK_OBJECT_CLASS inClass)
802 {
803 switch (type) {
804 /* ALWAYS */
805 case CKA_PRIVATE_EXPONENT:
806 case CKA_PRIME_1:
807 case CKA_PRIME_2:
808 case CKA_EXPONENT_1:
809 case CKA_EXPONENT_2:
810 case CKA_COEFFICIENT:
811 return PR_TRUE;
812
813 /* DEPENDS ON CLASS */
814 case CKA_VALUE:
815 /* PRIVATE and SECRET KEYS have SENSITIVE values */
816 return (PRBool)((inClass == CKO_PRIVATE_KEY) || (inClass == CKO_SECRET_KEY));
817
818 default:
819 break;
820 }
821 return PR_FALSE;
822 }
823
824 /*
825 * copy an attribute into a SECItem. Secitem is allocated in the specified
826 * arena.
827 */
828 CK_RV
sftk_Attribute2SecItem(PLArenaPool * arena,SECItem * item,SFTKObject * object,CK_ATTRIBUTE_TYPE type)829 sftk_Attribute2SecItem(PLArenaPool *arena, SECItem *item, SFTKObject *object,
830 CK_ATTRIBUTE_TYPE type)
831 {
832 int len;
833 SFTKAttribute *attribute;
834
835 attribute = sftk_FindAttribute(object, type);
836 if (attribute == NULL)
837 return CKR_TEMPLATE_INCOMPLETE;
838 len = attribute->attrib.ulValueLen;
839
840 if (arena) {
841 item->data = (unsigned char *)PORT_ArenaAlloc(arena, len);
842 } else {
843 item->data = (unsigned char *)PORT_Alloc(len);
844 }
845 if (item->data == NULL) {
846 sftk_FreeAttribute(attribute);
847 return CKR_HOST_MEMORY;
848 }
849 item->len = len;
850 PORT_Memcpy(item->data, attribute->attrib.pValue, len);
851 sftk_FreeAttribute(attribute);
852 return CKR_OK;
853 }
854
855 CK_RV
sftk_GetULongAttribute(SFTKObject * object,CK_ATTRIBUTE_TYPE type,CK_ULONG * longData)856 sftk_GetULongAttribute(SFTKObject *object, CK_ATTRIBUTE_TYPE type,
857 CK_ULONG *longData)
858 {
859 SFTKAttribute *attribute;
860
861 attribute = sftk_FindAttribute(object, type);
862 if (attribute == NULL)
863 return CKR_TEMPLATE_INCOMPLETE;
864
865 if (attribute->attrib.ulValueLen != sizeof(CK_ULONG)) {
866 return CKR_ATTRIBUTE_VALUE_INVALID;
867 }
868
869 *longData = *(CK_ULONG *)attribute->attrib.pValue;
870 sftk_FreeAttribute(attribute);
871 return CKR_OK;
872 }
873
874 void
sftk_DeleteAttributeType(SFTKObject * object,CK_ATTRIBUTE_TYPE type)875 sftk_DeleteAttributeType(SFTKObject *object, CK_ATTRIBUTE_TYPE type)
876 {
877 SFTKAttribute *attribute;
878 attribute = sftk_FindAttribute(object, type);
879 if (attribute == NULL)
880 return;
881 sftk_DeleteAttribute(object, attribute);
882 sftk_DestroyAttribute(attribute);
883 }
884
885 CK_RV
sftk_AddAttributeType(SFTKObject * object,CK_ATTRIBUTE_TYPE type,const void * valPtr,CK_ULONG length)886 sftk_AddAttributeType(SFTKObject *object, CK_ATTRIBUTE_TYPE type,
887 const void *valPtr, CK_ULONG length)
888 {
889 SFTKAttribute *attribute;
890 attribute = sftk_NewAttribute(object, type, valPtr, length);
891 if (attribute == NULL) {
892 return CKR_HOST_MEMORY;
893 }
894 sftk_AddAttribute(object, attribute);
895 return CKR_OK;
896 }
897
898 /*
899 * ******************** Object Utilities *******************************
900 */
901
902 /* must be called holding sftk_tokenKeyLock(slot) */
903 static SECItem *
sftk_lookupTokenKeyByHandle(SFTKSlot * slot,CK_OBJECT_HANDLE handle)904 sftk_lookupTokenKeyByHandle(SFTKSlot *slot, CK_OBJECT_HANDLE handle)
905 {
906 return (SECItem *)PL_HashTableLookup(slot->tokObjHashTable, (void *)handle);
907 }
908
909 /*
910 * use the refLock. This operations should be very rare, so the added
911 * contention on the ref lock should be lower than the overhead of adding
912 * a new lock. We use separate functions for this just in case I'm wrong.
913 */
914 static void
sftk_tokenKeyLock(SFTKSlot * slot)915 sftk_tokenKeyLock(SFTKSlot *slot)
916 {
917 SKIP_AFTER_FORK(PZ_Lock(slot->objectLock));
918 }
919
920 static void
sftk_tokenKeyUnlock(SFTKSlot * slot)921 sftk_tokenKeyUnlock(SFTKSlot *slot)
922 {
923 SKIP_AFTER_FORK(PZ_Unlock(slot->objectLock));
924 }
925
926 static PRIntn
sftk_freeHashItem(PLHashEntry * entry,PRIntn index,void * arg)927 sftk_freeHashItem(PLHashEntry *entry, PRIntn index, void *arg)
928 {
929 SECItem *item = (SECItem *)entry->value;
930
931 SECITEM_FreeItem(item, PR_TRUE);
932 return HT_ENUMERATE_NEXT;
933 }
934
935 CK_RV
SFTK_ClearTokenKeyHashTable(SFTKSlot * slot)936 SFTK_ClearTokenKeyHashTable(SFTKSlot *slot)
937 {
938 sftk_tokenKeyLock(slot);
939 PORT_Assert(!slot->present);
940 PL_HashTableEnumerateEntries(slot->tokObjHashTable, sftk_freeHashItem, NULL);
941 sftk_tokenKeyUnlock(slot);
942 return CKR_OK;
943 }
944
945 /* allocation hooks that allow us to recycle old object structures */
946 static SFTKObjectFreeList sessionObjectList = { NULL, NULL, 0 };
947 static SFTKObjectFreeList tokenObjectList = { NULL, NULL, 0 };
948
949 SFTKObject *
sftk_GetObjectFromList(PRBool * hasLocks,PRBool optimizeSpace,SFTKObjectFreeList * list,unsigned int hashSize,PRBool isSessionObject)950 sftk_GetObjectFromList(PRBool *hasLocks, PRBool optimizeSpace,
951 SFTKObjectFreeList *list, unsigned int hashSize, PRBool isSessionObject)
952 {
953 SFTKObject *object;
954 int size = 0;
955
956 if (!optimizeSpace) {
957 PZ_Lock(list->lock);
958 object = list->head;
959 if (object) {
960 list->head = object->next;
961 list->count--;
962 }
963 PZ_Unlock(list->lock);
964 if (object) {
965 object->next = object->prev = NULL;
966 *hasLocks = PR_TRUE;
967 return object;
968 }
969 }
970 size = isSessionObject ? sizeof(SFTKSessionObject) + hashSize * sizeof(SFTKAttribute *) : sizeof(SFTKTokenObject);
971
972 object = (SFTKObject *)PORT_ZAlloc(size);
973 if (isSessionObject && object) {
974 ((SFTKSessionObject *)object)->hashSize = hashSize;
975 }
976 *hasLocks = PR_FALSE;
977 return object;
978 }
979
980 static void
sftk_PutObjectToList(SFTKObject * object,SFTKObjectFreeList * list,PRBool isSessionObject)981 sftk_PutObjectToList(SFTKObject *object, SFTKObjectFreeList *list,
982 PRBool isSessionObject)
983 {
984
985 /* the code below is equivalent to :
986 * optimizeSpace = isSessionObject ? object->optimizeSpace : PR_FALSE;
987 * just faster.
988 */
989 PRBool optimizeSpace = isSessionObject &&
990 ((SFTKSessionObject *)object)->optimizeSpace;
991 if (object->refLock && !optimizeSpace && (list->count < MAX_OBJECT_LIST_SIZE)) {
992 PZ_Lock(list->lock);
993 object->next = list->head;
994 list->head = object;
995 list->count++;
996 PZ_Unlock(list->lock);
997 return;
998 }
999 if (isSessionObject) {
1000 SFTKSessionObject *so = (SFTKSessionObject *)object;
1001 PZ_DestroyLock(so->attributeLock);
1002 so->attributeLock = NULL;
1003 }
1004 if (object->refLock) {
1005 PZ_DestroyLock(object->refLock);
1006 object->refLock = NULL;
1007 }
1008 PORT_Free(object);
1009 }
1010
1011 static SFTKObject *
sftk_freeObjectData(SFTKObject * object)1012 sftk_freeObjectData(SFTKObject *object)
1013 {
1014 SFTKObject *next = object->next;
1015
1016 PORT_Free(object);
1017 return next;
1018 }
1019
1020 static void
sftk_InitFreeList(SFTKObjectFreeList * list)1021 sftk_InitFreeList(SFTKObjectFreeList *list)
1022 {
1023 if (!list->lock) {
1024 list->lock = PZ_NewLock(nssILockObject);
1025 }
1026 }
1027
1028 void
sftk_InitFreeLists(void)1029 sftk_InitFreeLists(void)
1030 {
1031 sftk_InitFreeList(&sessionObjectList);
1032 sftk_InitFreeList(&tokenObjectList);
1033 }
1034
1035 static void
sftk_CleanupFreeList(SFTKObjectFreeList * list,PRBool isSessionList)1036 sftk_CleanupFreeList(SFTKObjectFreeList *list, PRBool isSessionList)
1037 {
1038 SFTKObject *object;
1039
1040 if (!list->lock) {
1041 return;
1042 }
1043 SKIP_AFTER_FORK(PZ_Lock(list->lock));
1044 for (object = list->head; object != NULL;
1045 object = sftk_freeObjectData(object)) {
1046 PZ_DestroyLock(object->refLock);
1047 if (isSessionList) {
1048 PZ_DestroyLock(((SFTKSessionObject *)object)->attributeLock);
1049 }
1050 }
1051 list->count = 0;
1052 list->head = NULL;
1053 SKIP_AFTER_FORK(PZ_Unlock(list->lock));
1054 SKIP_AFTER_FORK(PZ_DestroyLock(list->lock));
1055 list->lock = NULL;
1056 }
1057
1058 void
sftk_CleanupFreeLists(void)1059 sftk_CleanupFreeLists(void)
1060 {
1061 sftk_CleanupFreeList(&sessionObjectList, PR_TRUE);
1062 sftk_CleanupFreeList(&tokenObjectList, PR_FALSE);
1063 }
1064
1065 /*
1066 * Create a new object
1067 */
1068 SFTKObject *
sftk_NewObject(SFTKSlot * slot)1069 sftk_NewObject(SFTKSlot *slot)
1070 {
1071 SFTKObject *object;
1072 SFTKSessionObject *sessObject;
1073 PRBool hasLocks = PR_FALSE;
1074 unsigned int i;
1075 unsigned int hashSize = 0;
1076
1077 hashSize = (slot->optimizeSpace) ? SPACE_ATTRIBUTE_HASH_SIZE : TIME_ATTRIBUTE_HASH_SIZE;
1078
1079 object = sftk_GetObjectFromList(&hasLocks, slot->optimizeSpace,
1080 &sessionObjectList, hashSize, PR_TRUE);
1081 if (object == NULL) {
1082 return NULL;
1083 }
1084 sessObject = (SFTKSessionObject *)object;
1085 sessObject->nextAttr = 0;
1086
1087 for (i = 0; i < MAX_OBJS_ATTRS; i++) {
1088 sessObject->attrList[i].attrib.pValue = NULL;
1089 sessObject->attrList[i].freeData = PR_FALSE;
1090 }
1091 sessObject->optimizeSpace = slot->optimizeSpace;
1092
1093 object->handle = 0;
1094 object->next = object->prev = NULL;
1095 object->slot = slot;
1096 object->isFIPS = sftk_isFIPS(slot->slotID);
1097
1098 object->refCount = 1;
1099 sessObject->sessionList.next = NULL;
1100 sessObject->sessionList.prev = NULL;
1101 sessObject->sessionList.parent = object;
1102 sessObject->session = NULL;
1103 sessObject->wasDerived = PR_FALSE;
1104 if (!hasLocks)
1105 object->refLock = PZ_NewLock(nssILockRefLock);
1106 if (object->refLock == NULL) {
1107 PORT_Free(object);
1108 return NULL;
1109 }
1110 if (!hasLocks)
1111 sessObject->attributeLock = PZ_NewLock(nssILockAttribute);
1112 if (sessObject->attributeLock == NULL) {
1113 PZ_DestroyLock(object->refLock);
1114 PORT_Free(object);
1115 return NULL;
1116 }
1117 for (i = 0; i < sessObject->hashSize; i++) {
1118 sessObject->head[i] = NULL;
1119 }
1120 object->objectInfo = NULL;
1121 object->infoFree = NULL;
1122 return object;
1123 }
1124
1125 static CK_RV
sftk_DestroySessionObjectData(SFTKSessionObject * so)1126 sftk_DestroySessionObjectData(SFTKSessionObject *so)
1127 {
1128 int i;
1129
1130 for (i = 0; i < MAX_OBJS_ATTRS; i++) {
1131 unsigned char *value = so->attrList[i].attrib.pValue;
1132 if (value) {
1133 PORT_Memset(value, 0, so->attrList[i].attrib.ulValueLen);
1134 if (so->attrList[i].freeData) {
1135 PORT_Free(value);
1136 }
1137 so->attrList[i].attrib.pValue = NULL;
1138 so->attrList[i].freeData = PR_FALSE;
1139 }
1140 }
1141 /* PZ_DestroyLock(so->attributeLock);*/
1142 return CKR_OK;
1143 }
1144
1145 /*
1146 * free all the data associated with an object. Object reference count must
1147 * be 'zero'.
1148 */
1149 static CK_RV
sftk_DestroyObject(SFTKObject * object)1150 sftk_DestroyObject(SFTKObject *object)
1151 {
1152 CK_RV crv = CKR_OK;
1153 SFTKSessionObject *so = sftk_narrowToSessionObject(object);
1154 SFTKTokenObject *to = sftk_narrowToTokenObject(object);
1155
1156 PORT_Assert(object->refCount == 0);
1157
1158 /* delete the database value */
1159 if (to) {
1160 if (to->dbKey.data) {
1161 PORT_Free(to->dbKey.data);
1162 to->dbKey.data = NULL;
1163 }
1164 }
1165 if (so) {
1166 sftk_DestroySessionObjectData(so);
1167 }
1168 if (object->objectInfo) {
1169 (*object->infoFree)(object->objectInfo);
1170 object->objectInfo = NULL;
1171 object->infoFree = NULL;
1172 }
1173 if (so) {
1174 sftk_PutObjectToList(object, &sessionObjectList, PR_TRUE);
1175 } else {
1176 sftk_PutObjectToList(object, &tokenObjectList, PR_FALSE);
1177 }
1178 return crv;
1179 }
1180
1181 void
sftk_ReferenceObject(SFTKObject * object)1182 sftk_ReferenceObject(SFTKObject *object)
1183 {
1184 PZ_Lock(object->refLock);
1185 object->refCount++;
1186 PZ_Unlock(object->refLock);
1187 }
1188
1189 static SFTKObject *
sftk_ObjectFromHandleOnSlot(CK_OBJECT_HANDLE handle,SFTKSlot * slot)1190 sftk_ObjectFromHandleOnSlot(CK_OBJECT_HANDLE handle, SFTKSlot *slot)
1191 {
1192 SFTKObject *object;
1193 PRUint32 index = sftk_hash(handle, slot->sessObjHashSize);
1194
1195 if (sftk_isToken(handle)) {
1196 return sftk_NewTokenObject(slot, NULL, handle);
1197 }
1198
1199 PZ_Lock(slot->objectLock);
1200 sftkqueue_find2(object, handle, index, slot->sessObjHashTable);
1201 if (object) {
1202 sftk_ReferenceObject(object);
1203 }
1204 PZ_Unlock(slot->objectLock);
1205
1206 return (object);
1207 }
1208 /*
1209 * look up and object structure from a handle. OBJECT_Handles only make
1210 * sense in terms of a given session. make a reference to that object
1211 * structure returned.
1212 */
1213 SFTKObject *
sftk_ObjectFromHandle(CK_OBJECT_HANDLE handle,SFTKSession * session)1214 sftk_ObjectFromHandle(CK_OBJECT_HANDLE handle, SFTKSession *session)
1215 {
1216 SFTKSlot *slot = sftk_SlotFromSession(session);
1217
1218 return sftk_ObjectFromHandleOnSlot(handle, slot);
1219 }
1220
1221 /*
1222 * release a reference to an object handle
1223 */
1224 SFTKFreeStatus
sftk_FreeObject(SFTKObject * object)1225 sftk_FreeObject(SFTKObject *object)
1226 {
1227 PRBool destroy = PR_FALSE;
1228 CK_RV crv;
1229
1230 PZ_Lock(object->refLock);
1231 if (object->refCount == 1)
1232 destroy = PR_TRUE;
1233 object->refCount--;
1234 PZ_Unlock(object->refLock);
1235
1236 if (destroy) {
1237 crv = sftk_DestroyObject(object);
1238 if (crv != CKR_OK) {
1239 return SFTK_DestroyFailure;
1240 }
1241 return SFTK_Destroyed;
1242 }
1243 return SFTK_Busy;
1244 }
1245
1246 /*
1247 * add an object to a slot and session queue. These two functions
1248 * adopt the object.
1249 */
1250 void
sftk_AddSlotObject(SFTKSlot * slot,SFTKObject * object)1251 sftk_AddSlotObject(SFTKSlot *slot, SFTKObject *object)
1252 {
1253 PRUint32 index = sftk_hash(object->handle, slot->sessObjHashSize);
1254 sftkqueue_init_element(object);
1255 PZ_Lock(slot->objectLock);
1256 sftkqueue_add2(object, object->handle, index, slot->sessObjHashTable);
1257 PZ_Unlock(slot->objectLock);
1258 }
1259
1260 void
sftk_AddObject(SFTKSession * session,SFTKObject * object)1261 sftk_AddObject(SFTKSession *session, SFTKObject *object)
1262 {
1263 SFTKSlot *slot = sftk_SlotFromSession(session);
1264 SFTKSessionObject *so = sftk_narrowToSessionObject(object);
1265
1266 if (so) {
1267 PZ_Lock(session->objectLock);
1268 sftkqueue_add(&so->sessionList, 0, session->objects, 0);
1269 so->session = session;
1270 PZ_Unlock(session->objectLock);
1271 }
1272 sftk_AddSlotObject(slot, object);
1273 sftk_ReferenceObject(object);
1274 }
1275
1276 /*
1277 * delete an object from a slot and session queue
1278 */
1279 CK_RV
sftk_DeleteObject(SFTKSession * session,SFTKObject * object)1280 sftk_DeleteObject(SFTKSession *session, SFTKObject *object)
1281 {
1282 SFTKSlot *slot = sftk_SlotFromSession(session);
1283 SFTKSessionObject *so = sftk_narrowToSessionObject(object);
1284 CK_RV crv = CKR_OK;
1285 PRUint32 index = sftk_hash(object->handle, slot->sessObjHashSize);
1286
1287 /* Handle Token case */
1288 if (so && so->session) {
1289 session = so->session;
1290 PZ_Lock(session->objectLock);
1291 sftkqueue_delete(&so->sessionList, 0, session->objects, 0);
1292 PZ_Unlock(session->objectLock);
1293 PZ_Lock(slot->objectLock);
1294 sftkqueue_delete2(object, object->handle, index, slot->sessObjHashTable);
1295 PZ_Unlock(slot->objectLock);
1296 sftkqueue_clear_deleted_element(object);
1297 sftk_FreeObject(object); /* free the reference owned by the queue */
1298 } else {
1299 SFTKDBHandle *handle = sftk_getDBForTokenObject(slot, object->handle);
1300 #ifdef DEBUG
1301 SFTKTokenObject *to = sftk_narrowToTokenObject(object);
1302 PORT_Assert(to);
1303 #endif
1304 crv = sftkdb_DestroyObject(handle, object->handle, object->objclass);
1305 sftk_freeDB(handle);
1306 }
1307 return crv;
1308 }
1309
1310 /*
1311 * Token objects don't explicitly store their attributes, so we need to know
1312 * what attributes make up a particular token object before we can copy it.
1313 * below are the tables by object type.
1314 */
1315 static const CK_ATTRIBUTE_TYPE commonAttrs[] = {
1316 CKA_CLASS, CKA_TOKEN, CKA_PRIVATE, CKA_LABEL, CKA_MODIFIABLE
1317 };
1318 static const CK_ULONG commonAttrsCount =
1319 sizeof(commonAttrs) / sizeof(commonAttrs[0]);
1320
1321 static const CK_ATTRIBUTE_TYPE commonKeyAttrs[] = {
1322 CKA_ID, CKA_START_DATE, CKA_END_DATE, CKA_DERIVE, CKA_LOCAL, CKA_KEY_TYPE
1323 };
1324 static const CK_ULONG commonKeyAttrsCount =
1325 sizeof(commonKeyAttrs) / sizeof(commonKeyAttrs[0]);
1326
1327 static const CK_ATTRIBUTE_TYPE secretKeyAttrs[] = {
1328 CKA_SENSITIVE, CKA_EXTRACTABLE, CKA_ENCRYPT, CKA_DECRYPT, CKA_SIGN,
1329 CKA_VERIFY, CKA_WRAP, CKA_UNWRAP, CKA_VALUE
1330 };
1331 static const CK_ULONG secretKeyAttrsCount =
1332 sizeof(secretKeyAttrs) / sizeof(secretKeyAttrs[0]);
1333
1334 static const CK_ATTRIBUTE_TYPE commonPubKeyAttrs[] = {
1335 CKA_ENCRYPT, CKA_VERIFY, CKA_VERIFY_RECOVER, CKA_WRAP, CKA_SUBJECT
1336 };
1337 static const CK_ULONG commonPubKeyAttrsCount =
1338 sizeof(commonPubKeyAttrs) / sizeof(commonPubKeyAttrs[0]);
1339
1340 static const CK_ATTRIBUTE_TYPE rsaPubKeyAttrs[] = {
1341 CKA_MODULUS, CKA_PUBLIC_EXPONENT
1342 };
1343 static const CK_ULONG rsaPubKeyAttrsCount =
1344 sizeof(rsaPubKeyAttrs) / sizeof(rsaPubKeyAttrs[0]);
1345
1346 static const CK_ATTRIBUTE_TYPE dsaPubKeyAttrs[] = {
1347 CKA_SUBPRIME, CKA_PRIME, CKA_BASE, CKA_VALUE
1348 };
1349 static const CK_ULONG dsaPubKeyAttrsCount =
1350 sizeof(dsaPubKeyAttrs) / sizeof(dsaPubKeyAttrs[0]);
1351
1352 static const CK_ATTRIBUTE_TYPE dhPubKeyAttrs[] = {
1353 CKA_PRIME, CKA_BASE, CKA_VALUE
1354 };
1355 static const CK_ULONG dhPubKeyAttrsCount =
1356 sizeof(dhPubKeyAttrs) / sizeof(dhPubKeyAttrs[0]);
1357 static const CK_ATTRIBUTE_TYPE ecPubKeyAttrs[] = {
1358 CKA_EC_PARAMS, CKA_EC_POINT
1359 };
1360 static const CK_ULONG ecPubKeyAttrsCount =
1361 sizeof(ecPubKeyAttrs) / sizeof(ecPubKeyAttrs[0]);
1362
1363 static const CK_ATTRIBUTE_TYPE commonPrivKeyAttrs[] = {
1364 CKA_DECRYPT, CKA_SIGN, CKA_SIGN_RECOVER, CKA_UNWRAP, CKA_SUBJECT,
1365 CKA_SENSITIVE, CKA_EXTRACTABLE, CKA_NSS_DB, CKA_PUBLIC_KEY_INFO
1366 };
1367 static const CK_ULONG commonPrivKeyAttrsCount =
1368 sizeof(commonPrivKeyAttrs) / sizeof(commonPrivKeyAttrs[0]);
1369
1370 static const CK_ATTRIBUTE_TYPE rsaPrivKeyAttrs[] = {
1371 CKA_MODULUS, CKA_PUBLIC_EXPONENT, CKA_PRIVATE_EXPONENT,
1372 CKA_PRIME_1, CKA_PRIME_2, CKA_EXPONENT_1, CKA_EXPONENT_2, CKA_COEFFICIENT
1373 };
1374 static const CK_ULONG rsaPrivKeyAttrsCount =
1375 sizeof(rsaPrivKeyAttrs) / sizeof(rsaPrivKeyAttrs[0]);
1376
1377 static const CK_ATTRIBUTE_TYPE dsaPrivKeyAttrs[] = {
1378 CKA_SUBPRIME, CKA_PRIME, CKA_BASE, CKA_VALUE
1379 };
1380 static const CK_ULONG dsaPrivKeyAttrsCount =
1381 sizeof(dsaPrivKeyAttrs) / sizeof(dsaPrivKeyAttrs[0]);
1382
1383 static const CK_ATTRIBUTE_TYPE dhPrivKeyAttrs[] = {
1384 CKA_PRIME, CKA_BASE, CKA_VALUE
1385 };
1386 static const CK_ULONG dhPrivKeyAttrsCount =
1387 sizeof(dhPrivKeyAttrs) / sizeof(dhPrivKeyAttrs[0]);
1388 static const CK_ATTRIBUTE_TYPE ecPrivKeyAttrs[] = {
1389 CKA_EC_PARAMS, CKA_VALUE
1390 };
1391 static const CK_ULONG ecPrivKeyAttrsCount =
1392 sizeof(ecPrivKeyAttrs) / sizeof(ecPrivKeyAttrs[0]);
1393
1394 static const CK_ATTRIBUTE_TYPE certAttrs[] = {
1395 CKA_CERTIFICATE_TYPE, CKA_VALUE, CKA_SUBJECT, CKA_ISSUER, CKA_SERIAL_NUMBER
1396 };
1397 static const CK_ULONG certAttrsCount =
1398 sizeof(certAttrs) / sizeof(certAttrs[0]);
1399
1400 static const CK_ATTRIBUTE_TYPE trustAttrs[] = {
1401 CKA_ISSUER, CKA_SERIAL_NUMBER, CKA_CERT_SHA1_HASH, CKA_CERT_MD5_HASH,
1402 CKA_TRUST_SERVER_AUTH, CKA_TRUST_CLIENT_AUTH, CKA_TRUST_EMAIL_PROTECTION,
1403 CKA_TRUST_CODE_SIGNING, CKA_TRUST_STEP_UP_APPROVED
1404 };
1405 static const CK_ULONG trustAttrsCount =
1406 sizeof(trustAttrs) / sizeof(trustAttrs[0]);
1407
1408 static const CK_ATTRIBUTE_TYPE smimeAttrs[] = {
1409 CKA_SUBJECT, CKA_NSS_EMAIL, CKA_NSS_SMIME_TIMESTAMP, CKA_VALUE
1410 };
1411 static const CK_ULONG smimeAttrsCount =
1412 sizeof(smimeAttrs) / sizeof(smimeAttrs[0]);
1413
1414 static const CK_ATTRIBUTE_TYPE crlAttrs[] = {
1415 CKA_SUBJECT, CKA_VALUE, CKA_NSS_URL, CKA_NSS_KRL
1416 };
1417 static const CK_ULONG crlAttrsCount =
1418 sizeof(crlAttrs) / sizeof(crlAttrs[0]);
1419
1420 /* copy an object based on it's table */
1421 CK_RV
stfk_CopyTokenAttributes(SFTKObject * destObject,SFTKTokenObject * src_to,const CK_ATTRIBUTE_TYPE * attrArray,CK_ULONG attrCount)1422 stfk_CopyTokenAttributes(SFTKObject *destObject, SFTKTokenObject *src_to,
1423 const CK_ATTRIBUTE_TYPE *attrArray, CK_ULONG attrCount)
1424 {
1425 SFTKAttribute *attribute;
1426 SFTKAttribute *newAttribute;
1427 CK_RV crv = CKR_OK;
1428 unsigned int i;
1429
1430 for (i = 0; i < attrCount; i++) {
1431 if (!sftk_hasAttribute(destObject, attrArray[i])) {
1432 attribute = sftk_FindAttribute(&src_to->obj, attrArray[i]);
1433 if (!attribute) {
1434 continue; /* return CKR_ATTRIBUTE_VALUE_INVALID; */
1435 }
1436 /* we need to copy the attribute since each attribute
1437 * only has one set of link list pointers */
1438 newAttribute = sftk_NewAttribute(destObject,
1439 sftk_attr_expand(&attribute->attrib));
1440 sftk_FreeAttribute(attribute); /* free the old attribute */
1441 if (!newAttribute) {
1442 return CKR_HOST_MEMORY;
1443 }
1444 sftk_AddAttribute(destObject, newAttribute);
1445 }
1446 }
1447 return crv;
1448 }
1449
1450 CK_RV
stfk_CopyTokenPrivateKey(SFTKObject * destObject,SFTKTokenObject * src_to)1451 stfk_CopyTokenPrivateKey(SFTKObject *destObject, SFTKTokenObject *src_to)
1452 {
1453 CK_RV crv;
1454 CK_KEY_TYPE key_type;
1455 SFTKAttribute *attribute;
1456
1457 /* copy the common attributes for all keys first */
1458 crv = stfk_CopyTokenAttributes(destObject, src_to, commonKeyAttrs,
1459 commonKeyAttrsCount);
1460 if (crv != CKR_OK) {
1461 goto fail;
1462 }
1463 /* copy the common attributes for all private keys next */
1464 crv = stfk_CopyTokenAttributes(destObject, src_to, commonPrivKeyAttrs,
1465 commonPrivKeyAttrsCount);
1466 if (crv != CKR_OK) {
1467 goto fail;
1468 }
1469 attribute = sftk_FindAttribute(&src_to->obj, CKA_KEY_TYPE);
1470 PORT_Assert(attribute); /* if it wasn't here, ww should have failed
1471 * copying the common attributes */
1472 if (!attribute) {
1473 /* OK, so CKR_ATTRIBUTE_VALUE_INVALID is the immediate error, but
1474 * the fact is, the only reason we couldn't get the attribute would
1475 * be a memory error or database error (an error in the 'device').
1476 * if we have a database error code, we could return it here */
1477 crv = CKR_DEVICE_ERROR;
1478 goto fail;
1479 }
1480 key_type = *(CK_KEY_TYPE *)attribute->attrib.pValue;
1481 sftk_FreeAttribute(attribute);
1482
1483 /* finally copy the attributes for various private key types */
1484 switch (key_type) {
1485 case CKK_RSA:
1486 crv = stfk_CopyTokenAttributes(destObject, src_to, rsaPrivKeyAttrs,
1487 rsaPrivKeyAttrsCount);
1488 break;
1489 case CKK_DSA:
1490 crv = stfk_CopyTokenAttributes(destObject, src_to, dsaPrivKeyAttrs,
1491 dsaPrivKeyAttrsCount);
1492 break;
1493 case CKK_DH:
1494 crv = stfk_CopyTokenAttributes(destObject, src_to, dhPrivKeyAttrs,
1495 dhPrivKeyAttrsCount);
1496 break;
1497 case CKK_EC:
1498 crv = stfk_CopyTokenAttributes(destObject, src_to, ecPrivKeyAttrs,
1499 ecPrivKeyAttrsCount);
1500 break;
1501 default:
1502 crv = CKR_DEVICE_ERROR; /* shouldn't happen unless we store more types
1503 * of token keys into our database. */
1504 }
1505 fail:
1506 return crv;
1507 }
1508
1509 CK_RV
stfk_CopyTokenPublicKey(SFTKObject * destObject,SFTKTokenObject * src_to)1510 stfk_CopyTokenPublicKey(SFTKObject *destObject, SFTKTokenObject *src_to)
1511 {
1512 CK_RV crv;
1513 CK_KEY_TYPE key_type;
1514 SFTKAttribute *attribute;
1515
1516 /* copy the common attributes for all keys first */
1517 crv = stfk_CopyTokenAttributes(destObject, src_to, commonKeyAttrs,
1518 commonKeyAttrsCount);
1519 if (crv != CKR_OK) {
1520 goto fail;
1521 }
1522
1523 /* copy the common attributes for all public keys next */
1524 crv = stfk_CopyTokenAttributes(destObject, src_to, commonPubKeyAttrs,
1525 commonPubKeyAttrsCount);
1526 if (crv != CKR_OK) {
1527 goto fail;
1528 }
1529 attribute = sftk_FindAttribute(&src_to->obj, CKA_KEY_TYPE);
1530 PORT_Assert(attribute); /* if it wasn't here, ww should have failed
1531 * copying the common attributes */
1532 if (!attribute) {
1533 /* OK, so CKR_ATTRIBUTE_VALUE_INVALID is the immediate error, but
1534 * the fact is, the only reason we couldn't get the attribute would
1535 * be a memory error or database error (an error in the 'device').
1536 * if we have a database error code, we could return it here */
1537 crv = CKR_DEVICE_ERROR;
1538 goto fail;
1539 }
1540 key_type = *(CK_KEY_TYPE *)attribute->attrib.pValue;
1541 sftk_FreeAttribute(attribute);
1542
1543 /* finally copy the attributes for various public key types */
1544 switch (key_type) {
1545 case CKK_RSA:
1546 crv = stfk_CopyTokenAttributes(destObject, src_to, rsaPubKeyAttrs,
1547 rsaPubKeyAttrsCount);
1548 break;
1549 case CKK_DSA:
1550 crv = stfk_CopyTokenAttributes(destObject, src_to, dsaPubKeyAttrs,
1551 dsaPubKeyAttrsCount);
1552 break;
1553 case CKK_DH:
1554 crv = stfk_CopyTokenAttributes(destObject, src_to, dhPubKeyAttrs,
1555 dhPubKeyAttrsCount);
1556 break;
1557 case CKK_EC:
1558 crv = stfk_CopyTokenAttributes(destObject, src_to, ecPubKeyAttrs,
1559 ecPubKeyAttrsCount);
1560 break;
1561 default:
1562 crv = CKR_DEVICE_ERROR; /* shouldn't happen unless we store more types
1563 * of token keys into our database. */
1564 }
1565 fail:
1566 return crv;
1567 }
1568 CK_RV
stfk_CopyTokenSecretKey(SFTKObject * destObject,SFTKTokenObject * src_to)1569 stfk_CopyTokenSecretKey(SFTKObject *destObject, SFTKTokenObject *src_to)
1570 {
1571 CK_RV crv;
1572 crv = stfk_CopyTokenAttributes(destObject, src_to, commonKeyAttrs,
1573 commonKeyAttrsCount);
1574 if (crv != CKR_OK) {
1575 goto fail;
1576 }
1577 crv = stfk_CopyTokenAttributes(destObject, src_to, secretKeyAttrs,
1578 secretKeyAttrsCount);
1579 fail:
1580 return crv;
1581 }
1582
1583 /*
1584 * Copy a token object. We need to explicitly copy the relevant
1585 * attributes since token objects don't store those attributes in
1586 * the token itself.
1587 */
1588 CK_RV
sftk_CopyTokenObject(SFTKObject * destObject,SFTKObject * srcObject)1589 sftk_CopyTokenObject(SFTKObject *destObject, SFTKObject *srcObject)
1590 {
1591 SFTKTokenObject *src_to = sftk_narrowToTokenObject(srcObject);
1592 CK_RV crv;
1593
1594 PORT_Assert(src_to);
1595 if (src_to == NULL) {
1596 return CKR_DEVICE_ERROR; /* internal state inconsistant */
1597 }
1598
1599 crv = stfk_CopyTokenAttributes(destObject, src_to, commonAttrs,
1600 commonAttrsCount);
1601 if (crv != CKR_OK) {
1602 goto fail;
1603 }
1604 switch (src_to->obj.objclass) {
1605 case CKO_CERTIFICATE:
1606 crv = stfk_CopyTokenAttributes(destObject, src_to, certAttrs,
1607 certAttrsCount);
1608 break;
1609 case CKO_NSS_TRUST:
1610 crv = stfk_CopyTokenAttributes(destObject, src_to, trustAttrs,
1611 trustAttrsCount);
1612 break;
1613 case CKO_NSS_SMIME:
1614 crv = stfk_CopyTokenAttributes(destObject, src_to, smimeAttrs,
1615 smimeAttrsCount);
1616 break;
1617 case CKO_NSS_CRL:
1618 crv = stfk_CopyTokenAttributes(destObject, src_to, crlAttrs,
1619 crlAttrsCount);
1620 break;
1621 case CKO_PRIVATE_KEY:
1622 crv = stfk_CopyTokenPrivateKey(destObject, src_to);
1623 break;
1624 case CKO_PUBLIC_KEY:
1625 crv = stfk_CopyTokenPublicKey(destObject, src_to);
1626 break;
1627 case CKO_SECRET_KEY:
1628 crv = stfk_CopyTokenSecretKey(destObject, src_to);
1629 break;
1630 default:
1631 crv = CKR_DEVICE_ERROR; /* shouldn't happen unless we store more types
1632 * of token keys into our database. */
1633 }
1634 fail:
1635 return crv;
1636 }
1637
1638 /*
1639 * copy the attributes from one object to another. Don't overwrite existing
1640 * attributes. NOTE: This is a pretty expensive operation since it
1641 * grabs the attribute locks for the src object for a *long* time.
1642 */
1643 CK_RV
sftk_CopyObject(SFTKObject * destObject,SFTKObject * srcObject)1644 sftk_CopyObject(SFTKObject *destObject, SFTKObject *srcObject)
1645 {
1646 SFTKAttribute *attribute;
1647 SFTKSessionObject *src_so = sftk_narrowToSessionObject(srcObject);
1648 unsigned int i;
1649
1650 destObject->isFIPS = srcObject->isFIPS;
1651 if (src_so == NULL) {
1652 return sftk_CopyTokenObject(destObject, srcObject);
1653 }
1654
1655 PZ_Lock(src_so->attributeLock);
1656 for (i = 0; i < src_so->hashSize; i++) {
1657 attribute = src_so->head[i];
1658 do {
1659 if (attribute) {
1660 if (!sftk_hasAttribute(destObject, attribute->handle)) {
1661 /* we need to copy the attribute since each attribute
1662 * only has one set of link list pointers */
1663 SFTKAttribute *newAttribute = sftk_NewAttribute(
1664 destObject, sftk_attr_expand(&attribute->attrib));
1665 if (newAttribute == NULL) {
1666 PZ_Unlock(src_so->attributeLock);
1667 return CKR_HOST_MEMORY;
1668 }
1669 sftk_AddAttribute(destObject, newAttribute);
1670 }
1671 attribute = attribute->next;
1672 }
1673 } while (attribute != NULL);
1674 }
1675 PZ_Unlock(src_so->attributeLock);
1676
1677 return CKR_OK;
1678 }
1679
1680 /*
1681 * ******************** Search Utilities *******************************
1682 */
1683
1684 /* add an object to a search list */
1685 CK_RV
AddToList(SFTKObjectListElement ** list,SFTKObject * object)1686 AddToList(SFTKObjectListElement **list, SFTKObject *object)
1687 {
1688 SFTKObjectListElement *newElem =
1689 (SFTKObjectListElement *)PORT_Alloc(sizeof(SFTKObjectListElement));
1690
1691 if (newElem == NULL)
1692 return CKR_HOST_MEMORY;
1693
1694 newElem->next = *list;
1695 newElem->object = object;
1696 sftk_ReferenceObject(object);
1697
1698 *list = newElem;
1699 return CKR_OK;
1700 }
1701
1702 /* return true if the object matches the template */
1703 PRBool
sftk_objectMatch(SFTKObject * object,CK_ATTRIBUTE_PTR theTemplate,int count)1704 sftk_objectMatch(SFTKObject *object, CK_ATTRIBUTE_PTR theTemplate, int count)
1705 {
1706 int i;
1707
1708 for (i = 0; i < count; i++) {
1709 SFTKAttribute *attribute = sftk_FindAttribute(object, theTemplate[i].type);
1710 if (attribute == NULL) {
1711 return PR_FALSE;
1712 }
1713 if (attribute->attrib.ulValueLen == theTemplate[i].ulValueLen) {
1714 if (PORT_Memcmp(attribute->attrib.pValue, theTemplate[i].pValue,
1715 theTemplate[i].ulValueLen) == 0) {
1716 sftk_FreeAttribute(attribute);
1717 continue;
1718 }
1719 }
1720 sftk_FreeAttribute(attribute);
1721 return PR_FALSE;
1722 }
1723 return PR_TRUE;
1724 }
1725
1726 /* search through all the objects in the queue and return the template matches
1727 * in the object list.
1728 */
1729 CK_RV
sftk_searchObjectList(SFTKSearchResults * search,SFTKObject ** head,unsigned int size,PZLock * lock,CK_ATTRIBUTE_PTR theTemplate,int count,PRBool isLoggedIn)1730 sftk_searchObjectList(SFTKSearchResults *search, SFTKObject **head,
1731 unsigned int size, PZLock *lock, CK_ATTRIBUTE_PTR theTemplate,
1732 int count, PRBool isLoggedIn)
1733 {
1734 unsigned int i;
1735 SFTKObject *object;
1736 CK_RV crv = CKR_OK;
1737
1738 PZ_Lock(lock);
1739 for (i = 0; i < size; i++) {
1740 for (object = head[i]; object != NULL; object = object->next) {
1741 if (sftk_objectMatch(object, theTemplate, count)) {
1742 /* don't return objects that aren't yet visible */
1743 if ((!isLoggedIn) && sftk_isTrue(object, CKA_PRIVATE))
1744 continue;
1745 sftk_addHandle(search, object->handle);
1746 }
1747 }
1748 }
1749 PZ_Unlock(lock);
1750 return crv;
1751 }
1752
1753 /*
1754 * free a single list element. Return the Next object in the list.
1755 */
1756 SFTKObjectListElement *
sftk_FreeObjectListElement(SFTKObjectListElement * objectList)1757 sftk_FreeObjectListElement(SFTKObjectListElement *objectList)
1758 {
1759 SFTKObjectListElement *ol = objectList->next;
1760
1761 sftk_FreeObject(objectList->object);
1762 PORT_Free(objectList);
1763 return ol;
1764 }
1765
1766 /* free an entire object list */
1767 void
sftk_FreeObjectList(SFTKObjectListElement * objectList)1768 sftk_FreeObjectList(SFTKObjectListElement *objectList)
1769 {
1770 SFTKObjectListElement *ol;
1771
1772 for (ol = objectList; ol != NULL; ol = sftk_FreeObjectListElement(ol)) {
1773 }
1774 }
1775
1776 /*
1777 * free a search structure
1778 */
1779 void
sftk_FreeSearch(SFTKSearchResults * search)1780 sftk_FreeSearch(SFTKSearchResults *search)
1781 {
1782 if (search->handles) {
1783 PORT_Free(search->handles);
1784 }
1785 PORT_Free(search);
1786 }
1787
1788 /*
1789 * ******************** Session Utilities *******************************
1790 */
1791
1792 /* update the sessions state based in it's flags and wether or not it's
1793 * logged in */
1794 void
sftk_update_state(SFTKSlot * slot,SFTKSession * session)1795 sftk_update_state(SFTKSlot *slot, SFTKSession *session)
1796 {
1797 if (slot->isLoggedIn) {
1798 if (slot->ssoLoggedIn) {
1799 session->info.state = CKS_RW_SO_FUNCTIONS;
1800 } else if (session->info.flags & CKF_RW_SESSION) {
1801 session->info.state = CKS_RW_USER_FUNCTIONS;
1802 } else {
1803 session->info.state = CKS_RO_USER_FUNCTIONS;
1804 }
1805 } else {
1806 if (session->info.flags & CKF_RW_SESSION) {
1807 session->info.state = CKS_RW_PUBLIC_SESSION;
1808 } else {
1809 session->info.state = CKS_RO_PUBLIC_SESSION;
1810 }
1811 }
1812 }
1813
1814 /* update the state of all the sessions on a slot */
1815 void
sftk_update_all_states(SFTKSlot * slot)1816 sftk_update_all_states(SFTKSlot *slot)
1817 {
1818 unsigned int i;
1819 SFTKSession *session;
1820
1821 for (i = 0; i < slot->sessHashSize; i++) {
1822 PZLock *lock = SFTK_SESSION_LOCK(slot, i);
1823 PZ_Lock(lock);
1824 for (session = slot->head[i]; session; session = session->next) {
1825 sftk_update_state(slot, session);
1826 }
1827 PZ_Unlock(lock);
1828 }
1829 }
1830
1831 /*
1832 * context are cipher and digest contexts that are associated with a session
1833 */
1834 void
sftk_FreeContext(SFTKSessionContext * context)1835 sftk_FreeContext(SFTKSessionContext *context)
1836 {
1837 if (context->cipherInfo) {
1838 (*context->destroy)(context->cipherInfo, PR_TRUE);
1839 }
1840 if (context->hashInfo) {
1841 (*context->hashdestroy)(context->hashInfo, PR_TRUE);
1842 }
1843 if (context->key) {
1844 sftk_FreeObject(context->key);
1845 context->key = NULL;
1846 }
1847 PORT_Free(context);
1848 }
1849
1850 /*
1851 * create a new nession. NOTE: The session handle is not set, and the
1852 * session is not added to the slot's session queue.
1853 */
1854 SFTKSession *
sftk_NewSession(CK_SLOT_ID slotID,CK_NOTIFY notify,CK_VOID_PTR pApplication,CK_FLAGS flags)1855 sftk_NewSession(CK_SLOT_ID slotID, CK_NOTIFY notify, CK_VOID_PTR pApplication,
1856 CK_FLAGS flags)
1857 {
1858 SFTKSession *session;
1859 SFTKSlot *slot = sftk_SlotFromID(slotID, PR_FALSE);
1860
1861 if (slot == NULL)
1862 return NULL;
1863
1864 session = (SFTKSession *)PORT_Alloc(sizeof(SFTKSession));
1865 if (session == NULL)
1866 return NULL;
1867
1868 session->next = session->prev = NULL;
1869 session->enc_context = NULL;
1870 session->hash_context = NULL;
1871 session->sign_context = NULL;
1872 session->search = NULL;
1873 session->objectIDCount = 1;
1874 session->objectLock = PZ_NewLock(nssILockObject);
1875 if (session->objectLock == NULL) {
1876 PORT_Free(session);
1877 return NULL;
1878 }
1879 session->objects[0] = NULL;
1880
1881 session->slot = slot;
1882 session->notify = notify;
1883 session->appData = pApplication;
1884 session->info.flags = flags;
1885 session->info.slotID = slotID;
1886 session->info.ulDeviceError = 0;
1887 sftk_update_state(slot, session);
1888 /* no ops completed yet, so the last one couldn't be a FIPS op */
1889 session->lastOpWasFIPS = PR_FALSE;
1890 return session;
1891 }
1892
1893 /* free all the data associated with a session. */
1894 void
sftk_DestroySession(SFTKSession * session)1895 sftk_DestroySession(SFTKSession *session)
1896 {
1897 SFTKObjectList *op, *next;
1898
1899 /* clean out the attributes */
1900 /* since no one is referencing us, it's safe to walk the chain
1901 * without a lock */
1902 for (op = session->objects[0]; op != NULL; op = next) {
1903 next = op->next;
1904 /* paranoia */
1905 op->next = op->prev = NULL;
1906 sftk_DeleteObject(session, op->parent);
1907 }
1908 PZ_DestroyLock(session->objectLock);
1909 if (session->enc_context) {
1910 sftk_FreeContext(session->enc_context);
1911 }
1912 if (session->hash_context) {
1913 sftk_FreeContext(session->hash_context);
1914 }
1915 if (session->sign_context) {
1916 sftk_FreeContext(session->sign_context);
1917 }
1918 if (session->search) {
1919 sftk_FreeSearch(session->search);
1920 }
1921 PORT_Free(session);
1922 }
1923
1924 /*
1925 * look up a session structure from a session handle
1926 * generate a reference to it.
1927 */
1928 SFTKSession *
sftk_SessionFromHandle(CK_SESSION_HANDLE handle)1929 sftk_SessionFromHandle(CK_SESSION_HANDLE handle)
1930 {
1931 SFTKSlot *slot = sftk_SlotFromSessionHandle(handle);
1932 SFTKSession *session;
1933 PZLock *lock;
1934
1935 if (!slot)
1936 return NULL;
1937 lock = SFTK_SESSION_LOCK(slot, handle);
1938
1939 PZ_Lock(lock);
1940 sftkqueue_find(session, handle, slot->head, slot->sessHashSize);
1941 PZ_Unlock(lock);
1942
1943 return (session);
1944 }
1945
1946 /*
1947 * release a reference to a session handle. This method of using SFTKSessions
1948 * is deprecated, but the pattern should be retained until a future effort
1949 * to refactor all SFTKSession users at once is completed.
1950 */
1951 void
sftk_FreeSession(SFTKSession * session)1952 sftk_FreeSession(SFTKSession *session)
1953 {
1954 return;
1955 }
1956
1957 void
sftk_addHandle(SFTKSearchResults * search,CK_OBJECT_HANDLE handle)1958 sftk_addHandle(SFTKSearchResults *search, CK_OBJECT_HANDLE handle)
1959 {
1960 if (search->handles == NULL) {
1961 return;
1962 }
1963 if (search->size >= search->array_size) {
1964 search->array_size += NSC_SEARCH_BLOCK_SIZE;
1965 search->handles = (CK_OBJECT_HANDLE *)PORT_Realloc(search->handles,
1966 sizeof(CK_OBJECT_HANDLE) * search->array_size);
1967 if (search->handles == NULL) {
1968 return;
1969 }
1970 }
1971 search->handles[search->size] = handle;
1972 search->size++;
1973 }
1974
1975 static CK_RV
handleToClass(SFTKSlot * slot,CK_OBJECT_HANDLE handle,CK_OBJECT_CLASS * objClass)1976 handleToClass(SFTKSlot *slot, CK_OBJECT_HANDLE handle,
1977 CK_OBJECT_CLASS *objClass)
1978 {
1979 SFTKDBHandle *dbHandle = sftk_getDBForTokenObject(slot, handle);
1980 CK_ATTRIBUTE objClassTemplate;
1981 CK_RV crv;
1982
1983 *objClass = CKO_DATA;
1984 objClassTemplate.type = CKA_CLASS;
1985 objClassTemplate.pValue = objClass;
1986 objClassTemplate.ulValueLen = sizeof(*objClass);
1987 crv = sftkdb_GetAttributeValue(dbHandle, handle, &objClassTemplate, 1);
1988 sftk_freeDB(dbHandle);
1989 return crv;
1990 }
1991
1992 SFTKObject *
sftk_NewTokenObject(SFTKSlot * slot,SECItem * dbKey,CK_OBJECT_HANDLE handle)1993 sftk_NewTokenObject(SFTKSlot *slot, SECItem *dbKey, CK_OBJECT_HANDLE handle)
1994 {
1995 SFTKObject *object = NULL;
1996 PRBool hasLocks = PR_FALSE;
1997 CK_RV crv;
1998
1999 object = sftk_GetObjectFromList(&hasLocks, PR_FALSE, &tokenObjectList, 0,
2000 PR_FALSE);
2001 if (object == NULL) {
2002 return NULL;
2003 }
2004
2005 object->handle = handle;
2006 /* every object must have a class, if we can't get it, the object
2007 * doesn't exist */
2008 crv = handleToClass(slot, handle, &object->objclass);
2009 if (crv != CKR_OK) {
2010 goto loser;
2011 }
2012 object->slot = slot;
2013 object->isFIPS = sftk_isFIPS(slot->slotID);
2014 object->objectInfo = NULL;
2015 object->infoFree = NULL;
2016 if (!hasLocks) {
2017 object->refLock = PZ_NewLock(nssILockRefLock);
2018 }
2019 if (object->refLock == NULL) {
2020 goto loser;
2021 }
2022 object->refCount = 1;
2023
2024 return object;
2025 loser:
2026 (void)sftk_DestroyObject(object);
2027 return NULL;
2028 }
2029
2030 SFTKTokenObject *
sftk_convertSessionToToken(SFTKObject * obj)2031 sftk_convertSessionToToken(SFTKObject *obj)
2032 {
2033 SECItem *key;
2034 SFTKSessionObject *so = (SFTKSessionObject *)obj;
2035 SFTKTokenObject *to = sftk_narrowToTokenObject(obj);
2036 SECStatus rv;
2037
2038 sftk_DestroySessionObjectData(so);
2039 PZ_DestroyLock(so->attributeLock);
2040 if (to == NULL) {
2041 return NULL;
2042 }
2043 sftk_tokenKeyLock(so->obj.slot);
2044 key = sftk_lookupTokenKeyByHandle(so->obj.slot, so->obj.handle);
2045 if (key == NULL) {
2046 sftk_tokenKeyUnlock(so->obj.slot);
2047 return NULL;
2048 }
2049 rv = SECITEM_CopyItem(NULL, &to->dbKey, key);
2050 sftk_tokenKeyUnlock(so->obj.slot);
2051 if (rv == SECFailure) {
2052 return NULL;
2053 }
2054
2055 return to;
2056 }
2057
2058 SFTKSessionObject *
sftk_narrowToSessionObject(SFTKObject * obj)2059 sftk_narrowToSessionObject(SFTKObject *obj)
2060 {
2061 return !sftk_isToken(obj->handle) ? (SFTKSessionObject *)obj : NULL;
2062 }
2063
2064 SFTKTokenObject *
sftk_narrowToTokenObject(SFTKObject * obj)2065 sftk_narrowToTokenObject(SFTKObject *obj)
2066 {
2067 return sftk_isToken(obj->handle) ? (SFTKTokenObject *)obj : NULL;
2068 }
2069
2070 /* Constant time helper functions */
2071
2072 /* sftk_CKRVToMask returns, in constant time, a mask value of
2073 * all ones if rv == CKR_OK. Otherwise it returns zero. */
2074 unsigned int
sftk_CKRVToMask(CK_RV rv)2075 sftk_CKRVToMask(CK_RV rv)
2076 {
2077 PR_STATIC_ASSERT(CKR_OK == 0);
2078 return ~PORT_CT_NOT_ZERO(rv);
2079 }
2080
2081 /* sftk_CheckCBCPadding checks, in constant time, the padding validity and
2082 * accordingly sets the pad length. */
2083 CK_RV
sftk_CheckCBCPadding(CK_BYTE_PTR pBuf,unsigned int bufLen,unsigned int blockSize,unsigned int * outPadSize)2084 sftk_CheckCBCPadding(CK_BYTE_PTR pBuf, unsigned int bufLen,
2085 unsigned int blockSize, unsigned int *outPadSize)
2086 {
2087 PORT_Assert(outPadSize);
2088
2089 unsigned int padSize = (unsigned int)pBuf[bufLen - 1];
2090
2091 /* If padSize <= blockSize, set goodPad to all-1s and all-0s otherwise.*/
2092 unsigned int goodPad = PORT_CT_DUPLICATE_MSB_TO_ALL(~(blockSize - padSize));
2093 /* padSize should not be 0 */
2094 goodPad &= PORT_CT_NOT_ZERO(padSize);
2095
2096 unsigned int i;
2097 for (i = 0; i < blockSize; i++) {
2098 /* If i < padSize, set loopMask to all-1s and all-0s otherwise.*/
2099 unsigned int loopMask = PORT_CT_DUPLICATE_MSB_TO_ALL(~(padSize - 1 - i));
2100 /* Get the padding value (should be padSize) from buffer */
2101 unsigned int padVal = pBuf[bufLen - 1 - i];
2102 /* Update goodPad only if i < padSize */
2103 goodPad &= PORT_CT_SEL(loopMask, ~(padVal ^ padSize), goodPad);
2104 }
2105
2106 /* If any of the final padding bytes had the wrong value, one or more
2107 * of the lower eight bits of |goodPad| will be cleared. We AND the
2108 * bottom 8 bits together and duplicate the result to all the bits. */
2109 goodPad &= goodPad >> 4;
2110 goodPad &= goodPad >> 2;
2111 goodPad &= goodPad >> 1;
2112 goodPad <<= sizeof(goodPad) * 8 - 1;
2113 goodPad = PORT_CT_DUPLICATE_MSB_TO_ALL(goodPad);
2114
2115 /* Set outPadSize to padSize or 0 */
2116 *outPadSize = PORT_CT_SEL(goodPad, padSize, 0);
2117 /* Return OK if the pad is valid */
2118 return PORT_CT_SEL(goodPad, CKR_OK, CKR_ENCRYPTED_DATA_INVALID);
2119 }
2120
2121 void
sftk_EncodeInteger(PRUint64 integer,CK_ULONG num_bits,CK_BBOOL littleEndian,CK_BYTE_PTR output,CK_ULONG_PTR output_len)2122 sftk_EncodeInteger(PRUint64 integer, CK_ULONG num_bits, CK_BBOOL littleEndian,
2123 CK_BYTE_PTR output, CK_ULONG_PTR output_len)
2124 {
2125 if (output_len) {
2126 *output_len = (num_bits / 8);
2127 }
2128
2129 PR_ASSERT(num_bits > 0 && num_bits <= 64 && (num_bits % 8) == 0);
2130
2131 if (littleEndian == CK_TRUE) {
2132 for (size_t offset = 0; offset < num_bits / 8; offset++) {
2133 output[offset] = (unsigned char)((integer >> (offset * 8)) & 0xFF);
2134 }
2135 } else {
2136 for (size_t offset = 0; offset < num_bits / 8; offset++) {
2137 PRUint64 shift = num_bits - (offset + 1) * 8;
2138 output[offset] = (unsigned char)((integer >> shift) & 0xFF);
2139 }
2140 }
2141 }
2142
2143 CK_FLAGS
sftk_AttributeToFlags(CK_ATTRIBUTE_TYPE op)2144 sftk_AttributeToFlags(CK_ATTRIBUTE_TYPE op)
2145 {
2146 CK_FLAGS flags = 0;
2147
2148 switch (op) {
2149 case CKA_ENCRYPT:
2150 flags = CKF_ENCRYPT;
2151 break;
2152 case CKA_DECRYPT:
2153 flags = CKF_DECRYPT;
2154 break;
2155 case CKA_WRAP:
2156 flags = CKF_WRAP;
2157 break;
2158 case CKA_UNWRAP:
2159 flags = CKF_UNWRAP;
2160 break;
2161 case CKA_SIGN:
2162 flags = CKF_SIGN;
2163 break;
2164 case CKA_SIGN_RECOVER:
2165 flags = CKF_SIGN_RECOVER;
2166 break;
2167 case CKA_VERIFY:
2168 flags = CKF_VERIFY;
2169 break;
2170 case CKA_VERIFY_RECOVER:
2171 flags = CKF_VERIFY_RECOVER;
2172 break;
2173 case CKA_DERIVE:
2174 flags = CKF_DERIVE;
2175 break;
2176 /* fake attribute to select digesting */
2177 case CKA_DIGEST:
2178 flags = CKF_DIGEST;
2179 break;
2180 case CKA_NSS_MESSAGE | CKA_ENCRYPT:
2181 flags = CKF_MESSAGE_ENCRYPT;
2182 break;
2183 case CKA_NSS_MESSAGE | CKA_DECRYPT:
2184 flags = CKF_MESSAGE_DECRYPT;
2185 break;
2186 case CKA_NSS_MESSAGE | CKA_SIGN:
2187 flags = CKF_MESSAGE_SIGN;
2188 break;
2189 case CKA_NSS_MESSAGE | CKA_VERIFY:
2190 flags = CKF_MESSAGE_VERIFY;
2191 break;
2192 default:
2193 break;
2194 }
2195 return flags;
2196 }
2197
2198 #ifdef NSS_HAS_FIPS_INDICATORS
2199 /* sigh, we probably need a version of this in secutil so that both
2200 * softoken and NSS can use it */
2201 static SECOidTag
sftk_quickGetECCCurveOid(SFTKObject * source)2202 sftk_quickGetECCCurveOid(SFTKObject *source)
2203 {
2204 SFTKAttribute *attribute = sftk_FindAttribute(source, CKA_EC_PARAMS);
2205 unsigned char *encoded;
2206 int len;
2207 SECItem oid;
2208 SECOidTag tag;
2209
2210 if (attribute == NULL) {
2211 return SEC_OID_UNKNOWN;
2212 }
2213 encoded = attribute->attrib.pValue;
2214 len = attribute->attrib.ulValueLen;
2215 if ((len < 2) || (encoded[0] != SEC_ASN1_OBJECT_ID) ||
2216 (len != encoded[1] + 2)) {
2217 sftk_FreeAttribute(attribute);
2218 return SEC_OID_UNKNOWN;
2219 }
2220 oid.data = encoded + 2;
2221 oid.len = len - 2;
2222 tag = SECOID_FindOIDTag(&oid);
2223 sftk_FreeAttribute(attribute);
2224 return tag;
2225 }
2226
2227 /* This function currently only returns valid lengths for
2228 * FIPS approved ECC curves. If we want to make this generic
2229 * in the future, that Curve determination can be done in
2230 * the sftk_handleSpecial. Since it's currently only used
2231 * in FIPS indicators, it's currently only compiled with
2232 * the FIPS indicator code */
2233 static int
sftk_getKeyLength(SFTKObject * source)2234 sftk_getKeyLength(SFTKObject *source)
2235 {
2236 CK_KEY_TYPE keyType = CK_INVALID_HANDLE;
2237 CK_ATTRIBUTE_TYPE keyAttribute;
2238 CK_ULONG keyLength = 0;
2239 SFTKAttribute *attribute;
2240 CK_RV crv;
2241
2242 /* If we don't have a key, then it doesn't have a length.
2243 * this may be OK (say we are hashing). The mech info will
2244 * sort this out because algorithms which expect no keys
2245 * will accept zero length for the keys */
2246 if (source == NULL) {
2247 return 0;
2248 }
2249
2250 crv = sftk_GetULongAttribute(source, CKA_KEY_TYPE, &keyType);
2251 if (crv != CKR_OK) {
2252 /* sometimes we're passed a data object, in that case the
2253 * key length is CKA_VALUE, which is the default */
2254 keyType = CKK_INVALID_KEY_TYPE;
2255 }
2256 if (keyType == CKK_EC) {
2257 SECOidTag curve = sftk_quickGetECCCurveOid(source);
2258 switch (curve) {
2259 case SEC_OID_CURVE25519:
2260 /* change when we start algorithm testing on curve25519 */
2261 return 0;
2262 case SEC_OID_SECG_EC_SECP256R1:
2263 return 256;
2264 case SEC_OID_SECG_EC_SECP384R1:
2265 return 384;
2266 case SEC_OID_SECG_EC_SECP521R1:
2267 /* this is a lie, but it makes the table easier. We don't
2268 * have to have a double entry for every ECC mechanism */
2269 return 512;
2270 default:
2271 break;
2272 }
2273 /* other curves aren't NIST approved, returning 0 will cause these
2274 * curves to fail FIPS length criteria */
2275 return 0;
2276 }
2277
2278 switch (keyType) {
2279 case CKK_RSA:
2280 keyAttribute = CKA_MODULUS;
2281 break;
2282 case CKK_DSA:
2283 case CKK_DH:
2284 keyAttribute = CKA_PRIME;
2285 break;
2286 default:
2287 keyAttribute = CKA_VALUE;
2288 break;
2289 }
2290 attribute = sftk_FindAttribute(source, keyAttribute);
2291 if (attribute) {
2292 keyLength = attribute->attrib.ulValueLen * 8;
2293 sftk_FreeAttribute(attribute);
2294 }
2295 return keyLength;
2296 }
2297
2298 /*
2299 * handle specialized FIPS semantics that are too complicated to
2300 * handle with just a table. NOTE: this means any additional semantics
2301 * would have to be coded here before they can be added to the table */
2302 static PRBool
sftk_handleSpecial(SFTKSlot * slot,CK_MECHANISM * mech,SFTKFIPSAlgorithmList * mechInfo,SFTKObject * source)2303 sftk_handleSpecial(SFTKSlot *slot, CK_MECHANISM *mech,
2304 SFTKFIPSAlgorithmList *mechInfo, SFTKObject *source)
2305 {
2306 switch (mechInfo->special) {
2307 case SFTKFIPSDH: {
2308 SECItem dhPrime;
2309 const SECItem *dhSubPrime;
2310 CK_RV crv = sftk_Attribute2SecItem(NULL, &dhPrime,
2311 source, CKA_PRIME);
2312 if (crv != CKR_OK) {
2313 return PR_FALSE;
2314 }
2315 dhSubPrime = sftk_VerifyDH_Prime(&dhPrime);
2316 SECITEM_ZfreeItem(&dhPrime, PR_FALSE);
2317 return (dhSubPrime) ? PR_TRUE : PR_FALSE;
2318 }
2319 case SFTKFIPSNone:
2320 return PR_FALSE;
2321 case SFTKFIPSECC:
2322 /* we've already handled the curve selection in the 'getlength'
2323 * function */
2324 return PR_TRUE;
2325 case SFTKFIPSAEAD: {
2326 if (mech->ulParameterLen == 0) {
2327 /* AEAD ciphers are only in FIPS mode if we are using the
2328 * MESSAGE interface. This takes an empty parameter
2329 * in the init function */
2330 return PR_TRUE;
2331 }
2332 return PR_FALSE;
2333 }
2334 default:
2335 break;
2336 }
2337 /* if we didn't understand the special processing, mark it non-fips */
2338 return PR_FALSE;
2339 }
2340 #endif
2341
2342 PRBool
sftk_operationIsFIPS(SFTKSlot * slot,CK_MECHANISM * mech,CK_ATTRIBUTE_TYPE op,SFTKObject * source)2343 sftk_operationIsFIPS(SFTKSlot *slot, CK_MECHANISM *mech, CK_ATTRIBUTE_TYPE op,
2344 SFTKObject *source)
2345 {
2346 #ifndef NSS_HAS_FIPS_INDICATORS
2347 return PR_FALSE;
2348 #else
2349 int i;
2350 CK_FLAGS opFlags;
2351 CK_ULONG keyLength;
2352
2353 /* handle all the quick stuff first */
2354 if (!sftk_isFIPS(slot->slotID)) {
2355 return PR_FALSE;
2356 }
2357 if (source && !source->isFIPS) {
2358 return PR_FALSE;
2359 }
2360 if (mech == NULL) {
2361 return PR_FALSE;
2362 }
2363
2364 /* now get the calculated values */
2365 opFlags = sftk_AttributeToFlags(op);
2366 if (opFlags == 0) {
2367 return PR_FALSE;
2368 }
2369 keyLength = sftk_getKeyLength(source);
2370
2371 /* check against our algorithm array */
2372 for (i = 0; i < SFTK_NUMBER_FIPS_ALGORITHMS; i++) {
2373 SFTKFIPSAlgorithmList *mechs = &sftk_fips_mechs[i];
2374 /* if we match the number of records exactly, then we are an
2375 * approved algorithm in the approved mode with an approved key */
2376 if (((mech->mechanism == mechs->type) &&
2377 (opFlags == (mechs->info.flags & opFlags)) &&
2378 (keyLength <= mechs->info.ulMaxKeySize) &&
2379 (keyLength >= mechs->info.ulMinKeySize) &&
2380 ((keyLength - mechs->info.ulMinKeySize) % mechs->step) == 0) &&
2381 ((mechs->special == SFTKFIPSNone) ||
2382 sftk_handleSpecial(slot, mech, mechs, source))) {
2383 return PR_TRUE;
2384 }
2385 }
2386 return PR_FALSE;
2387 #endif
2388 }
2389