Thu, 22 Jan 2015 13:21:57 +0100
Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6
michael@0 | 1 | /* This Source Code Form is subject to the terms of the Mozilla Public |
michael@0 | 2 | * License, v. 2.0. If a copy of the MPL was not distributed with this |
michael@0 | 3 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
michael@0 | 4 | /* |
michael@0 | 5 | * Internal PKCS #11 functions. Should only be called by pkcs11.c |
michael@0 | 6 | */ |
michael@0 | 7 | #include "pkcs11.h" |
michael@0 | 8 | #include "pkcs11i.h" |
michael@0 | 9 | #include "lowkeyi.h" |
michael@0 | 10 | #include "secasn1.h" |
michael@0 | 11 | #include "blapi.h" |
michael@0 | 12 | #include "secerr.h" |
michael@0 | 13 | #include "prnetdb.h" /* for PR_ntohl */ |
michael@0 | 14 | #include "sftkdb.h" |
michael@0 | 15 | #include "softoken.h" |
michael@0 | 16 | |
michael@0 | 17 | /* |
michael@0 | 18 | * ******************** Attribute Utilities ******************************* |
michael@0 | 19 | */ |
michael@0 | 20 | |
michael@0 | 21 | /* |
michael@0 | 22 | * create a new attribute with type, value, and length. Space is allocated |
michael@0 | 23 | * to hold value. |
michael@0 | 24 | */ |
michael@0 | 25 | static SFTKAttribute * |
michael@0 | 26 | sftk_NewAttribute(SFTKObject *object, |
michael@0 | 27 | CK_ATTRIBUTE_TYPE type, const void *value, CK_ULONG len) |
michael@0 | 28 | { |
michael@0 | 29 | SFTKAttribute *attribute; |
michael@0 | 30 | |
michael@0 | 31 | SFTKSessionObject *so = sftk_narrowToSessionObject(object); |
michael@0 | 32 | int index; |
michael@0 | 33 | |
michael@0 | 34 | if (so == NULL) { |
michael@0 | 35 | /* allocate new attribute in a buffer */ |
michael@0 | 36 | PORT_Assert(0); |
michael@0 | 37 | return NULL; |
michael@0 | 38 | } |
michael@0 | 39 | /* |
michael@0 | 40 | * We attempt to keep down contention on Malloc and Arena locks by |
michael@0 | 41 | * limiting the number of these calls on high traversed paths. This |
michael@0 | 42 | * is done for attributes by 'allocating' them from a pool already |
michael@0 | 43 | * allocated by the parent object. |
michael@0 | 44 | */ |
michael@0 | 45 | PZ_Lock(so->attributeLock); |
michael@0 | 46 | index = so->nextAttr++; |
michael@0 | 47 | PZ_Unlock(so->attributeLock); |
michael@0 | 48 | PORT_Assert(index < MAX_OBJS_ATTRS); |
michael@0 | 49 | if (index >= MAX_OBJS_ATTRS) return NULL; |
michael@0 | 50 | |
michael@0 | 51 | attribute = &so->attrList[index]; |
michael@0 | 52 | attribute->attrib.type = type; |
michael@0 | 53 | attribute->freeAttr = PR_FALSE; |
michael@0 | 54 | attribute->freeData = PR_FALSE; |
michael@0 | 55 | if (value) { |
michael@0 | 56 | if (len <= ATTR_SPACE) { |
michael@0 | 57 | attribute->attrib.pValue = attribute->space; |
michael@0 | 58 | } else { |
michael@0 | 59 | attribute->attrib.pValue = PORT_Alloc(len); |
michael@0 | 60 | attribute->freeData = PR_TRUE; |
michael@0 | 61 | } |
michael@0 | 62 | if (attribute->attrib.pValue == NULL) { |
michael@0 | 63 | return NULL; |
michael@0 | 64 | } |
michael@0 | 65 | PORT_Memcpy(attribute->attrib.pValue,value,len); |
michael@0 | 66 | attribute->attrib.ulValueLen = len; |
michael@0 | 67 | } else { |
michael@0 | 68 | attribute->attrib.pValue = NULL; |
michael@0 | 69 | attribute->attrib.ulValueLen = 0; |
michael@0 | 70 | } |
michael@0 | 71 | attribute->attrib.type = type; |
michael@0 | 72 | attribute->handle = type; |
michael@0 | 73 | attribute->next = attribute->prev = NULL; |
michael@0 | 74 | return attribute; |
michael@0 | 75 | } |
michael@0 | 76 | |
michael@0 | 77 | /* |
michael@0 | 78 | * Free up all the memory associated with an attribute. Reference count |
michael@0 | 79 | * must be zero to call this. |
michael@0 | 80 | */ |
michael@0 | 81 | static void |
michael@0 | 82 | sftk_DestroyAttribute(SFTKAttribute *attribute) |
michael@0 | 83 | { |
michael@0 | 84 | if (attribute->freeData) { |
michael@0 | 85 | if (attribute->attrib.pValue) { |
michael@0 | 86 | /* clear out the data in the attribute value... it may have been |
michael@0 | 87 | * sensitive data */ |
michael@0 | 88 | PORT_Memset(attribute->attrib.pValue, 0, |
michael@0 | 89 | attribute->attrib.ulValueLen); |
michael@0 | 90 | } |
michael@0 | 91 | PORT_Free(attribute->attrib.pValue); |
michael@0 | 92 | } |
michael@0 | 93 | PORT_Free(attribute); |
michael@0 | 94 | } |
michael@0 | 95 | |
michael@0 | 96 | /* |
michael@0 | 97 | * release a reference to an attribute structure |
michael@0 | 98 | */ |
michael@0 | 99 | void |
michael@0 | 100 | sftk_FreeAttribute(SFTKAttribute *attribute) |
michael@0 | 101 | { |
michael@0 | 102 | if (attribute->freeAttr) { |
michael@0 | 103 | sftk_DestroyAttribute(attribute); |
michael@0 | 104 | return; |
michael@0 | 105 | } |
michael@0 | 106 | } |
michael@0 | 107 | |
michael@0 | 108 | static SFTKAttribute * |
michael@0 | 109 | sftk_FindTokenAttribute(SFTKTokenObject *object,CK_ATTRIBUTE_TYPE type) |
michael@0 | 110 | { |
michael@0 | 111 | SFTKAttribute *myattribute = NULL; |
michael@0 | 112 | SFTKDBHandle *dbHandle = NULL; |
michael@0 | 113 | CK_RV crv = CKR_HOST_MEMORY; |
michael@0 | 114 | |
michael@0 | 115 | myattribute = (SFTKAttribute*)PORT_Alloc(sizeof(SFTKAttribute)); |
michael@0 | 116 | if (myattribute == NULL) { |
michael@0 | 117 | goto loser; |
michael@0 | 118 | } |
michael@0 | 119 | |
michael@0 | 120 | dbHandle = sftk_getDBForTokenObject(object->obj.slot, object->obj.handle); |
michael@0 | 121 | |
michael@0 | 122 | myattribute->handle = type; |
michael@0 | 123 | myattribute->attrib.type = type; |
michael@0 | 124 | myattribute->attrib.pValue = myattribute->space; |
michael@0 | 125 | myattribute->attrib.ulValueLen = ATTR_SPACE; |
michael@0 | 126 | myattribute->next = myattribute->prev = NULL; |
michael@0 | 127 | myattribute->freeAttr = PR_TRUE; |
michael@0 | 128 | myattribute->freeData = PR_FALSE; |
michael@0 | 129 | |
michael@0 | 130 | crv = sftkdb_GetAttributeValue(dbHandle, object->obj.handle, |
michael@0 | 131 | &myattribute->attrib, 1); |
michael@0 | 132 | |
michael@0 | 133 | /* attribute is bigger than our attribute space buffer, malloc it */ |
michael@0 | 134 | if (crv == CKR_BUFFER_TOO_SMALL) { |
michael@0 | 135 | myattribute->attrib.pValue = NULL; |
michael@0 | 136 | crv = sftkdb_GetAttributeValue(dbHandle, object->obj.handle, |
michael@0 | 137 | &myattribute->attrib, 1); |
michael@0 | 138 | if (crv != CKR_OK) { |
michael@0 | 139 | goto loser; |
michael@0 | 140 | } |
michael@0 | 141 | myattribute->attrib.pValue = PORT_Alloc(myattribute->attrib.ulValueLen); |
michael@0 | 142 | if (myattribute->attrib.pValue == NULL) { |
michael@0 | 143 | crv = CKR_HOST_MEMORY; |
michael@0 | 144 | goto loser; |
michael@0 | 145 | } |
michael@0 | 146 | myattribute->freeData = PR_TRUE; |
michael@0 | 147 | crv = sftkdb_GetAttributeValue(dbHandle, object->obj.handle, |
michael@0 | 148 | &myattribute->attrib, 1); |
michael@0 | 149 | } |
michael@0 | 150 | loser: |
michael@0 | 151 | if (dbHandle) { |
michael@0 | 152 | sftk_freeDB(dbHandle); |
michael@0 | 153 | } |
michael@0 | 154 | if (crv != CKR_OK) { |
michael@0 | 155 | if (myattribute) { |
michael@0 | 156 | myattribute->attrib.ulValueLen = 0; |
michael@0 | 157 | sftk_FreeAttribute(myattribute); |
michael@0 | 158 | myattribute = NULL; |
michael@0 | 159 | } |
michael@0 | 160 | } |
michael@0 | 161 | return myattribute; |
michael@0 | 162 | } |
michael@0 | 163 | |
michael@0 | 164 | /* |
michael@0 | 165 | * look up and attribute structure from a type and Object structure. |
michael@0 | 166 | * The returned attribute is referenced and needs to be freed when |
michael@0 | 167 | * it is no longer needed. |
michael@0 | 168 | */ |
michael@0 | 169 | SFTKAttribute * |
michael@0 | 170 | sftk_FindAttribute(SFTKObject *object,CK_ATTRIBUTE_TYPE type) |
michael@0 | 171 | { |
michael@0 | 172 | SFTKAttribute *attribute; |
michael@0 | 173 | SFTKSessionObject *sessObject = sftk_narrowToSessionObject(object); |
michael@0 | 174 | |
michael@0 | 175 | if (sessObject == NULL) { |
michael@0 | 176 | return sftk_FindTokenAttribute(sftk_narrowToTokenObject(object),type); |
michael@0 | 177 | } |
michael@0 | 178 | |
michael@0 | 179 | PZ_Lock(sessObject->attributeLock); |
michael@0 | 180 | sftkqueue_find(attribute,type,sessObject->head, sessObject->hashSize); |
michael@0 | 181 | PZ_Unlock(sessObject->attributeLock); |
michael@0 | 182 | |
michael@0 | 183 | return(attribute); |
michael@0 | 184 | } |
michael@0 | 185 | |
michael@0 | 186 | /* |
michael@0 | 187 | * Take a buffer and it's length and return it's true size in bits; |
michael@0 | 188 | */ |
michael@0 | 189 | unsigned int |
michael@0 | 190 | sftk_GetLengthInBits(unsigned char *buf, unsigned int bufLen) |
michael@0 | 191 | { |
michael@0 | 192 | unsigned int size = bufLen * 8; |
michael@0 | 193 | unsigned int i; |
michael@0 | 194 | |
michael@0 | 195 | /* Get the real length in bytes */ |
michael@0 | 196 | for (i=0; i < bufLen; i++) { |
michael@0 | 197 | unsigned char c = *buf++; |
michael@0 | 198 | if (c != 0) { |
michael@0 | 199 | unsigned char m; |
michael@0 | 200 | for (m=0x80; m > 0 ; m = m >> 1) { |
michael@0 | 201 | if ((c & m) != 0) { |
michael@0 | 202 | break; |
michael@0 | 203 | } |
michael@0 | 204 | size--; |
michael@0 | 205 | } |
michael@0 | 206 | break; |
michael@0 | 207 | } |
michael@0 | 208 | size-=8; |
michael@0 | 209 | } |
michael@0 | 210 | return size; |
michael@0 | 211 | } |
michael@0 | 212 | |
michael@0 | 213 | /* |
michael@0 | 214 | * Constrain a big num attribute. to size and padding |
michael@0 | 215 | * minLength means length of the object must be greater than equal to minLength |
michael@0 | 216 | * maxLength means length of the object must be less than equal to maxLength |
michael@0 | 217 | * minMultiple means that object length mod minMultiple must equal 0. |
michael@0 | 218 | * all input sizes are in bits. |
michael@0 | 219 | * if any constraint is '0' that constraint is not checked. |
michael@0 | 220 | */ |
michael@0 | 221 | CK_RV |
michael@0 | 222 | sftk_ConstrainAttribute(SFTKObject *object, CK_ATTRIBUTE_TYPE type, |
michael@0 | 223 | int minLength, int maxLength, int minMultiple) |
michael@0 | 224 | { |
michael@0 | 225 | SFTKAttribute *attribute; |
michael@0 | 226 | int size; |
michael@0 | 227 | unsigned char *ptr; |
michael@0 | 228 | |
michael@0 | 229 | attribute = sftk_FindAttribute(object, type); |
michael@0 | 230 | if (!attribute) { |
michael@0 | 231 | return CKR_TEMPLATE_INCOMPLETE; |
michael@0 | 232 | } |
michael@0 | 233 | ptr = (unsigned char *) attribute->attrib.pValue; |
michael@0 | 234 | if (ptr == NULL) { |
michael@0 | 235 | sftk_FreeAttribute(attribute); |
michael@0 | 236 | return CKR_ATTRIBUTE_VALUE_INVALID; |
michael@0 | 237 | } |
michael@0 | 238 | size = sftk_GetLengthInBits(ptr, attribute->attrib.ulValueLen); |
michael@0 | 239 | sftk_FreeAttribute(attribute); |
michael@0 | 240 | |
michael@0 | 241 | if ((minLength != 0) && (size < minLength)) { |
michael@0 | 242 | return CKR_ATTRIBUTE_VALUE_INVALID; |
michael@0 | 243 | } |
michael@0 | 244 | if ((maxLength != 0) && (size > maxLength)) { |
michael@0 | 245 | return CKR_ATTRIBUTE_VALUE_INVALID; |
michael@0 | 246 | } |
michael@0 | 247 | if ((minMultiple != 0) && ((size % minMultiple) != 0)) { |
michael@0 | 248 | return CKR_ATTRIBUTE_VALUE_INVALID; |
michael@0 | 249 | } |
michael@0 | 250 | return CKR_OK; |
michael@0 | 251 | } |
michael@0 | 252 | |
michael@0 | 253 | PRBool |
michael@0 | 254 | sftk_hasAttributeToken(SFTKTokenObject *object, CK_ATTRIBUTE_TYPE type) |
michael@0 | 255 | { |
michael@0 | 256 | CK_ATTRIBUTE template; |
michael@0 | 257 | CK_RV crv; |
michael@0 | 258 | SFTKDBHandle *dbHandle; |
michael@0 | 259 | |
michael@0 | 260 | dbHandle = sftk_getDBForTokenObject(object->obj.slot, object->obj.handle); |
michael@0 | 261 | template.type = type; |
michael@0 | 262 | template.pValue = NULL; |
michael@0 | 263 | template.ulValueLen = 0; |
michael@0 | 264 | |
michael@0 | 265 | crv = sftkdb_GetAttributeValue(dbHandle, object->obj.handle, &template, 1); |
michael@0 | 266 | sftk_freeDB(dbHandle); |
michael@0 | 267 | |
michael@0 | 268 | /* attribute is bigger than our attribute space buffer, malloc it */ |
michael@0 | 269 | return (crv == CKR_OK) ? PR_TRUE : PR_FALSE; |
michael@0 | 270 | } |
michael@0 | 271 | |
michael@0 | 272 | /* |
michael@0 | 273 | * return true if object has attribute |
michael@0 | 274 | */ |
michael@0 | 275 | PRBool |
michael@0 | 276 | sftk_hasAttribute(SFTKObject *object,CK_ATTRIBUTE_TYPE type) |
michael@0 | 277 | { |
michael@0 | 278 | SFTKAttribute *attribute; |
michael@0 | 279 | SFTKSessionObject *sessObject = sftk_narrowToSessionObject(object); |
michael@0 | 280 | |
michael@0 | 281 | if (sessObject == NULL) { |
michael@0 | 282 | return sftk_hasAttributeToken(sftk_narrowToTokenObject(object), type); |
michael@0 | 283 | } |
michael@0 | 284 | |
michael@0 | 285 | PZ_Lock(sessObject->attributeLock); |
michael@0 | 286 | sftkqueue_find(attribute,type,sessObject->head, sessObject->hashSize); |
michael@0 | 287 | PZ_Unlock(sessObject->attributeLock); |
michael@0 | 288 | |
michael@0 | 289 | return (PRBool)(attribute != NULL); |
michael@0 | 290 | } |
michael@0 | 291 | |
michael@0 | 292 | /* |
michael@0 | 293 | * add an attribute to an object |
michael@0 | 294 | */ |
michael@0 | 295 | static void |
michael@0 | 296 | sftk_AddAttribute(SFTKObject *object,SFTKAttribute *attribute) |
michael@0 | 297 | { |
michael@0 | 298 | SFTKSessionObject *sessObject = sftk_narrowToSessionObject(object); |
michael@0 | 299 | |
michael@0 | 300 | if (sessObject == NULL) return; |
michael@0 | 301 | PZ_Lock(sessObject->attributeLock); |
michael@0 | 302 | sftkqueue_add(attribute,attribute->handle, |
michael@0 | 303 | sessObject->head, sessObject->hashSize); |
michael@0 | 304 | PZ_Unlock(sessObject->attributeLock); |
michael@0 | 305 | } |
michael@0 | 306 | |
michael@0 | 307 | /* |
michael@0 | 308 | * copy an unsigned attribute into a SECItem. Secitem is allocated in |
michael@0 | 309 | * the specified arena. |
michael@0 | 310 | */ |
michael@0 | 311 | CK_RV |
michael@0 | 312 | sftk_Attribute2SSecItem(PLArenaPool *arena,SECItem *item,SFTKObject *object, |
michael@0 | 313 | CK_ATTRIBUTE_TYPE type) |
michael@0 | 314 | { |
michael@0 | 315 | SFTKAttribute *attribute; |
michael@0 | 316 | |
michael@0 | 317 | item->data = NULL; |
michael@0 | 318 | |
michael@0 | 319 | attribute = sftk_FindAttribute(object, type); |
michael@0 | 320 | if (attribute == NULL) return CKR_TEMPLATE_INCOMPLETE; |
michael@0 | 321 | |
michael@0 | 322 | (void)SECITEM_AllocItem(arena, item, attribute->attrib.ulValueLen); |
michael@0 | 323 | if (item->data == NULL) { |
michael@0 | 324 | sftk_FreeAttribute(attribute); |
michael@0 | 325 | return CKR_HOST_MEMORY; |
michael@0 | 326 | } |
michael@0 | 327 | PORT_Memcpy(item->data, attribute->attrib.pValue, item->len); |
michael@0 | 328 | sftk_FreeAttribute(attribute); |
michael@0 | 329 | return CKR_OK; |
michael@0 | 330 | } |
michael@0 | 331 | |
michael@0 | 332 | /* |
michael@0 | 333 | * fetch multiple attributes into SECItems. Secitem data is allocated in |
michael@0 | 334 | * the specified arena. |
michael@0 | 335 | */ |
michael@0 | 336 | CK_RV |
michael@0 | 337 | sftk_MultipleAttribute2SecItem(PLArenaPool *arena, SFTKObject *object, |
michael@0 | 338 | SFTKItemTemplate *itemTemplate, int itemTemplateCount) |
michael@0 | 339 | { |
michael@0 | 340 | |
michael@0 | 341 | CK_RV crv = CKR_OK; |
michael@0 | 342 | CK_ATTRIBUTE templateSpace[SFTK_MAX_ITEM_TEMPLATE]; |
michael@0 | 343 | CK_ATTRIBUTE *template; |
michael@0 | 344 | SFTKTokenObject *tokObject; |
michael@0 | 345 | SFTKDBHandle *dbHandle = NULL; |
michael@0 | 346 | int i; |
michael@0 | 347 | |
michael@0 | 348 | tokObject = sftk_narrowToTokenObject(object); |
michael@0 | 349 | |
michael@0 | 350 | /* session objects, just loop through the list */ |
michael@0 | 351 | if (tokObject == NULL) { |
michael@0 | 352 | for (i=0; i < itemTemplateCount; i++) { |
michael@0 | 353 | crv = sftk_Attribute2SecItem(arena,itemTemplate[i].item, object, |
michael@0 | 354 | itemTemplate[i].type); |
michael@0 | 355 | if (crv != CKR_OK) { |
michael@0 | 356 | return crv; |
michael@0 | 357 | } |
michael@0 | 358 | } |
michael@0 | 359 | return CKR_OK; |
michael@0 | 360 | } |
michael@0 | 361 | |
michael@0 | 362 | /* don't do any work if none is required */ |
michael@0 | 363 | if (itemTemplateCount == 0) { |
michael@0 | 364 | return CKR_OK; |
michael@0 | 365 | } |
michael@0 | 366 | |
michael@0 | 367 | /* don't allocate the template unless we need it */ |
michael@0 | 368 | if (itemTemplateCount > SFTK_MAX_ITEM_TEMPLATE) { |
michael@0 | 369 | template = PORT_NewArray(CK_ATTRIBUTE, itemTemplateCount); |
michael@0 | 370 | } else { |
michael@0 | 371 | template = templateSpace; |
michael@0 | 372 | } |
michael@0 | 373 | |
michael@0 | 374 | if (template == NULL) { |
michael@0 | 375 | crv = CKR_HOST_MEMORY; |
michael@0 | 376 | goto loser; |
michael@0 | 377 | } |
michael@0 | 378 | |
michael@0 | 379 | dbHandle = sftk_getDBForTokenObject(object->slot, object->handle); |
michael@0 | 380 | if (dbHandle == NULL) { |
michael@0 | 381 | crv = CKR_OBJECT_HANDLE_INVALID; |
michael@0 | 382 | goto loser; |
michael@0 | 383 | } |
michael@0 | 384 | |
michael@0 | 385 | /* set up the PKCS #11 template */ |
michael@0 | 386 | for (i=0; i < itemTemplateCount; i++) { |
michael@0 | 387 | template[i].type = itemTemplate[i].type; |
michael@0 | 388 | template[i].pValue = NULL; |
michael@0 | 389 | template[i].ulValueLen = 0; |
michael@0 | 390 | } |
michael@0 | 391 | |
michael@0 | 392 | /* fetch the attribute lengths */ |
michael@0 | 393 | crv = sftkdb_GetAttributeValue(dbHandle, object->handle, |
michael@0 | 394 | template, itemTemplateCount); |
michael@0 | 395 | if (crv != CKR_OK) { |
michael@0 | 396 | goto loser; |
michael@0 | 397 | } |
michael@0 | 398 | |
michael@0 | 399 | /* allocate space for the attributes */ |
michael@0 | 400 | for (i=0; i < itemTemplateCount ; i++) { |
michael@0 | 401 | template[i].pValue = PORT_ArenaAlloc(arena, template[i].ulValueLen); |
michael@0 | 402 | if (template[i].pValue == NULL) { |
michael@0 | 403 | crv = CKR_HOST_MEMORY; |
michael@0 | 404 | goto loser; |
michael@0 | 405 | } |
michael@0 | 406 | } |
michael@0 | 407 | |
michael@0 | 408 | /* fetch the attributes */ |
michael@0 | 409 | crv = sftkdb_GetAttributeValue(dbHandle, object->handle, |
michael@0 | 410 | template, itemTemplateCount); |
michael@0 | 411 | if (crv != CKR_OK) { |
michael@0 | 412 | goto loser; |
michael@0 | 413 | } |
michael@0 | 414 | |
michael@0 | 415 | /* Fill in the items */ |
michael@0 | 416 | for (i=0; i < itemTemplateCount; i++) { |
michael@0 | 417 | itemTemplate[i].item->data = template[i].pValue; |
michael@0 | 418 | itemTemplate[i].item->len = template[i].ulValueLen; |
michael@0 | 419 | } |
michael@0 | 420 | |
michael@0 | 421 | loser: |
michael@0 | 422 | if (template != templateSpace) { |
michael@0 | 423 | PORT_Free(template); |
michael@0 | 424 | } |
michael@0 | 425 | if (dbHandle) { |
michael@0 | 426 | sftk_freeDB(dbHandle); |
michael@0 | 427 | } |
michael@0 | 428 | |
michael@0 | 429 | return crv; |
michael@0 | 430 | } |
michael@0 | 431 | |
michael@0 | 432 | |
michael@0 | 433 | /* |
michael@0 | 434 | * delete an attribute from an object |
michael@0 | 435 | */ |
michael@0 | 436 | static void |
michael@0 | 437 | sftk_DeleteAttribute(SFTKObject *object, SFTKAttribute *attribute) |
michael@0 | 438 | { |
michael@0 | 439 | SFTKSessionObject *sessObject = sftk_narrowToSessionObject(object); |
michael@0 | 440 | |
michael@0 | 441 | if (sessObject == NULL) { |
michael@0 | 442 | return ; |
michael@0 | 443 | } |
michael@0 | 444 | PZ_Lock(sessObject->attributeLock); |
michael@0 | 445 | if (sftkqueue_is_queued(attribute,attribute->handle, |
michael@0 | 446 | sessObject->head, sessObject->hashSize)) { |
michael@0 | 447 | sftkqueue_delete(attribute,attribute->handle, |
michael@0 | 448 | sessObject->head, sessObject->hashSize); |
michael@0 | 449 | } |
michael@0 | 450 | PZ_Unlock(sessObject->attributeLock); |
michael@0 | 451 | } |
michael@0 | 452 | |
michael@0 | 453 | /* |
michael@0 | 454 | * this is only valid for CK_BBOOL type attributes. Return the state |
michael@0 | 455 | * of that attribute. |
michael@0 | 456 | */ |
michael@0 | 457 | PRBool |
michael@0 | 458 | sftk_isTrue(SFTKObject *object,CK_ATTRIBUTE_TYPE type) |
michael@0 | 459 | { |
michael@0 | 460 | SFTKAttribute *attribute; |
michael@0 | 461 | PRBool tok = PR_FALSE; |
michael@0 | 462 | |
michael@0 | 463 | attribute=sftk_FindAttribute(object,type); |
michael@0 | 464 | if (attribute == NULL) { return PR_FALSE; } |
michael@0 | 465 | tok = (PRBool)(*(CK_BBOOL *)attribute->attrib.pValue); |
michael@0 | 466 | sftk_FreeAttribute(attribute); |
michael@0 | 467 | |
michael@0 | 468 | return tok; |
michael@0 | 469 | } |
michael@0 | 470 | |
michael@0 | 471 | /* |
michael@0 | 472 | * force an attribute to null. |
michael@0 | 473 | * this is for sensitive keys which are stored in the database, we don't |
michael@0 | 474 | * want to keep this info around in memory in the clear. |
michael@0 | 475 | */ |
michael@0 | 476 | void |
michael@0 | 477 | sftk_nullAttribute(SFTKObject *object,CK_ATTRIBUTE_TYPE type) |
michael@0 | 478 | { |
michael@0 | 479 | SFTKAttribute *attribute; |
michael@0 | 480 | |
michael@0 | 481 | attribute=sftk_FindAttribute(object,type); |
michael@0 | 482 | if (attribute == NULL) return; |
michael@0 | 483 | |
michael@0 | 484 | if (attribute->attrib.pValue != NULL) { |
michael@0 | 485 | PORT_Memset(attribute->attrib.pValue,0,attribute->attrib.ulValueLen); |
michael@0 | 486 | if (attribute->freeData) { |
michael@0 | 487 | PORT_Free(attribute->attrib.pValue); |
michael@0 | 488 | } |
michael@0 | 489 | attribute->freeData = PR_FALSE; |
michael@0 | 490 | attribute->attrib.pValue = NULL; |
michael@0 | 491 | attribute->attrib.ulValueLen = 0; |
michael@0 | 492 | } |
michael@0 | 493 | sftk_FreeAttribute(attribute); |
michael@0 | 494 | } |
michael@0 | 495 | |
michael@0 | 496 | |
michael@0 | 497 | static CK_RV |
michael@0 | 498 | sftk_forceTokenAttribute(SFTKObject *object,CK_ATTRIBUTE_TYPE type, |
michael@0 | 499 | const void *value, unsigned int len) |
michael@0 | 500 | { |
michael@0 | 501 | CK_ATTRIBUTE attribute; |
michael@0 | 502 | SFTKDBHandle *dbHandle = NULL; |
michael@0 | 503 | SFTKTokenObject *to = sftk_narrowToTokenObject(object); |
michael@0 | 504 | CK_RV crv; |
michael@0 | 505 | |
michael@0 | 506 | PORT_Assert(to); |
michael@0 | 507 | if (to == NULL) { |
michael@0 | 508 | return CKR_DEVICE_ERROR; |
michael@0 | 509 | } |
michael@0 | 510 | |
michael@0 | 511 | dbHandle = sftk_getDBForTokenObject(object->slot, object->handle); |
michael@0 | 512 | |
michael@0 | 513 | attribute.type = type; |
michael@0 | 514 | attribute.pValue = (void *)value; |
michael@0 | 515 | attribute.ulValueLen = len; |
michael@0 | 516 | |
michael@0 | 517 | crv = sftkdb_SetAttributeValue(dbHandle, object, &attribute, 1); |
michael@0 | 518 | sftk_freeDB(dbHandle); |
michael@0 | 519 | return crv; |
michael@0 | 520 | } |
michael@0 | 521 | |
michael@0 | 522 | /* |
michael@0 | 523 | * force an attribute to a specifc value. |
michael@0 | 524 | */ |
michael@0 | 525 | CK_RV |
michael@0 | 526 | sftk_forceAttribute(SFTKObject *object,CK_ATTRIBUTE_TYPE type, |
michael@0 | 527 | const void *value, unsigned int len) |
michael@0 | 528 | { |
michael@0 | 529 | SFTKAttribute *attribute; |
michael@0 | 530 | void *att_val = NULL; |
michael@0 | 531 | PRBool freeData = PR_FALSE; |
michael@0 | 532 | |
michael@0 | 533 | PORT_Assert(object); |
michael@0 | 534 | PORT_Assert(object->refCount); |
michael@0 | 535 | PORT_Assert(object->slot); |
michael@0 | 536 | if (!object || |
michael@0 | 537 | !object->refCount || |
michael@0 | 538 | !object->slot) { |
michael@0 | 539 | return CKR_DEVICE_ERROR; |
michael@0 | 540 | } |
michael@0 | 541 | if (sftk_isToken(object->handle)) { |
michael@0 | 542 | return sftk_forceTokenAttribute(object,type,value,len); |
michael@0 | 543 | } |
michael@0 | 544 | attribute=sftk_FindAttribute(object,type); |
michael@0 | 545 | if (attribute == NULL) return sftk_AddAttributeType(object,type,value,len); |
michael@0 | 546 | |
michael@0 | 547 | |
michael@0 | 548 | if (value) { |
michael@0 | 549 | if (len <= ATTR_SPACE) { |
michael@0 | 550 | att_val = attribute->space; |
michael@0 | 551 | } else { |
michael@0 | 552 | att_val = PORT_Alloc(len); |
michael@0 | 553 | freeData = PR_TRUE; |
michael@0 | 554 | } |
michael@0 | 555 | if (att_val == NULL) { |
michael@0 | 556 | return CKR_HOST_MEMORY; |
michael@0 | 557 | } |
michael@0 | 558 | if (attribute->attrib.pValue == att_val) { |
michael@0 | 559 | PORT_Memset(attribute->attrib.pValue,0, |
michael@0 | 560 | attribute->attrib.ulValueLen); |
michael@0 | 561 | } |
michael@0 | 562 | PORT_Memcpy(att_val,value,len); |
michael@0 | 563 | } |
michael@0 | 564 | if (attribute->attrib.pValue != NULL) { |
michael@0 | 565 | if (attribute->attrib.pValue != att_val) { |
michael@0 | 566 | PORT_Memset(attribute->attrib.pValue,0, |
michael@0 | 567 | attribute->attrib.ulValueLen); |
michael@0 | 568 | } |
michael@0 | 569 | if (attribute->freeData) { |
michael@0 | 570 | PORT_Free(attribute->attrib.pValue); |
michael@0 | 571 | } |
michael@0 | 572 | attribute->freeData = PR_FALSE; |
michael@0 | 573 | attribute->attrib.pValue = NULL; |
michael@0 | 574 | attribute->attrib.ulValueLen = 0; |
michael@0 | 575 | } |
michael@0 | 576 | if (att_val) { |
michael@0 | 577 | attribute->attrib.pValue = att_val; |
michael@0 | 578 | attribute->attrib.ulValueLen = len; |
michael@0 | 579 | attribute->freeData = freeData; |
michael@0 | 580 | } |
michael@0 | 581 | sftk_FreeAttribute(attribute); |
michael@0 | 582 | return CKR_OK; |
michael@0 | 583 | } |
michael@0 | 584 | |
michael@0 | 585 | /* |
michael@0 | 586 | * return a null terminated string from attribute 'type'. This string |
michael@0 | 587 | * is allocated and needs to be freed with PORT_Free() When complete. |
michael@0 | 588 | */ |
michael@0 | 589 | char * |
michael@0 | 590 | sftk_getString(SFTKObject *object,CK_ATTRIBUTE_TYPE type) |
michael@0 | 591 | { |
michael@0 | 592 | SFTKAttribute *attribute; |
michael@0 | 593 | char *label = NULL; |
michael@0 | 594 | |
michael@0 | 595 | attribute=sftk_FindAttribute(object,type); |
michael@0 | 596 | if (attribute == NULL) return NULL; |
michael@0 | 597 | |
michael@0 | 598 | if (attribute->attrib.pValue != NULL) { |
michael@0 | 599 | label = (char *) PORT_Alloc(attribute->attrib.ulValueLen+1); |
michael@0 | 600 | if (label == NULL) { |
michael@0 | 601 | sftk_FreeAttribute(attribute); |
michael@0 | 602 | return NULL; |
michael@0 | 603 | } |
michael@0 | 604 | |
michael@0 | 605 | PORT_Memcpy(label,attribute->attrib.pValue, |
michael@0 | 606 | attribute->attrib.ulValueLen); |
michael@0 | 607 | label[attribute->attrib.ulValueLen] = 0; |
michael@0 | 608 | } |
michael@0 | 609 | sftk_FreeAttribute(attribute); |
michael@0 | 610 | return label; |
michael@0 | 611 | } |
michael@0 | 612 | |
michael@0 | 613 | /* |
michael@0 | 614 | * decode when a particular attribute may be modified |
michael@0 | 615 | * SFTK_NEVER: This attribute must be set at object creation time and |
michael@0 | 616 | * can never be modified. |
michael@0 | 617 | * SFTK_ONCOPY: This attribute may be modified only when you copy the |
michael@0 | 618 | * object. |
michael@0 | 619 | * SFTK_SENSITIVE: The CKA_SENSITIVE attribute can only be changed from |
michael@0 | 620 | * CK_FALSE to CK_TRUE. |
michael@0 | 621 | * SFTK_ALWAYS: This attribute can always be modified. |
michael@0 | 622 | * Some attributes vary their modification type based on the class of the |
michael@0 | 623 | * object. |
michael@0 | 624 | */ |
michael@0 | 625 | SFTKModifyType |
michael@0 | 626 | sftk_modifyType(CK_ATTRIBUTE_TYPE type, CK_OBJECT_CLASS inClass) |
michael@0 | 627 | { |
michael@0 | 628 | /* if we don't know about it, user user defined, always allow modify */ |
michael@0 | 629 | SFTKModifyType mtype = SFTK_ALWAYS; |
michael@0 | 630 | |
michael@0 | 631 | switch(type) { |
michael@0 | 632 | /* NEVER */ |
michael@0 | 633 | case CKA_CLASS: |
michael@0 | 634 | case CKA_CERTIFICATE_TYPE: |
michael@0 | 635 | case CKA_KEY_TYPE: |
michael@0 | 636 | case CKA_MODULUS: |
michael@0 | 637 | case CKA_MODULUS_BITS: |
michael@0 | 638 | case CKA_PUBLIC_EXPONENT: |
michael@0 | 639 | case CKA_PRIVATE_EXPONENT: |
michael@0 | 640 | case CKA_PRIME: |
michael@0 | 641 | case CKA_SUBPRIME: |
michael@0 | 642 | case CKA_BASE: |
michael@0 | 643 | case CKA_PRIME_1: |
michael@0 | 644 | case CKA_PRIME_2: |
michael@0 | 645 | case CKA_EXPONENT_1: |
michael@0 | 646 | case CKA_EXPONENT_2: |
michael@0 | 647 | case CKA_COEFFICIENT: |
michael@0 | 648 | case CKA_VALUE_LEN: |
michael@0 | 649 | case CKA_ALWAYS_SENSITIVE: |
michael@0 | 650 | case CKA_NEVER_EXTRACTABLE: |
michael@0 | 651 | case CKA_NETSCAPE_DB: |
michael@0 | 652 | mtype = SFTK_NEVER; |
michael@0 | 653 | break; |
michael@0 | 654 | |
michael@0 | 655 | /* ONCOPY */ |
michael@0 | 656 | case CKA_TOKEN: |
michael@0 | 657 | case CKA_PRIVATE: |
michael@0 | 658 | case CKA_MODIFIABLE: |
michael@0 | 659 | mtype = SFTK_ONCOPY; |
michael@0 | 660 | break; |
michael@0 | 661 | |
michael@0 | 662 | /* SENSITIVE */ |
michael@0 | 663 | case CKA_SENSITIVE: |
michael@0 | 664 | case CKA_EXTRACTABLE: |
michael@0 | 665 | mtype = SFTK_SENSITIVE; |
michael@0 | 666 | break; |
michael@0 | 667 | |
michael@0 | 668 | /* ALWAYS */ |
michael@0 | 669 | case CKA_LABEL: |
michael@0 | 670 | case CKA_APPLICATION: |
michael@0 | 671 | case CKA_ID: |
michael@0 | 672 | case CKA_SERIAL_NUMBER: |
michael@0 | 673 | case CKA_START_DATE: |
michael@0 | 674 | case CKA_END_DATE: |
michael@0 | 675 | case CKA_DERIVE: |
michael@0 | 676 | case CKA_ENCRYPT: |
michael@0 | 677 | case CKA_DECRYPT: |
michael@0 | 678 | case CKA_SIGN: |
michael@0 | 679 | case CKA_VERIFY: |
michael@0 | 680 | case CKA_SIGN_RECOVER: |
michael@0 | 681 | case CKA_VERIFY_RECOVER: |
michael@0 | 682 | case CKA_WRAP: |
michael@0 | 683 | case CKA_UNWRAP: |
michael@0 | 684 | mtype = SFTK_ALWAYS; |
michael@0 | 685 | break; |
michael@0 | 686 | |
michael@0 | 687 | /* DEPENDS ON CLASS */ |
michael@0 | 688 | case CKA_VALUE: |
michael@0 | 689 | mtype = (inClass == CKO_DATA) ? SFTK_ALWAYS : SFTK_NEVER; |
michael@0 | 690 | break; |
michael@0 | 691 | |
michael@0 | 692 | case CKA_SUBJECT: |
michael@0 | 693 | mtype = (inClass == CKO_CERTIFICATE) ? SFTK_NEVER : SFTK_ALWAYS; |
michael@0 | 694 | break; |
michael@0 | 695 | default: |
michael@0 | 696 | break; |
michael@0 | 697 | } |
michael@0 | 698 | return mtype; |
michael@0 | 699 | } |
michael@0 | 700 | |
michael@0 | 701 | /* decode if a particular attribute is sensitive (cannot be read |
michael@0 | 702 | * back to the user of if the object is set to SENSITIVE) */ |
michael@0 | 703 | PRBool |
michael@0 | 704 | sftk_isSensitive(CK_ATTRIBUTE_TYPE type, CK_OBJECT_CLASS inClass) |
michael@0 | 705 | { |
michael@0 | 706 | switch(type) { |
michael@0 | 707 | /* ALWAYS */ |
michael@0 | 708 | case CKA_PRIVATE_EXPONENT: |
michael@0 | 709 | case CKA_PRIME_1: |
michael@0 | 710 | case CKA_PRIME_2: |
michael@0 | 711 | case CKA_EXPONENT_1: |
michael@0 | 712 | case CKA_EXPONENT_2: |
michael@0 | 713 | case CKA_COEFFICIENT: |
michael@0 | 714 | return PR_TRUE; |
michael@0 | 715 | |
michael@0 | 716 | /* DEPENDS ON CLASS */ |
michael@0 | 717 | case CKA_VALUE: |
michael@0 | 718 | /* PRIVATE and SECRET KEYS have SENSITIVE values */ |
michael@0 | 719 | return (PRBool)((inClass == CKO_PRIVATE_KEY) || (inClass == CKO_SECRET_KEY)); |
michael@0 | 720 | |
michael@0 | 721 | default: |
michael@0 | 722 | break; |
michael@0 | 723 | } |
michael@0 | 724 | return PR_FALSE; |
michael@0 | 725 | } |
michael@0 | 726 | |
michael@0 | 727 | /* |
michael@0 | 728 | * copy an attribute into a SECItem. Secitem is allocated in the specified |
michael@0 | 729 | * arena. |
michael@0 | 730 | */ |
michael@0 | 731 | CK_RV |
michael@0 | 732 | sftk_Attribute2SecItem(PLArenaPool *arena,SECItem *item,SFTKObject *object, |
michael@0 | 733 | CK_ATTRIBUTE_TYPE type) |
michael@0 | 734 | { |
michael@0 | 735 | int len; |
michael@0 | 736 | SFTKAttribute *attribute; |
michael@0 | 737 | |
michael@0 | 738 | attribute = sftk_FindAttribute(object, type); |
michael@0 | 739 | if (attribute == NULL) return CKR_TEMPLATE_INCOMPLETE; |
michael@0 | 740 | len = attribute->attrib.ulValueLen; |
michael@0 | 741 | |
michael@0 | 742 | if (arena) { |
michael@0 | 743 | item->data = (unsigned char *) PORT_ArenaAlloc(arena,len); |
michael@0 | 744 | } else { |
michael@0 | 745 | item->data = (unsigned char *) PORT_Alloc(len); |
michael@0 | 746 | } |
michael@0 | 747 | if (item->data == NULL) { |
michael@0 | 748 | sftk_FreeAttribute(attribute); |
michael@0 | 749 | return CKR_HOST_MEMORY; |
michael@0 | 750 | } |
michael@0 | 751 | item->len = len; |
michael@0 | 752 | PORT_Memcpy(item->data,attribute->attrib.pValue, len); |
michael@0 | 753 | sftk_FreeAttribute(attribute); |
michael@0 | 754 | return CKR_OK; |
michael@0 | 755 | } |
michael@0 | 756 | |
michael@0 | 757 | CK_RV |
michael@0 | 758 | sftk_GetULongAttribute(SFTKObject *object, CK_ATTRIBUTE_TYPE type, |
michael@0 | 759 | CK_ULONG *longData) |
michael@0 | 760 | { |
michael@0 | 761 | SFTKAttribute *attribute; |
michael@0 | 762 | |
michael@0 | 763 | attribute = sftk_FindAttribute(object, type); |
michael@0 | 764 | if (attribute == NULL) return CKR_TEMPLATE_INCOMPLETE; |
michael@0 | 765 | |
michael@0 | 766 | if (attribute->attrib.ulValueLen != sizeof(CK_ULONG)) { |
michael@0 | 767 | return CKR_ATTRIBUTE_VALUE_INVALID; |
michael@0 | 768 | } |
michael@0 | 769 | |
michael@0 | 770 | *longData = *(CK_ULONG *)attribute->attrib.pValue; |
michael@0 | 771 | sftk_FreeAttribute(attribute); |
michael@0 | 772 | return CKR_OK; |
michael@0 | 773 | } |
michael@0 | 774 | |
michael@0 | 775 | void |
michael@0 | 776 | sftk_DeleteAttributeType(SFTKObject *object,CK_ATTRIBUTE_TYPE type) |
michael@0 | 777 | { |
michael@0 | 778 | SFTKAttribute *attribute; |
michael@0 | 779 | attribute = sftk_FindAttribute(object, type); |
michael@0 | 780 | if (attribute == NULL) return ; |
michael@0 | 781 | sftk_DeleteAttribute(object,attribute); |
michael@0 | 782 | sftk_FreeAttribute(attribute); |
michael@0 | 783 | } |
michael@0 | 784 | |
michael@0 | 785 | CK_RV |
michael@0 | 786 | sftk_AddAttributeType(SFTKObject *object,CK_ATTRIBUTE_TYPE type, |
michael@0 | 787 | const void *valPtr, CK_ULONG length) |
michael@0 | 788 | { |
michael@0 | 789 | SFTKAttribute *attribute; |
michael@0 | 790 | attribute = sftk_NewAttribute(object,type,valPtr,length); |
michael@0 | 791 | if (attribute == NULL) { return CKR_HOST_MEMORY; } |
michael@0 | 792 | sftk_AddAttribute(object,attribute); |
michael@0 | 793 | return CKR_OK; |
michael@0 | 794 | } |
michael@0 | 795 | |
michael@0 | 796 | /* |
michael@0 | 797 | * ******************** Object Utilities ******************************* |
michael@0 | 798 | */ |
michael@0 | 799 | |
michael@0 | 800 | /* must be called holding sftk_tokenKeyLock(slot) */ |
michael@0 | 801 | static SECItem * |
michael@0 | 802 | sftk_lookupTokenKeyByHandle(SFTKSlot *slot, CK_OBJECT_HANDLE handle) |
michael@0 | 803 | { |
michael@0 | 804 | return (SECItem *)PL_HashTableLookup(slot->tokObjHashTable, (void *)handle); |
michael@0 | 805 | } |
michael@0 | 806 | |
michael@0 | 807 | /* |
michael@0 | 808 | * use the refLock. This operations should be very rare, so the added |
michael@0 | 809 | * contention on the ref lock should be lower than the overhead of adding |
michael@0 | 810 | * a new lock. We use separate functions for this just in case I'm wrong. |
michael@0 | 811 | */ |
michael@0 | 812 | static void |
michael@0 | 813 | sftk_tokenKeyLock(SFTKSlot *slot) { |
michael@0 | 814 | SKIP_AFTER_FORK(PZ_Lock(slot->objectLock)); |
michael@0 | 815 | } |
michael@0 | 816 | |
michael@0 | 817 | static void |
michael@0 | 818 | sftk_tokenKeyUnlock(SFTKSlot *slot) { |
michael@0 | 819 | SKIP_AFTER_FORK(PZ_Unlock(slot->objectLock)); |
michael@0 | 820 | } |
michael@0 | 821 | |
michael@0 | 822 | static PRIntn |
michael@0 | 823 | sftk_freeHashItem(PLHashEntry* entry, PRIntn index, void *arg) |
michael@0 | 824 | { |
michael@0 | 825 | SECItem *item = (SECItem *)entry->value; |
michael@0 | 826 | |
michael@0 | 827 | SECITEM_FreeItem(item, PR_TRUE); |
michael@0 | 828 | return HT_ENUMERATE_NEXT; |
michael@0 | 829 | } |
michael@0 | 830 | |
michael@0 | 831 | CK_RV |
michael@0 | 832 | SFTK_ClearTokenKeyHashTable(SFTKSlot *slot) |
michael@0 | 833 | { |
michael@0 | 834 | sftk_tokenKeyLock(slot); |
michael@0 | 835 | PORT_Assert(!slot->present); |
michael@0 | 836 | PL_HashTableEnumerateEntries(slot->tokObjHashTable, sftk_freeHashItem, NULL); |
michael@0 | 837 | sftk_tokenKeyUnlock(slot); |
michael@0 | 838 | return CKR_OK; |
michael@0 | 839 | } |
michael@0 | 840 | |
michael@0 | 841 | |
michael@0 | 842 | /* allocation hooks that allow us to recycle old object structures */ |
michael@0 | 843 | static SFTKObjectFreeList sessionObjectList = { NULL, NULL, 0 }; |
michael@0 | 844 | static SFTKObjectFreeList tokenObjectList = { NULL, NULL, 0 }; |
michael@0 | 845 | |
michael@0 | 846 | SFTKObject * |
michael@0 | 847 | sftk_GetObjectFromList(PRBool *hasLocks, PRBool optimizeSpace, |
michael@0 | 848 | SFTKObjectFreeList *list, unsigned int hashSize, PRBool isSessionObject) |
michael@0 | 849 | { |
michael@0 | 850 | SFTKObject *object; |
michael@0 | 851 | int size = 0; |
michael@0 | 852 | |
michael@0 | 853 | if (!optimizeSpace) { |
michael@0 | 854 | PZ_Lock(list->lock); |
michael@0 | 855 | object = list->head; |
michael@0 | 856 | if (object) { |
michael@0 | 857 | list->head = object->next; |
michael@0 | 858 | list->count--; |
michael@0 | 859 | } |
michael@0 | 860 | PZ_Unlock(list->lock); |
michael@0 | 861 | if (object) { |
michael@0 | 862 | object->next = object->prev = NULL; |
michael@0 | 863 | *hasLocks = PR_TRUE; |
michael@0 | 864 | return object; |
michael@0 | 865 | } |
michael@0 | 866 | } |
michael@0 | 867 | size = isSessionObject ? sizeof(SFTKSessionObject) |
michael@0 | 868 | + hashSize *sizeof(SFTKAttribute *) : sizeof(SFTKTokenObject); |
michael@0 | 869 | |
michael@0 | 870 | object = (SFTKObject*)PORT_ZAlloc(size); |
michael@0 | 871 | if (isSessionObject && object) { |
michael@0 | 872 | ((SFTKSessionObject *)object)->hashSize = hashSize; |
michael@0 | 873 | } |
michael@0 | 874 | *hasLocks = PR_FALSE; |
michael@0 | 875 | return object; |
michael@0 | 876 | } |
michael@0 | 877 | |
michael@0 | 878 | static void |
michael@0 | 879 | sftk_PutObjectToList(SFTKObject *object, SFTKObjectFreeList *list, |
michael@0 | 880 | PRBool isSessionObject) { |
michael@0 | 881 | |
michael@0 | 882 | /* the code below is equivalent to : |
michael@0 | 883 | * optimizeSpace = isSessionObject ? object->optimizeSpace : PR_FALSE; |
michael@0 | 884 | * just faster. |
michael@0 | 885 | */ |
michael@0 | 886 | PRBool optimizeSpace = isSessionObject && |
michael@0 | 887 | ((SFTKSessionObject *)object)->optimizeSpace; |
michael@0 | 888 | if (object->refLock && !optimizeSpace |
michael@0 | 889 | && (list->count < MAX_OBJECT_LIST_SIZE)) { |
michael@0 | 890 | PZ_Lock(list->lock); |
michael@0 | 891 | object->next = list->head; |
michael@0 | 892 | list->head = object; |
michael@0 | 893 | list->count++; |
michael@0 | 894 | PZ_Unlock(list->lock); |
michael@0 | 895 | return; |
michael@0 | 896 | } |
michael@0 | 897 | if (isSessionObject) { |
michael@0 | 898 | SFTKSessionObject *so = (SFTKSessionObject *)object; |
michael@0 | 899 | PZ_DestroyLock(so->attributeLock); |
michael@0 | 900 | so->attributeLock = NULL; |
michael@0 | 901 | } |
michael@0 | 902 | if (object->refLock) { |
michael@0 | 903 | PZ_DestroyLock(object->refLock); |
michael@0 | 904 | object->refLock = NULL; |
michael@0 | 905 | } |
michael@0 | 906 | PORT_Free(object); |
michael@0 | 907 | } |
michael@0 | 908 | |
michael@0 | 909 | static SFTKObject * |
michael@0 | 910 | sftk_freeObjectData(SFTKObject *object) { |
michael@0 | 911 | SFTKObject *next = object->next; |
michael@0 | 912 | |
michael@0 | 913 | PORT_Free(object); |
michael@0 | 914 | return next; |
michael@0 | 915 | } |
michael@0 | 916 | |
michael@0 | 917 | static void |
michael@0 | 918 | sftk_InitFreeList(SFTKObjectFreeList *list) |
michael@0 | 919 | { |
michael@0 | 920 | list->lock = PZ_NewLock(nssILockObject); |
michael@0 | 921 | } |
michael@0 | 922 | |
michael@0 | 923 | void sftk_InitFreeLists(void) |
michael@0 | 924 | { |
michael@0 | 925 | sftk_InitFreeList(&sessionObjectList); |
michael@0 | 926 | sftk_InitFreeList(&tokenObjectList); |
michael@0 | 927 | } |
michael@0 | 928 | |
michael@0 | 929 | static void |
michael@0 | 930 | sftk_CleanupFreeList(SFTKObjectFreeList *list, PRBool isSessionList) |
michael@0 | 931 | { |
michael@0 | 932 | SFTKObject *object; |
michael@0 | 933 | |
michael@0 | 934 | if (!list->lock) { |
michael@0 | 935 | return; |
michael@0 | 936 | } |
michael@0 | 937 | SKIP_AFTER_FORK(PZ_Lock(list->lock)); |
michael@0 | 938 | for (object= list->head; object != NULL; |
michael@0 | 939 | object = sftk_freeObjectData(object)) { |
michael@0 | 940 | PZ_DestroyLock(object->refLock); |
michael@0 | 941 | if (isSessionList) { |
michael@0 | 942 | PZ_DestroyLock(((SFTKSessionObject *)object)->attributeLock); |
michael@0 | 943 | } |
michael@0 | 944 | } |
michael@0 | 945 | list->count = 0; |
michael@0 | 946 | list->head = NULL; |
michael@0 | 947 | SKIP_AFTER_FORK(PZ_Unlock(list->lock)); |
michael@0 | 948 | SKIP_AFTER_FORK(PZ_DestroyLock(list->lock)); |
michael@0 | 949 | list->lock = NULL; |
michael@0 | 950 | } |
michael@0 | 951 | |
michael@0 | 952 | void |
michael@0 | 953 | sftk_CleanupFreeLists(void) |
michael@0 | 954 | { |
michael@0 | 955 | sftk_CleanupFreeList(&sessionObjectList, PR_TRUE); |
michael@0 | 956 | sftk_CleanupFreeList(&tokenObjectList, PR_FALSE); |
michael@0 | 957 | } |
michael@0 | 958 | |
michael@0 | 959 | |
michael@0 | 960 | /* |
michael@0 | 961 | * Create a new object |
michael@0 | 962 | */ |
michael@0 | 963 | SFTKObject * |
michael@0 | 964 | sftk_NewObject(SFTKSlot *slot) |
michael@0 | 965 | { |
michael@0 | 966 | SFTKObject *object; |
michael@0 | 967 | SFTKSessionObject *sessObject; |
michael@0 | 968 | PRBool hasLocks = PR_FALSE; |
michael@0 | 969 | unsigned int i; |
michael@0 | 970 | unsigned int hashSize = 0; |
michael@0 | 971 | |
michael@0 | 972 | hashSize = (slot->optimizeSpace) ? SPACE_ATTRIBUTE_HASH_SIZE : |
michael@0 | 973 | TIME_ATTRIBUTE_HASH_SIZE; |
michael@0 | 974 | |
michael@0 | 975 | object = sftk_GetObjectFromList(&hasLocks, slot->optimizeSpace, |
michael@0 | 976 | &sessionObjectList, hashSize, PR_TRUE); |
michael@0 | 977 | if (object == NULL) { |
michael@0 | 978 | return NULL; |
michael@0 | 979 | } |
michael@0 | 980 | sessObject = (SFTKSessionObject *)object; |
michael@0 | 981 | sessObject->nextAttr = 0; |
michael@0 | 982 | |
michael@0 | 983 | for (i=0; i < MAX_OBJS_ATTRS; i++) { |
michael@0 | 984 | sessObject->attrList[i].attrib.pValue = NULL; |
michael@0 | 985 | sessObject->attrList[i].freeData = PR_FALSE; |
michael@0 | 986 | } |
michael@0 | 987 | sessObject->optimizeSpace = slot->optimizeSpace; |
michael@0 | 988 | |
michael@0 | 989 | object->handle = 0; |
michael@0 | 990 | object->next = object->prev = NULL; |
michael@0 | 991 | object->slot = slot; |
michael@0 | 992 | |
michael@0 | 993 | object->refCount = 1; |
michael@0 | 994 | sessObject->sessionList.next = NULL; |
michael@0 | 995 | sessObject->sessionList.prev = NULL; |
michael@0 | 996 | sessObject->sessionList.parent = object; |
michael@0 | 997 | sessObject->session = NULL; |
michael@0 | 998 | sessObject->wasDerived = PR_FALSE; |
michael@0 | 999 | if (!hasLocks) object->refLock = PZ_NewLock(nssILockRefLock); |
michael@0 | 1000 | if (object->refLock == NULL) { |
michael@0 | 1001 | PORT_Free(object); |
michael@0 | 1002 | return NULL; |
michael@0 | 1003 | } |
michael@0 | 1004 | if (!hasLocks) sessObject->attributeLock = PZ_NewLock(nssILockAttribute); |
michael@0 | 1005 | if (sessObject->attributeLock == NULL) { |
michael@0 | 1006 | PZ_DestroyLock(object->refLock); |
michael@0 | 1007 | PORT_Free(object); |
michael@0 | 1008 | return NULL; |
michael@0 | 1009 | } |
michael@0 | 1010 | for (i=0; i < sessObject->hashSize; i++) { |
michael@0 | 1011 | sessObject->head[i] = NULL; |
michael@0 | 1012 | } |
michael@0 | 1013 | object->objectInfo = NULL; |
michael@0 | 1014 | object->infoFree = NULL; |
michael@0 | 1015 | return object; |
michael@0 | 1016 | } |
michael@0 | 1017 | |
michael@0 | 1018 | static CK_RV |
michael@0 | 1019 | sftk_DestroySessionObjectData(SFTKSessionObject *so) |
michael@0 | 1020 | { |
michael@0 | 1021 | int i; |
michael@0 | 1022 | |
michael@0 | 1023 | for (i=0; i < MAX_OBJS_ATTRS; i++) { |
michael@0 | 1024 | unsigned char *value = so->attrList[i].attrib.pValue; |
michael@0 | 1025 | if (value) { |
michael@0 | 1026 | PORT_Memset(value,0,so->attrList[i].attrib.ulValueLen); |
michael@0 | 1027 | if (so->attrList[i].freeData) { |
michael@0 | 1028 | PORT_Free(value); |
michael@0 | 1029 | } |
michael@0 | 1030 | so->attrList[i].attrib.pValue = NULL; |
michael@0 | 1031 | so->attrList[i].freeData = PR_FALSE; |
michael@0 | 1032 | } |
michael@0 | 1033 | } |
michael@0 | 1034 | /* PZ_DestroyLock(so->attributeLock);*/ |
michael@0 | 1035 | return CKR_OK; |
michael@0 | 1036 | } |
michael@0 | 1037 | |
michael@0 | 1038 | /* |
michael@0 | 1039 | * free all the data associated with an object. Object reference count must |
michael@0 | 1040 | * be 'zero'. |
michael@0 | 1041 | */ |
michael@0 | 1042 | static CK_RV |
michael@0 | 1043 | sftk_DestroyObject(SFTKObject *object) |
michael@0 | 1044 | { |
michael@0 | 1045 | CK_RV crv = CKR_OK; |
michael@0 | 1046 | SFTKSessionObject *so = sftk_narrowToSessionObject(object); |
michael@0 | 1047 | SFTKTokenObject *to = sftk_narrowToTokenObject(object); |
michael@0 | 1048 | |
michael@0 | 1049 | PORT_Assert(object->refCount == 0); |
michael@0 | 1050 | |
michael@0 | 1051 | /* delete the database value */ |
michael@0 | 1052 | if (to) { |
michael@0 | 1053 | if (to->dbKey.data) { |
michael@0 | 1054 | PORT_Free(to->dbKey.data); |
michael@0 | 1055 | to->dbKey.data = NULL; |
michael@0 | 1056 | } |
michael@0 | 1057 | } |
michael@0 | 1058 | if (so) { |
michael@0 | 1059 | sftk_DestroySessionObjectData(so); |
michael@0 | 1060 | } |
michael@0 | 1061 | if (object->objectInfo) { |
michael@0 | 1062 | (*object->infoFree)(object->objectInfo); |
michael@0 | 1063 | object->objectInfo = NULL; |
michael@0 | 1064 | object->infoFree = NULL; |
michael@0 | 1065 | } |
michael@0 | 1066 | if (so) { |
michael@0 | 1067 | sftk_PutObjectToList(object,&sessionObjectList,PR_TRUE); |
michael@0 | 1068 | } else { |
michael@0 | 1069 | sftk_PutObjectToList(object,&tokenObjectList,PR_FALSE); |
michael@0 | 1070 | } |
michael@0 | 1071 | return crv; |
michael@0 | 1072 | } |
michael@0 | 1073 | |
michael@0 | 1074 | void |
michael@0 | 1075 | sftk_ReferenceObject(SFTKObject *object) |
michael@0 | 1076 | { |
michael@0 | 1077 | PZ_Lock(object->refLock); |
michael@0 | 1078 | object->refCount++; |
michael@0 | 1079 | PZ_Unlock(object->refLock); |
michael@0 | 1080 | } |
michael@0 | 1081 | |
michael@0 | 1082 | static SFTKObject * |
michael@0 | 1083 | sftk_ObjectFromHandleOnSlot(CK_OBJECT_HANDLE handle, SFTKSlot *slot) |
michael@0 | 1084 | { |
michael@0 | 1085 | SFTKObject *object; |
michael@0 | 1086 | PRUint32 index = sftk_hash(handle, slot->sessObjHashSize); |
michael@0 | 1087 | |
michael@0 | 1088 | if (sftk_isToken(handle)) { |
michael@0 | 1089 | return sftk_NewTokenObject(slot, NULL, handle); |
michael@0 | 1090 | } |
michael@0 | 1091 | |
michael@0 | 1092 | PZ_Lock(slot->objectLock); |
michael@0 | 1093 | sftkqueue_find2(object, handle, index, slot->sessObjHashTable); |
michael@0 | 1094 | if (object) { |
michael@0 | 1095 | sftk_ReferenceObject(object); |
michael@0 | 1096 | } |
michael@0 | 1097 | PZ_Unlock(slot->objectLock); |
michael@0 | 1098 | |
michael@0 | 1099 | return(object); |
michael@0 | 1100 | } |
michael@0 | 1101 | /* |
michael@0 | 1102 | * look up and object structure from a handle. OBJECT_Handles only make |
michael@0 | 1103 | * sense in terms of a given session. make a reference to that object |
michael@0 | 1104 | * structure returned. |
michael@0 | 1105 | */ |
michael@0 | 1106 | SFTKObject * |
michael@0 | 1107 | sftk_ObjectFromHandle(CK_OBJECT_HANDLE handle, SFTKSession *session) |
michael@0 | 1108 | { |
michael@0 | 1109 | SFTKSlot *slot = sftk_SlotFromSession(session); |
michael@0 | 1110 | |
michael@0 | 1111 | return sftk_ObjectFromHandleOnSlot(handle,slot); |
michael@0 | 1112 | } |
michael@0 | 1113 | |
michael@0 | 1114 | |
michael@0 | 1115 | /* |
michael@0 | 1116 | * release a reference to an object handle |
michael@0 | 1117 | */ |
michael@0 | 1118 | SFTKFreeStatus |
michael@0 | 1119 | sftk_FreeObject(SFTKObject *object) |
michael@0 | 1120 | { |
michael@0 | 1121 | PRBool destroy = PR_FALSE; |
michael@0 | 1122 | CK_RV crv; |
michael@0 | 1123 | |
michael@0 | 1124 | PZ_Lock(object->refLock); |
michael@0 | 1125 | if (object->refCount == 1) destroy = PR_TRUE; |
michael@0 | 1126 | object->refCount--; |
michael@0 | 1127 | PZ_Unlock(object->refLock); |
michael@0 | 1128 | |
michael@0 | 1129 | if (destroy) { |
michael@0 | 1130 | crv = sftk_DestroyObject(object); |
michael@0 | 1131 | if (crv != CKR_OK) { |
michael@0 | 1132 | return SFTK_DestroyFailure; |
michael@0 | 1133 | } |
michael@0 | 1134 | return SFTK_Destroyed; |
michael@0 | 1135 | } |
michael@0 | 1136 | return SFTK_Busy; |
michael@0 | 1137 | } |
michael@0 | 1138 | |
michael@0 | 1139 | /* |
michael@0 | 1140 | * add an object to a slot and session queue. These two functions |
michael@0 | 1141 | * adopt the object. |
michael@0 | 1142 | */ |
michael@0 | 1143 | void |
michael@0 | 1144 | sftk_AddSlotObject(SFTKSlot *slot, SFTKObject *object) |
michael@0 | 1145 | { |
michael@0 | 1146 | PRUint32 index = sftk_hash(object->handle, slot->sessObjHashSize); |
michael@0 | 1147 | sftkqueue_init_element(object); |
michael@0 | 1148 | PZ_Lock(slot->objectLock); |
michael@0 | 1149 | sftkqueue_add2(object, object->handle, index, slot->sessObjHashTable); |
michael@0 | 1150 | PZ_Unlock(slot->objectLock); |
michael@0 | 1151 | } |
michael@0 | 1152 | |
michael@0 | 1153 | void |
michael@0 | 1154 | sftk_AddObject(SFTKSession *session, SFTKObject *object) |
michael@0 | 1155 | { |
michael@0 | 1156 | SFTKSlot *slot = sftk_SlotFromSession(session); |
michael@0 | 1157 | SFTKSessionObject *so = sftk_narrowToSessionObject(object); |
michael@0 | 1158 | |
michael@0 | 1159 | if (so) { |
michael@0 | 1160 | PZ_Lock(session->objectLock); |
michael@0 | 1161 | sftkqueue_add(&so->sessionList,0,session->objects,0); |
michael@0 | 1162 | so->session = session; |
michael@0 | 1163 | PZ_Unlock(session->objectLock); |
michael@0 | 1164 | } |
michael@0 | 1165 | sftk_AddSlotObject(slot,object); |
michael@0 | 1166 | sftk_ReferenceObject(object); |
michael@0 | 1167 | } |
michael@0 | 1168 | |
michael@0 | 1169 | /* |
michael@0 | 1170 | * delete an object from a slot and session queue |
michael@0 | 1171 | */ |
michael@0 | 1172 | CK_RV |
michael@0 | 1173 | sftk_DeleteObject(SFTKSession *session, SFTKObject *object) |
michael@0 | 1174 | { |
michael@0 | 1175 | SFTKSlot *slot = sftk_SlotFromSession(session); |
michael@0 | 1176 | SFTKSessionObject *so = sftk_narrowToSessionObject(object); |
michael@0 | 1177 | SFTKTokenObject *to = sftk_narrowToTokenObject(object); |
michael@0 | 1178 | CK_RV crv = CKR_OK; |
michael@0 | 1179 | PRUint32 index = sftk_hash(object->handle, slot->sessObjHashSize); |
michael@0 | 1180 | |
michael@0 | 1181 | /* Handle Token case */ |
michael@0 | 1182 | if (so && so->session) { |
michael@0 | 1183 | SFTKSession *session = so->session; |
michael@0 | 1184 | PZ_Lock(session->objectLock); |
michael@0 | 1185 | sftkqueue_delete(&so->sessionList,0,session->objects,0); |
michael@0 | 1186 | PZ_Unlock(session->objectLock); |
michael@0 | 1187 | PZ_Lock(slot->objectLock); |
michael@0 | 1188 | sftkqueue_delete2(object, object->handle, index, slot->sessObjHashTable); |
michael@0 | 1189 | PZ_Unlock(slot->objectLock); |
michael@0 | 1190 | sftkqueue_clear_deleted_element(object); |
michael@0 | 1191 | sftk_FreeObject(object); /* free the reference owned by the queue */ |
michael@0 | 1192 | } else { |
michael@0 | 1193 | SFTKDBHandle *handle = sftk_getDBForTokenObject(slot, object->handle); |
michael@0 | 1194 | |
michael@0 | 1195 | PORT_Assert(to); |
michael@0 | 1196 | crv = sftkdb_DestroyObject(handle, object->handle); |
michael@0 | 1197 | sftk_freeDB(handle); |
michael@0 | 1198 | } |
michael@0 | 1199 | return crv; |
michael@0 | 1200 | } |
michael@0 | 1201 | |
michael@0 | 1202 | /* |
michael@0 | 1203 | * Token objects don't explicitly store their attributes, so we need to know |
michael@0 | 1204 | * what attributes make up a particular token object before we can copy it. |
michael@0 | 1205 | * below are the tables by object type. |
michael@0 | 1206 | */ |
michael@0 | 1207 | static const CK_ATTRIBUTE_TYPE commonAttrs[] = { |
michael@0 | 1208 | CKA_CLASS, CKA_TOKEN, CKA_PRIVATE, CKA_LABEL, CKA_MODIFIABLE |
michael@0 | 1209 | }; |
michael@0 | 1210 | static const CK_ULONG commonAttrsCount = |
michael@0 | 1211 | sizeof(commonAttrs)/sizeof(commonAttrs[0]); |
michael@0 | 1212 | |
michael@0 | 1213 | static const CK_ATTRIBUTE_TYPE commonKeyAttrs[] = { |
michael@0 | 1214 | CKA_ID, CKA_START_DATE, CKA_END_DATE, CKA_DERIVE, CKA_LOCAL, CKA_KEY_TYPE |
michael@0 | 1215 | }; |
michael@0 | 1216 | static const CK_ULONG commonKeyAttrsCount = |
michael@0 | 1217 | sizeof(commonKeyAttrs)/sizeof(commonKeyAttrs[0]); |
michael@0 | 1218 | |
michael@0 | 1219 | static const CK_ATTRIBUTE_TYPE secretKeyAttrs[] = { |
michael@0 | 1220 | CKA_SENSITIVE, CKA_EXTRACTABLE, CKA_ENCRYPT, CKA_DECRYPT, CKA_SIGN, |
michael@0 | 1221 | CKA_VERIFY, CKA_WRAP, CKA_UNWRAP, CKA_VALUE |
michael@0 | 1222 | }; |
michael@0 | 1223 | static const CK_ULONG secretKeyAttrsCount = |
michael@0 | 1224 | sizeof(secretKeyAttrs)/sizeof(secretKeyAttrs[0]); |
michael@0 | 1225 | |
michael@0 | 1226 | static const CK_ATTRIBUTE_TYPE commonPubKeyAttrs[] = { |
michael@0 | 1227 | CKA_ENCRYPT, CKA_VERIFY, CKA_VERIFY_RECOVER, CKA_WRAP, CKA_SUBJECT |
michael@0 | 1228 | }; |
michael@0 | 1229 | static const CK_ULONG commonPubKeyAttrsCount = |
michael@0 | 1230 | sizeof(commonPubKeyAttrs)/sizeof(commonPubKeyAttrs[0]); |
michael@0 | 1231 | |
michael@0 | 1232 | static const CK_ATTRIBUTE_TYPE rsaPubKeyAttrs[] = { |
michael@0 | 1233 | CKA_MODULUS, CKA_PUBLIC_EXPONENT |
michael@0 | 1234 | }; |
michael@0 | 1235 | static const CK_ULONG rsaPubKeyAttrsCount = |
michael@0 | 1236 | sizeof(rsaPubKeyAttrs)/sizeof(rsaPubKeyAttrs[0]); |
michael@0 | 1237 | |
michael@0 | 1238 | static const CK_ATTRIBUTE_TYPE dsaPubKeyAttrs[] = { |
michael@0 | 1239 | CKA_SUBPRIME, CKA_PRIME, CKA_BASE, CKA_VALUE |
michael@0 | 1240 | }; |
michael@0 | 1241 | static const CK_ULONG dsaPubKeyAttrsCount = |
michael@0 | 1242 | sizeof(dsaPubKeyAttrs)/sizeof(dsaPubKeyAttrs[0]); |
michael@0 | 1243 | |
michael@0 | 1244 | static const CK_ATTRIBUTE_TYPE dhPubKeyAttrs[] = { |
michael@0 | 1245 | CKA_PRIME, CKA_BASE, CKA_VALUE |
michael@0 | 1246 | }; |
michael@0 | 1247 | static const CK_ULONG dhPubKeyAttrsCount = |
michael@0 | 1248 | sizeof(dhPubKeyAttrs)/sizeof(dhPubKeyAttrs[0]); |
michael@0 | 1249 | #ifndef NSS_DISABLE_ECC |
michael@0 | 1250 | static const CK_ATTRIBUTE_TYPE ecPubKeyAttrs[] = { |
michael@0 | 1251 | CKA_EC_PARAMS, CKA_EC_POINT |
michael@0 | 1252 | }; |
michael@0 | 1253 | static const CK_ULONG ecPubKeyAttrsCount = |
michael@0 | 1254 | sizeof(ecPubKeyAttrs)/sizeof(ecPubKeyAttrs[0]); |
michael@0 | 1255 | #endif |
michael@0 | 1256 | |
michael@0 | 1257 | static const CK_ATTRIBUTE_TYPE commonPrivKeyAttrs[] = { |
michael@0 | 1258 | CKA_DECRYPT, CKA_SIGN, CKA_SIGN_RECOVER, CKA_UNWRAP, CKA_SUBJECT, |
michael@0 | 1259 | CKA_SENSITIVE, CKA_EXTRACTABLE, CKA_NETSCAPE_DB |
michael@0 | 1260 | }; |
michael@0 | 1261 | static const CK_ULONG commonPrivKeyAttrsCount = |
michael@0 | 1262 | sizeof(commonPrivKeyAttrs)/sizeof(commonPrivKeyAttrs[0]); |
michael@0 | 1263 | |
michael@0 | 1264 | static const CK_ATTRIBUTE_TYPE rsaPrivKeyAttrs[] = { |
michael@0 | 1265 | CKA_MODULUS, CKA_PUBLIC_EXPONENT, CKA_PRIVATE_EXPONENT, |
michael@0 | 1266 | CKA_PRIME_1, CKA_PRIME_2, CKA_EXPONENT_1, CKA_EXPONENT_2, CKA_COEFFICIENT |
michael@0 | 1267 | }; |
michael@0 | 1268 | static const CK_ULONG rsaPrivKeyAttrsCount = |
michael@0 | 1269 | sizeof(rsaPrivKeyAttrs)/sizeof(rsaPrivKeyAttrs[0]); |
michael@0 | 1270 | |
michael@0 | 1271 | static const CK_ATTRIBUTE_TYPE dsaPrivKeyAttrs[] = { |
michael@0 | 1272 | CKA_SUBPRIME, CKA_PRIME, CKA_BASE, CKA_VALUE |
michael@0 | 1273 | }; |
michael@0 | 1274 | static const CK_ULONG dsaPrivKeyAttrsCount = |
michael@0 | 1275 | sizeof(dsaPrivKeyAttrs)/sizeof(dsaPrivKeyAttrs[0]); |
michael@0 | 1276 | |
michael@0 | 1277 | static const CK_ATTRIBUTE_TYPE dhPrivKeyAttrs[] = { |
michael@0 | 1278 | CKA_PRIME, CKA_BASE, CKA_VALUE |
michael@0 | 1279 | }; |
michael@0 | 1280 | static const CK_ULONG dhPrivKeyAttrsCount = |
michael@0 | 1281 | sizeof(dhPrivKeyAttrs)/sizeof(dhPrivKeyAttrs[0]); |
michael@0 | 1282 | #ifndef NSS_DISABLE_ECC |
michael@0 | 1283 | static const CK_ATTRIBUTE_TYPE ecPrivKeyAttrs[] = { |
michael@0 | 1284 | CKA_EC_PARAMS, CKA_VALUE |
michael@0 | 1285 | }; |
michael@0 | 1286 | static const CK_ULONG ecPrivKeyAttrsCount = |
michael@0 | 1287 | sizeof(ecPrivKeyAttrs)/sizeof(ecPrivKeyAttrs[0]); |
michael@0 | 1288 | #endif |
michael@0 | 1289 | |
michael@0 | 1290 | static const CK_ATTRIBUTE_TYPE certAttrs[] = { |
michael@0 | 1291 | CKA_CERTIFICATE_TYPE, CKA_VALUE, CKA_SUBJECT, CKA_ISSUER, CKA_SERIAL_NUMBER |
michael@0 | 1292 | }; |
michael@0 | 1293 | static const CK_ULONG certAttrsCount = |
michael@0 | 1294 | sizeof(certAttrs)/sizeof(certAttrs[0]); |
michael@0 | 1295 | |
michael@0 | 1296 | static const CK_ATTRIBUTE_TYPE trustAttrs[] = { |
michael@0 | 1297 | CKA_ISSUER, CKA_SERIAL_NUMBER, CKA_CERT_SHA1_HASH, CKA_CERT_MD5_HASH, |
michael@0 | 1298 | CKA_TRUST_SERVER_AUTH, CKA_TRUST_CLIENT_AUTH, CKA_TRUST_EMAIL_PROTECTION, |
michael@0 | 1299 | CKA_TRUST_CODE_SIGNING, CKA_TRUST_STEP_UP_APPROVED |
michael@0 | 1300 | }; |
michael@0 | 1301 | static const CK_ULONG trustAttrsCount = |
michael@0 | 1302 | sizeof(trustAttrs)/sizeof(trustAttrs[0]); |
michael@0 | 1303 | |
michael@0 | 1304 | static const CK_ATTRIBUTE_TYPE smimeAttrs[] = { |
michael@0 | 1305 | CKA_SUBJECT, CKA_NETSCAPE_EMAIL, CKA_NETSCAPE_SMIME_TIMESTAMP, CKA_VALUE |
michael@0 | 1306 | }; |
michael@0 | 1307 | static const CK_ULONG smimeAttrsCount = |
michael@0 | 1308 | sizeof(smimeAttrs)/sizeof(smimeAttrs[0]); |
michael@0 | 1309 | |
michael@0 | 1310 | static const CK_ATTRIBUTE_TYPE crlAttrs[] = { |
michael@0 | 1311 | CKA_SUBJECT, CKA_VALUE, CKA_NETSCAPE_URL, CKA_NETSCAPE_KRL |
michael@0 | 1312 | }; |
michael@0 | 1313 | static const CK_ULONG crlAttrsCount = |
michael@0 | 1314 | sizeof(crlAttrs)/sizeof(crlAttrs[0]); |
michael@0 | 1315 | |
michael@0 | 1316 | /* copy an object based on it's table */ |
michael@0 | 1317 | CK_RV |
michael@0 | 1318 | stfk_CopyTokenAttributes(SFTKObject *destObject,SFTKTokenObject *src_to, |
michael@0 | 1319 | const CK_ATTRIBUTE_TYPE *attrArray, CK_ULONG attrCount) |
michael@0 | 1320 | { |
michael@0 | 1321 | SFTKAttribute *attribute; |
michael@0 | 1322 | SFTKAttribute *newAttribute; |
michael@0 | 1323 | CK_RV crv = CKR_OK; |
michael@0 | 1324 | unsigned int i; |
michael@0 | 1325 | |
michael@0 | 1326 | for (i=0; i < attrCount; i++) { |
michael@0 | 1327 | if (!sftk_hasAttribute(destObject,attrArray[i])) { |
michael@0 | 1328 | attribute =sftk_FindAttribute(&src_to->obj, attrArray[i]); |
michael@0 | 1329 | if (!attribute) { |
michael@0 | 1330 | continue; /* return CKR_ATTRIBUTE_VALUE_INVALID; */ |
michael@0 | 1331 | } |
michael@0 | 1332 | /* we need to copy the attribute since each attribute |
michael@0 | 1333 | * only has one set of link list pointers */ |
michael@0 | 1334 | newAttribute = sftk_NewAttribute( destObject, |
michael@0 | 1335 | sftk_attr_expand(&attribute->attrib)); |
michael@0 | 1336 | sftk_FreeAttribute(attribute); /* free the old attribute */ |
michael@0 | 1337 | if (!newAttribute) { |
michael@0 | 1338 | return CKR_HOST_MEMORY; |
michael@0 | 1339 | } |
michael@0 | 1340 | sftk_AddAttribute(destObject,newAttribute); |
michael@0 | 1341 | } |
michael@0 | 1342 | } |
michael@0 | 1343 | return crv; |
michael@0 | 1344 | } |
michael@0 | 1345 | |
michael@0 | 1346 | CK_RV |
michael@0 | 1347 | stfk_CopyTokenPrivateKey(SFTKObject *destObject,SFTKTokenObject *src_to) |
michael@0 | 1348 | { |
michael@0 | 1349 | CK_RV crv; |
michael@0 | 1350 | CK_KEY_TYPE key_type; |
michael@0 | 1351 | SFTKAttribute *attribute; |
michael@0 | 1352 | |
michael@0 | 1353 | /* copy the common attributes for all keys first */ |
michael@0 | 1354 | crv = stfk_CopyTokenAttributes(destObject, src_to, commonKeyAttrs, |
michael@0 | 1355 | commonKeyAttrsCount); |
michael@0 | 1356 | if (crv != CKR_OK) { |
michael@0 | 1357 | goto fail; |
michael@0 | 1358 | } |
michael@0 | 1359 | /* copy the common attributes for all private keys next */ |
michael@0 | 1360 | crv = stfk_CopyTokenAttributes(destObject, src_to, commonPrivKeyAttrs, |
michael@0 | 1361 | commonPrivKeyAttrsCount); |
michael@0 | 1362 | if (crv != CKR_OK) { |
michael@0 | 1363 | goto fail; |
michael@0 | 1364 | } |
michael@0 | 1365 | attribute =sftk_FindAttribute(&src_to->obj, CKA_KEY_TYPE); |
michael@0 | 1366 | PORT_Assert(attribute); /* if it wasn't here, ww should have failed |
michael@0 | 1367 | * copying the common attributes */ |
michael@0 | 1368 | if (!attribute) { |
michael@0 | 1369 | /* OK, so CKR_ATTRIBUTE_VALUE_INVALID is the immediate error, but |
michael@0 | 1370 | * the fact is, the only reason we couldn't get the attribute would |
michael@0 | 1371 | * be a memory error or database error (an error in the 'device'). |
michael@0 | 1372 | * if we have a database error code, we could return it here */ |
michael@0 | 1373 | crv = CKR_DEVICE_ERROR; |
michael@0 | 1374 | goto fail; |
michael@0 | 1375 | } |
michael@0 | 1376 | key_type = *(CK_KEY_TYPE *)attribute->attrib.pValue; |
michael@0 | 1377 | sftk_FreeAttribute(attribute); |
michael@0 | 1378 | |
michael@0 | 1379 | /* finally copy the attributes for various private key types */ |
michael@0 | 1380 | switch (key_type) { |
michael@0 | 1381 | case CKK_RSA: |
michael@0 | 1382 | crv = stfk_CopyTokenAttributes(destObject, src_to, rsaPrivKeyAttrs, |
michael@0 | 1383 | rsaPrivKeyAttrsCount); |
michael@0 | 1384 | break; |
michael@0 | 1385 | case CKK_DSA: |
michael@0 | 1386 | crv = stfk_CopyTokenAttributes(destObject, src_to, dsaPrivKeyAttrs, |
michael@0 | 1387 | dsaPrivKeyAttrsCount); |
michael@0 | 1388 | break; |
michael@0 | 1389 | case CKK_DH: |
michael@0 | 1390 | crv = stfk_CopyTokenAttributes(destObject, src_to, dhPrivKeyAttrs, |
michael@0 | 1391 | dhPrivKeyAttrsCount); |
michael@0 | 1392 | break; |
michael@0 | 1393 | #ifndef NSS_DISABLE_ECC |
michael@0 | 1394 | case CKK_EC: |
michael@0 | 1395 | crv = stfk_CopyTokenAttributes(destObject, src_to, ecPrivKeyAttrs, |
michael@0 | 1396 | ecPrivKeyAttrsCount); |
michael@0 | 1397 | break; |
michael@0 | 1398 | #endif |
michael@0 | 1399 | default: |
michael@0 | 1400 | crv = CKR_DEVICE_ERROR; /* shouldn't happen unless we store more types |
michael@0 | 1401 | * of token keys into our database. */ |
michael@0 | 1402 | } |
michael@0 | 1403 | fail: |
michael@0 | 1404 | return crv; |
michael@0 | 1405 | } |
michael@0 | 1406 | |
michael@0 | 1407 | CK_RV |
michael@0 | 1408 | stfk_CopyTokenPublicKey(SFTKObject *destObject,SFTKTokenObject *src_to) |
michael@0 | 1409 | { |
michael@0 | 1410 | CK_RV crv; |
michael@0 | 1411 | CK_KEY_TYPE key_type; |
michael@0 | 1412 | SFTKAttribute *attribute; |
michael@0 | 1413 | |
michael@0 | 1414 | /* copy the common attributes for all keys first */ |
michael@0 | 1415 | crv = stfk_CopyTokenAttributes(destObject, src_to, commonKeyAttrs, |
michael@0 | 1416 | commonKeyAttrsCount); |
michael@0 | 1417 | if (crv != CKR_OK) { |
michael@0 | 1418 | goto fail; |
michael@0 | 1419 | } |
michael@0 | 1420 | |
michael@0 | 1421 | /* copy the common attributes for all public keys next */ |
michael@0 | 1422 | crv = stfk_CopyTokenAttributes(destObject, src_to, commonPubKeyAttrs, |
michael@0 | 1423 | commonPubKeyAttrsCount); |
michael@0 | 1424 | if (crv != CKR_OK) { |
michael@0 | 1425 | goto fail; |
michael@0 | 1426 | } |
michael@0 | 1427 | attribute =sftk_FindAttribute(&src_to->obj, CKA_KEY_TYPE); |
michael@0 | 1428 | PORT_Assert(attribute); /* if it wasn't here, ww should have failed |
michael@0 | 1429 | * copying the common attributes */ |
michael@0 | 1430 | if (!attribute) { |
michael@0 | 1431 | /* OK, so CKR_ATTRIBUTE_VALUE_INVALID is the immediate error, but |
michael@0 | 1432 | * the fact is, the only reason we couldn't get the attribute would |
michael@0 | 1433 | * be a memory error or database error (an error in the 'device'). |
michael@0 | 1434 | * if we have a database error code, we could return it here */ |
michael@0 | 1435 | crv = CKR_DEVICE_ERROR; |
michael@0 | 1436 | goto fail; |
michael@0 | 1437 | } |
michael@0 | 1438 | key_type = *(CK_KEY_TYPE *)attribute->attrib.pValue; |
michael@0 | 1439 | sftk_FreeAttribute(attribute); |
michael@0 | 1440 | |
michael@0 | 1441 | /* finally copy the attributes for various public key types */ |
michael@0 | 1442 | switch (key_type) { |
michael@0 | 1443 | case CKK_RSA: |
michael@0 | 1444 | crv = stfk_CopyTokenAttributes(destObject, src_to, rsaPubKeyAttrs, |
michael@0 | 1445 | rsaPubKeyAttrsCount); |
michael@0 | 1446 | break; |
michael@0 | 1447 | case CKK_DSA: |
michael@0 | 1448 | crv = stfk_CopyTokenAttributes(destObject, src_to, dsaPubKeyAttrs, |
michael@0 | 1449 | dsaPubKeyAttrsCount); |
michael@0 | 1450 | break; |
michael@0 | 1451 | case CKK_DH: |
michael@0 | 1452 | crv = stfk_CopyTokenAttributes(destObject, src_to, dhPubKeyAttrs, |
michael@0 | 1453 | dhPubKeyAttrsCount); |
michael@0 | 1454 | break; |
michael@0 | 1455 | #ifndef NSS_DISABLE_ECC |
michael@0 | 1456 | case CKK_EC: |
michael@0 | 1457 | crv = stfk_CopyTokenAttributes(destObject, src_to, ecPubKeyAttrs, |
michael@0 | 1458 | ecPubKeyAttrsCount); |
michael@0 | 1459 | break; |
michael@0 | 1460 | #endif |
michael@0 | 1461 | default: |
michael@0 | 1462 | crv = CKR_DEVICE_ERROR; /* shouldn't happen unless we store more types |
michael@0 | 1463 | * of token keys into our database. */ |
michael@0 | 1464 | } |
michael@0 | 1465 | fail: |
michael@0 | 1466 | return crv; |
michael@0 | 1467 | } |
michael@0 | 1468 | CK_RV |
michael@0 | 1469 | stfk_CopyTokenSecretKey(SFTKObject *destObject,SFTKTokenObject *src_to) |
michael@0 | 1470 | { |
michael@0 | 1471 | CK_RV crv; |
michael@0 | 1472 | crv = stfk_CopyTokenAttributes(destObject, src_to, commonKeyAttrs, |
michael@0 | 1473 | commonKeyAttrsCount); |
michael@0 | 1474 | if (crv != CKR_OK) { |
michael@0 | 1475 | goto fail; |
michael@0 | 1476 | } |
michael@0 | 1477 | crv = stfk_CopyTokenAttributes(destObject, src_to, secretKeyAttrs, |
michael@0 | 1478 | secretKeyAttrsCount); |
michael@0 | 1479 | fail: |
michael@0 | 1480 | return crv; |
michael@0 | 1481 | } |
michael@0 | 1482 | |
michael@0 | 1483 | /* |
michael@0 | 1484 | * Copy a token object. We need to explicitly copy the relevant |
michael@0 | 1485 | * attributes since token objects don't store those attributes in |
michael@0 | 1486 | * the token itself. |
michael@0 | 1487 | */ |
michael@0 | 1488 | CK_RV |
michael@0 | 1489 | sftk_CopyTokenObject(SFTKObject *destObject,SFTKObject *srcObject) |
michael@0 | 1490 | { |
michael@0 | 1491 | SFTKTokenObject *src_to = sftk_narrowToTokenObject(srcObject); |
michael@0 | 1492 | CK_RV crv; |
michael@0 | 1493 | |
michael@0 | 1494 | PORT_Assert(src_to); |
michael@0 | 1495 | if (src_to == NULL) { |
michael@0 | 1496 | return CKR_DEVICE_ERROR; /* internal state inconsistant */ |
michael@0 | 1497 | } |
michael@0 | 1498 | |
michael@0 | 1499 | crv = stfk_CopyTokenAttributes(destObject, src_to, commonAttrs, |
michael@0 | 1500 | commonAttrsCount); |
michael@0 | 1501 | if (crv != CKR_OK) { |
michael@0 | 1502 | goto fail; |
michael@0 | 1503 | } |
michael@0 | 1504 | switch (src_to->obj.objclass) { |
michael@0 | 1505 | case CKO_CERTIFICATE: |
michael@0 | 1506 | crv = stfk_CopyTokenAttributes(destObject, src_to, certAttrs, |
michael@0 | 1507 | certAttrsCount); |
michael@0 | 1508 | break; |
michael@0 | 1509 | case CKO_NETSCAPE_TRUST: |
michael@0 | 1510 | crv = stfk_CopyTokenAttributes(destObject, src_to, trustAttrs, |
michael@0 | 1511 | trustAttrsCount); |
michael@0 | 1512 | break; |
michael@0 | 1513 | case CKO_NETSCAPE_SMIME: |
michael@0 | 1514 | crv = stfk_CopyTokenAttributes(destObject, src_to, smimeAttrs, |
michael@0 | 1515 | smimeAttrsCount); |
michael@0 | 1516 | break; |
michael@0 | 1517 | case CKO_NETSCAPE_CRL: |
michael@0 | 1518 | crv = stfk_CopyTokenAttributes(destObject, src_to, crlAttrs, |
michael@0 | 1519 | crlAttrsCount); |
michael@0 | 1520 | break; |
michael@0 | 1521 | case CKO_PRIVATE_KEY: |
michael@0 | 1522 | crv = stfk_CopyTokenPrivateKey(destObject,src_to); |
michael@0 | 1523 | break; |
michael@0 | 1524 | case CKO_PUBLIC_KEY: |
michael@0 | 1525 | crv = stfk_CopyTokenPublicKey(destObject,src_to); |
michael@0 | 1526 | break; |
michael@0 | 1527 | case CKO_SECRET_KEY: |
michael@0 | 1528 | crv = stfk_CopyTokenSecretKey(destObject,src_to); |
michael@0 | 1529 | break; |
michael@0 | 1530 | default: |
michael@0 | 1531 | crv = CKR_DEVICE_ERROR; /* shouldn't happen unless we store more types |
michael@0 | 1532 | * of token keys into our database. */ |
michael@0 | 1533 | } |
michael@0 | 1534 | fail: |
michael@0 | 1535 | return crv; |
michael@0 | 1536 | } |
michael@0 | 1537 | |
michael@0 | 1538 | /* |
michael@0 | 1539 | * copy the attributes from one object to another. Don't overwrite existing |
michael@0 | 1540 | * attributes. NOTE: This is a pretty expensive operation since it |
michael@0 | 1541 | * grabs the attribute locks for the src object for a *long* time. |
michael@0 | 1542 | */ |
michael@0 | 1543 | CK_RV |
michael@0 | 1544 | sftk_CopyObject(SFTKObject *destObject,SFTKObject *srcObject) |
michael@0 | 1545 | { |
michael@0 | 1546 | SFTKAttribute *attribute; |
michael@0 | 1547 | SFTKSessionObject *src_so = sftk_narrowToSessionObject(srcObject); |
michael@0 | 1548 | unsigned int i; |
michael@0 | 1549 | |
michael@0 | 1550 | if (src_so == NULL) { |
michael@0 | 1551 | return sftk_CopyTokenObject(destObject,srcObject); |
michael@0 | 1552 | } |
michael@0 | 1553 | |
michael@0 | 1554 | PZ_Lock(src_so->attributeLock); |
michael@0 | 1555 | for(i=0; i < src_so->hashSize; i++) { |
michael@0 | 1556 | attribute = src_so->head[i]; |
michael@0 | 1557 | do { |
michael@0 | 1558 | if (attribute) { |
michael@0 | 1559 | if (!sftk_hasAttribute(destObject,attribute->handle)) { |
michael@0 | 1560 | /* we need to copy the attribute since each attribute |
michael@0 | 1561 | * only has one set of link list pointers */ |
michael@0 | 1562 | SFTKAttribute *newAttribute = sftk_NewAttribute( |
michael@0 | 1563 | destObject,sftk_attr_expand(&attribute->attrib)); |
michael@0 | 1564 | if (newAttribute == NULL) { |
michael@0 | 1565 | PZ_Unlock(src_so->attributeLock); |
michael@0 | 1566 | return CKR_HOST_MEMORY; |
michael@0 | 1567 | } |
michael@0 | 1568 | sftk_AddAttribute(destObject,newAttribute); |
michael@0 | 1569 | } |
michael@0 | 1570 | attribute=attribute->next; |
michael@0 | 1571 | } |
michael@0 | 1572 | } while (attribute != NULL); |
michael@0 | 1573 | } |
michael@0 | 1574 | PZ_Unlock(src_so->attributeLock); |
michael@0 | 1575 | |
michael@0 | 1576 | return CKR_OK; |
michael@0 | 1577 | } |
michael@0 | 1578 | |
michael@0 | 1579 | /* |
michael@0 | 1580 | * ******************** Search Utilities ******************************* |
michael@0 | 1581 | */ |
michael@0 | 1582 | |
michael@0 | 1583 | /* add an object to a search list */ |
michael@0 | 1584 | CK_RV |
michael@0 | 1585 | AddToList(SFTKObjectListElement **list,SFTKObject *object) |
michael@0 | 1586 | { |
michael@0 | 1587 | SFTKObjectListElement *newElem = |
michael@0 | 1588 | (SFTKObjectListElement *)PORT_Alloc(sizeof(SFTKObjectListElement)); |
michael@0 | 1589 | |
michael@0 | 1590 | if (newElem == NULL) return CKR_HOST_MEMORY; |
michael@0 | 1591 | |
michael@0 | 1592 | newElem->next = *list; |
michael@0 | 1593 | newElem->object = object; |
michael@0 | 1594 | sftk_ReferenceObject(object); |
michael@0 | 1595 | |
michael@0 | 1596 | *list = newElem; |
michael@0 | 1597 | return CKR_OK; |
michael@0 | 1598 | } |
michael@0 | 1599 | |
michael@0 | 1600 | |
michael@0 | 1601 | /* return true if the object matches the template */ |
michael@0 | 1602 | PRBool |
michael@0 | 1603 | sftk_objectMatch(SFTKObject *object,CK_ATTRIBUTE_PTR theTemplate,int count) |
michael@0 | 1604 | { |
michael@0 | 1605 | int i; |
michael@0 | 1606 | |
michael@0 | 1607 | for (i=0; i < count; i++) { |
michael@0 | 1608 | SFTKAttribute *attribute = sftk_FindAttribute(object,theTemplate[i].type); |
michael@0 | 1609 | if (attribute == NULL) { |
michael@0 | 1610 | return PR_FALSE; |
michael@0 | 1611 | } |
michael@0 | 1612 | if (attribute->attrib.ulValueLen == theTemplate[i].ulValueLen) { |
michael@0 | 1613 | if (PORT_Memcmp(attribute->attrib.pValue,theTemplate[i].pValue, |
michael@0 | 1614 | theTemplate[i].ulValueLen) == 0) { |
michael@0 | 1615 | sftk_FreeAttribute(attribute); |
michael@0 | 1616 | continue; |
michael@0 | 1617 | } |
michael@0 | 1618 | } |
michael@0 | 1619 | sftk_FreeAttribute(attribute); |
michael@0 | 1620 | return PR_FALSE; |
michael@0 | 1621 | } |
michael@0 | 1622 | return PR_TRUE; |
michael@0 | 1623 | } |
michael@0 | 1624 | |
michael@0 | 1625 | /* search through all the objects in the queue and return the template matches |
michael@0 | 1626 | * in the object list. |
michael@0 | 1627 | */ |
michael@0 | 1628 | CK_RV |
michael@0 | 1629 | sftk_searchObjectList(SFTKSearchResults *search,SFTKObject **head, |
michael@0 | 1630 | unsigned int size, PZLock *lock, CK_ATTRIBUTE_PTR theTemplate, |
michael@0 | 1631 | int count, PRBool isLoggedIn) |
michael@0 | 1632 | { |
michael@0 | 1633 | unsigned int i; |
michael@0 | 1634 | SFTKObject *object; |
michael@0 | 1635 | CK_RV crv = CKR_OK; |
michael@0 | 1636 | |
michael@0 | 1637 | for(i=0; i < size; i++) { |
michael@0 | 1638 | /* We need to hold the lock to copy a consistant version of |
michael@0 | 1639 | * the linked list. */ |
michael@0 | 1640 | PZ_Lock(lock); |
michael@0 | 1641 | for (object = head[i]; object != NULL; object= object->next) { |
michael@0 | 1642 | if (sftk_objectMatch(object,theTemplate,count)) { |
michael@0 | 1643 | /* don't return objects that aren't yet visible */ |
michael@0 | 1644 | if ((!isLoggedIn) && sftk_isTrue(object,CKA_PRIVATE)) continue; |
michael@0 | 1645 | sftk_addHandle(search,object->handle); |
michael@0 | 1646 | } |
michael@0 | 1647 | } |
michael@0 | 1648 | PZ_Unlock(lock); |
michael@0 | 1649 | } |
michael@0 | 1650 | return crv; |
michael@0 | 1651 | } |
michael@0 | 1652 | |
michael@0 | 1653 | /* |
michael@0 | 1654 | * free a single list element. Return the Next object in the list. |
michael@0 | 1655 | */ |
michael@0 | 1656 | SFTKObjectListElement * |
michael@0 | 1657 | sftk_FreeObjectListElement(SFTKObjectListElement *objectList) |
michael@0 | 1658 | { |
michael@0 | 1659 | SFTKObjectListElement *ol = objectList->next; |
michael@0 | 1660 | |
michael@0 | 1661 | sftk_FreeObject(objectList->object); |
michael@0 | 1662 | PORT_Free(objectList); |
michael@0 | 1663 | return ol; |
michael@0 | 1664 | } |
michael@0 | 1665 | |
michael@0 | 1666 | /* free an entire object list */ |
michael@0 | 1667 | void |
michael@0 | 1668 | sftk_FreeObjectList(SFTKObjectListElement *objectList) |
michael@0 | 1669 | { |
michael@0 | 1670 | SFTKObjectListElement *ol; |
michael@0 | 1671 | |
michael@0 | 1672 | for (ol= objectList; ol != NULL; ol = sftk_FreeObjectListElement(ol)) {} |
michael@0 | 1673 | } |
michael@0 | 1674 | |
michael@0 | 1675 | /* |
michael@0 | 1676 | * free a search structure |
michael@0 | 1677 | */ |
michael@0 | 1678 | void |
michael@0 | 1679 | sftk_FreeSearch(SFTKSearchResults *search) |
michael@0 | 1680 | { |
michael@0 | 1681 | if (search->handles) { |
michael@0 | 1682 | PORT_Free(search->handles); |
michael@0 | 1683 | } |
michael@0 | 1684 | PORT_Free(search); |
michael@0 | 1685 | } |
michael@0 | 1686 | |
michael@0 | 1687 | /* |
michael@0 | 1688 | * ******************** Session Utilities ******************************* |
michael@0 | 1689 | */ |
michael@0 | 1690 | |
michael@0 | 1691 | /* update the sessions state based in it's flags and wether or not it's |
michael@0 | 1692 | * logged in */ |
michael@0 | 1693 | void |
michael@0 | 1694 | sftk_update_state(SFTKSlot *slot,SFTKSession *session) |
michael@0 | 1695 | { |
michael@0 | 1696 | if (slot->isLoggedIn) { |
michael@0 | 1697 | if (slot->ssoLoggedIn) { |
michael@0 | 1698 | session->info.state = CKS_RW_SO_FUNCTIONS; |
michael@0 | 1699 | } else if (session->info.flags & CKF_RW_SESSION) { |
michael@0 | 1700 | session->info.state = CKS_RW_USER_FUNCTIONS; |
michael@0 | 1701 | } else { |
michael@0 | 1702 | session->info.state = CKS_RO_USER_FUNCTIONS; |
michael@0 | 1703 | } |
michael@0 | 1704 | } else { |
michael@0 | 1705 | if (session->info.flags & CKF_RW_SESSION) { |
michael@0 | 1706 | session->info.state = CKS_RW_PUBLIC_SESSION; |
michael@0 | 1707 | } else { |
michael@0 | 1708 | session->info.state = CKS_RO_PUBLIC_SESSION; |
michael@0 | 1709 | } |
michael@0 | 1710 | } |
michael@0 | 1711 | } |
michael@0 | 1712 | |
michael@0 | 1713 | /* update the state of all the sessions on a slot */ |
michael@0 | 1714 | void |
michael@0 | 1715 | sftk_update_all_states(SFTKSlot *slot) |
michael@0 | 1716 | { |
michael@0 | 1717 | unsigned int i; |
michael@0 | 1718 | SFTKSession *session; |
michael@0 | 1719 | |
michael@0 | 1720 | for (i=0; i < slot->sessHashSize; i++) { |
michael@0 | 1721 | PZLock *lock = SFTK_SESSION_LOCK(slot,i); |
michael@0 | 1722 | PZ_Lock(lock); |
michael@0 | 1723 | for (session = slot->head[i]; session; session = session->next) { |
michael@0 | 1724 | sftk_update_state(slot,session); |
michael@0 | 1725 | } |
michael@0 | 1726 | PZ_Unlock(lock); |
michael@0 | 1727 | } |
michael@0 | 1728 | } |
michael@0 | 1729 | |
michael@0 | 1730 | /* |
michael@0 | 1731 | * context are cipher and digest contexts that are associated with a session |
michael@0 | 1732 | */ |
michael@0 | 1733 | void |
michael@0 | 1734 | sftk_FreeContext(SFTKSessionContext *context) |
michael@0 | 1735 | { |
michael@0 | 1736 | if (context->cipherInfo) { |
michael@0 | 1737 | (*context->destroy)(context->cipherInfo,PR_TRUE); |
michael@0 | 1738 | } |
michael@0 | 1739 | if (context->hashInfo) { |
michael@0 | 1740 | (*context->hashdestroy)(context->hashInfo,PR_TRUE); |
michael@0 | 1741 | } |
michael@0 | 1742 | if (context->key) { |
michael@0 | 1743 | sftk_FreeObject(context->key); |
michael@0 | 1744 | context->key = NULL; |
michael@0 | 1745 | } |
michael@0 | 1746 | PORT_Free(context); |
michael@0 | 1747 | } |
michael@0 | 1748 | |
michael@0 | 1749 | /* |
michael@0 | 1750 | * create a new nession. NOTE: The session handle is not set, and the |
michael@0 | 1751 | * session is not added to the slot's session queue. |
michael@0 | 1752 | */ |
michael@0 | 1753 | SFTKSession * |
michael@0 | 1754 | sftk_NewSession(CK_SLOT_ID slotID, CK_NOTIFY notify, CK_VOID_PTR pApplication, |
michael@0 | 1755 | CK_FLAGS flags) |
michael@0 | 1756 | { |
michael@0 | 1757 | SFTKSession *session; |
michael@0 | 1758 | SFTKSlot *slot = sftk_SlotFromID(slotID, PR_FALSE); |
michael@0 | 1759 | |
michael@0 | 1760 | if (slot == NULL) return NULL; |
michael@0 | 1761 | |
michael@0 | 1762 | session = (SFTKSession*)PORT_Alloc(sizeof(SFTKSession)); |
michael@0 | 1763 | if (session == NULL) return NULL; |
michael@0 | 1764 | |
michael@0 | 1765 | session->next = session->prev = NULL; |
michael@0 | 1766 | session->refCount = 1; |
michael@0 | 1767 | session->enc_context = NULL; |
michael@0 | 1768 | session->hash_context = NULL; |
michael@0 | 1769 | session->sign_context = NULL; |
michael@0 | 1770 | session->search = NULL; |
michael@0 | 1771 | session->objectIDCount = 1; |
michael@0 | 1772 | session->objectLock = PZ_NewLock(nssILockObject); |
michael@0 | 1773 | if (session->objectLock == NULL) { |
michael@0 | 1774 | PORT_Free(session); |
michael@0 | 1775 | return NULL; |
michael@0 | 1776 | } |
michael@0 | 1777 | session->objects[0] = NULL; |
michael@0 | 1778 | |
michael@0 | 1779 | session->slot = slot; |
michael@0 | 1780 | session->notify = notify; |
michael@0 | 1781 | session->appData = pApplication; |
michael@0 | 1782 | session->info.flags = flags; |
michael@0 | 1783 | session->info.slotID = slotID; |
michael@0 | 1784 | session->info.ulDeviceError = 0; |
michael@0 | 1785 | sftk_update_state(slot,session); |
michael@0 | 1786 | return session; |
michael@0 | 1787 | } |
michael@0 | 1788 | |
michael@0 | 1789 | |
michael@0 | 1790 | /* free all the data associated with a session. */ |
michael@0 | 1791 | static void |
michael@0 | 1792 | sftk_DestroySession(SFTKSession *session) |
michael@0 | 1793 | { |
michael@0 | 1794 | SFTKObjectList *op,*next; |
michael@0 | 1795 | PORT_Assert(session->refCount == 0); |
michael@0 | 1796 | |
michael@0 | 1797 | /* clean out the attributes */ |
michael@0 | 1798 | /* since no one is referencing us, it's safe to walk the chain |
michael@0 | 1799 | * without a lock */ |
michael@0 | 1800 | for (op = session->objects[0]; op != NULL; op = next) { |
michael@0 | 1801 | next = op->next; |
michael@0 | 1802 | /* paranoia */ |
michael@0 | 1803 | op->next = op->prev = NULL; |
michael@0 | 1804 | sftk_DeleteObject(session,op->parent); |
michael@0 | 1805 | } |
michael@0 | 1806 | PZ_DestroyLock(session->objectLock); |
michael@0 | 1807 | if (session->enc_context) { |
michael@0 | 1808 | sftk_FreeContext(session->enc_context); |
michael@0 | 1809 | } |
michael@0 | 1810 | if (session->hash_context) { |
michael@0 | 1811 | sftk_FreeContext(session->hash_context); |
michael@0 | 1812 | } |
michael@0 | 1813 | if (session->sign_context) { |
michael@0 | 1814 | sftk_FreeContext(session->sign_context); |
michael@0 | 1815 | } |
michael@0 | 1816 | if (session->search) { |
michael@0 | 1817 | sftk_FreeSearch(session->search); |
michael@0 | 1818 | } |
michael@0 | 1819 | PORT_Free(session); |
michael@0 | 1820 | } |
michael@0 | 1821 | |
michael@0 | 1822 | |
michael@0 | 1823 | /* |
michael@0 | 1824 | * look up a session structure from a session handle |
michael@0 | 1825 | * generate a reference to it. |
michael@0 | 1826 | */ |
michael@0 | 1827 | SFTKSession * |
michael@0 | 1828 | sftk_SessionFromHandle(CK_SESSION_HANDLE handle) |
michael@0 | 1829 | { |
michael@0 | 1830 | SFTKSlot *slot = sftk_SlotFromSessionHandle(handle); |
michael@0 | 1831 | SFTKSession *session; |
michael@0 | 1832 | PZLock *lock; |
michael@0 | 1833 | |
michael@0 | 1834 | if (!slot) return NULL; |
michael@0 | 1835 | lock = SFTK_SESSION_LOCK(slot,handle); |
michael@0 | 1836 | |
michael@0 | 1837 | PZ_Lock(lock); |
michael@0 | 1838 | sftkqueue_find(session,handle,slot->head,slot->sessHashSize); |
michael@0 | 1839 | if (session) session->refCount++; |
michael@0 | 1840 | PZ_Unlock(lock); |
michael@0 | 1841 | |
michael@0 | 1842 | return (session); |
michael@0 | 1843 | } |
michael@0 | 1844 | |
michael@0 | 1845 | /* |
michael@0 | 1846 | * release a reference to a session handle |
michael@0 | 1847 | */ |
michael@0 | 1848 | void |
michael@0 | 1849 | sftk_FreeSession(SFTKSession *session) |
michael@0 | 1850 | { |
michael@0 | 1851 | PRBool destroy = PR_FALSE; |
michael@0 | 1852 | SFTKSlot *slot = sftk_SlotFromSession(session); |
michael@0 | 1853 | PZLock *lock = SFTK_SESSION_LOCK(slot,session->handle); |
michael@0 | 1854 | |
michael@0 | 1855 | PZ_Lock(lock); |
michael@0 | 1856 | if (session->refCount == 1) destroy = PR_TRUE; |
michael@0 | 1857 | session->refCount--; |
michael@0 | 1858 | PZ_Unlock(lock); |
michael@0 | 1859 | |
michael@0 | 1860 | if (destroy) sftk_DestroySession(session); |
michael@0 | 1861 | } |
michael@0 | 1862 | |
michael@0 | 1863 | void |
michael@0 | 1864 | sftk_addHandle(SFTKSearchResults *search, CK_OBJECT_HANDLE handle) |
michael@0 | 1865 | { |
michael@0 | 1866 | if (search->handles == NULL) { |
michael@0 | 1867 | return; |
michael@0 | 1868 | } |
michael@0 | 1869 | if (search->size >= search->array_size) { |
michael@0 | 1870 | search->array_size += NSC_SEARCH_BLOCK_SIZE; |
michael@0 | 1871 | search->handles = (CK_OBJECT_HANDLE *) PORT_Realloc(search->handles, |
michael@0 | 1872 | sizeof(CK_OBJECT_HANDLE)* search->array_size); |
michael@0 | 1873 | if (search->handles == NULL) { |
michael@0 | 1874 | return; |
michael@0 | 1875 | } |
michael@0 | 1876 | } |
michael@0 | 1877 | search->handles[search->size] = handle; |
michael@0 | 1878 | search->size++; |
michael@0 | 1879 | } |
michael@0 | 1880 | |
michael@0 | 1881 | static CK_RV |
michael@0 | 1882 | handleToClass(SFTKSlot *slot, CK_OBJECT_HANDLE handle, |
michael@0 | 1883 | CK_OBJECT_CLASS *objClass) |
michael@0 | 1884 | { |
michael@0 | 1885 | SFTKDBHandle *dbHandle = sftk_getDBForTokenObject(slot, handle); |
michael@0 | 1886 | CK_ATTRIBUTE objClassTemplate; |
michael@0 | 1887 | CK_RV crv; |
michael@0 | 1888 | |
michael@0 | 1889 | *objClass = CKO_DATA; |
michael@0 | 1890 | objClassTemplate.type = CKA_CLASS; |
michael@0 | 1891 | objClassTemplate.pValue = objClass; |
michael@0 | 1892 | objClassTemplate.ulValueLen = sizeof(*objClass); |
michael@0 | 1893 | crv = sftkdb_GetAttributeValue(dbHandle, handle, &objClassTemplate, 1); |
michael@0 | 1894 | sftk_freeDB(dbHandle); |
michael@0 | 1895 | return crv; |
michael@0 | 1896 | } |
michael@0 | 1897 | |
michael@0 | 1898 | SFTKObject * |
michael@0 | 1899 | sftk_NewTokenObject(SFTKSlot *slot, SECItem *dbKey, CK_OBJECT_HANDLE handle) |
michael@0 | 1900 | { |
michael@0 | 1901 | SFTKObject *object = NULL; |
michael@0 | 1902 | SFTKTokenObject *tokObject = NULL; |
michael@0 | 1903 | PRBool hasLocks = PR_FALSE; |
michael@0 | 1904 | CK_RV crv; |
michael@0 | 1905 | |
michael@0 | 1906 | object = sftk_GetObjectFromList(&hasLocks, PR_FALSE, &tokenObjectList, 0, |
michael@0 | 1907 | PR_FALSE); |
michael@0 | 1908 | if (object == NULL) { |
michael@0 | 1909 | return NULL; |
michael@0 | 1910 | } |
michael@0 | 1911 | tokObject = (SFTKTokenObject *) object; |
michael@0 | 1912 | |
michael@0 | 1913 | object->handle = handle; |
michael@0 | 1914 | /* every object must have a class, if we can't get it, the object |
michael@0 | 1915 | * doesn't exist */ |
michael@0 | 1916 | crv = handleToClass(slot, handle, &object->objclass); |
michael@0 | 1917 | if (crv != CKR_OK) { |
michael@0 | 1918 | goto loser; |
michael@0 | 1919 | } |
michael@0 | 1920 | object->slot = slot; |
michael@0 | 1921 | object->objectInfo = NULL; |
michael@0 | 1922 | object->infoFree = NULL; |
michael@0 | 1923 | if (!hasLocks) { |
michael@0 | 1924 | object->refLock = PZ_NewLock(nssILockRefLock); |
michael@0 | 1925 | } |
michael@0 | 1926 | if (object->refLock == NULL) { |
michael@0 | 1927 | goto loser; |
michael@0 | 1928 | } |
michael@0 | 1929 | object->refCount = 1; |
michael@0 | 1930 | |
michael@0 | 1931 | return object; |
michael@0 | 1932 | loser: |
michael@0 | 1933 | if (object) { |
michael@0 | 1934 | (void) sftk_DestroyObject(object); |
michael@0 | 1935 | } |
michael@0 | 1936 | return NULL; |
michael@0 | 1937 | |
michael@0 | 1938 | } |
michael@0 | 1939 | |
michael@0 | 1940 | SFTKTokenObject * |
michael@0 | 1941 | sftk_convertSessionToToken(SFTKObject *obj) |
michael@0 | 1942 | { |
michael@0 | 1943 | SECItem *key; |
michael@0 | 1944 | SFTKSessionObject *so = (SFTKSessionObject *)obj; |
michael@0 | 1945 | SFTKTokenObject *to = sftk_narrowToTokenObject(obj); |
michael@0 | 1946 | SECStatus rv; |
michael@0 | 1947 | |
michael@0 | 1948 | sftk_DestroySessionObjectData(so); |
michael@0 | 1949 | PZ_DestroyLock(so->attributeLock); |
michael@0 | 1950 | if (to == NULL) { |
michael@0 | 1951 | return NULL; |
michael@0 | 1952 | } |
michael@0 | 1953 | sftk_tokenKeyLock(so->obj.slot); |
michael@0 | 1954 | key = sftk_lookupTokenKeyByHandle(so->obj.slot,so->obj.handle); |
michael@0 | 1955 | if (key == NULL) { |
michael@0 | 1956 | sftk_tokenKeyUnlock(so->obj.slot); |
michael@0 | 1957 | return NULL; |
michael@0 | 1958 | } |
michael@0 | 1959 | rv = SECITEM_CopyItem(NULL,&to->dbKey,key); |
michael@0 | 1960 | sftk_tokenKeyUnlock(so->obj.slot); |
michael@0 | 1961 | if (rv == SECFailure) { |
michael@0 | 1962 | return NULL; |
michael@0 | 1963 | } |
michael@0 | 1964 | |
michael@0 | 1965 | return to; |
michael@0 | 1966 | } |
michael@0 | 1967 | |
michael@0 | 1968 | SFTKSessionObject * |
michael@0 | 1969 | sftk_narrowToSessionObject(SFTKObject *obj) |
michael@0 | 1970 | { |
michael@0 | 1971 | return !sftk_isToken(obj->handle) ? (SFTKSessionObject *)obj : NULL; |
michael@0 | 1972 | } |
michael@0 | 1973 | |
michael@0 | 1974 | SFTKTokenObject * |
michael@0 | 1975 | sftk_narrowToTokenObject(SFTKObject *obj) |
michael@0 | 1976 | { |
michael@0 | 1977 | return sftk_isToken(obj->handle) ? (SFTKTokenObject *)obj : NULL; |
michael@0 | 1978 | } |
michael@0 | 1979 |