| OLD | NEW |
| (Empty) |
| 1 /* This Source Code Form is subject to the terms of the Mozilla Public | |
| 2 * License, v. 2.0. If a copy of the MPL was not distributed with this | |
| 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ | |
| 4 | |
| 5 #ifndef DEVM_H | |
| 6 #include "devm.h" | |
| 7 #endif /* DEVM_H */ | |
| 8 | |
| 9 #ifndef CKHELPER_H | |
| 10 #include "ckhelper.h" | |
| 11 #endif /* CKHELPER_H */ | |
| 12 | |
| 13 NSS_IMPLEMENT nssCryptokiObject * | |
| 14 nssCryptokiObject_Create( | |
| 15 NSSToken *t, | |
| 16 nssSession *session, | |
| 17 CK_OBJECT_HANDLE h) | |
| 18 { | |
| 19 PRStatus status; | |
| 20 NSSSlot *slot; | |
| 21 nssCryptokiObject *object; | |
| 22 CK_BBOOL *isTokenObject; | |
| 23 CK_ATTRIBUTE cert_template[] = { | |
| 24 { CKA_TOKEN, NULL, 0 }, | |
| 25 { CKA_LABEL, NULL, 0 } | |
| 26 }; | |
| 27 slot = nssToken_GetSlot(t); | |
| 28 status = nssCKObject_GetAttributes(h, cert_template, 2, | |
| 29 NULL, session, slot); | |
| 30 nssSlot_Destroy(slot); | |
| 31 if (status != PR_SUCCESS) { | |
| 32 /* a failure here indicates a device error */ | |
| 33 return (nssCryptokiObject *)NULL; | |
| 34 } | |
| 35 object = nss_ZNEW(NULL, nssCryptokiObject); | |
| 36 if (!object) { | |
| 37 return (nssCryptokiObject *)NULL; | |
| 38 } | |
| 39 object->handle = h; | |
| 40 object->token = nssToken_AddRef(t); | |
| 41 isTokenObject = (CK_BBOOL *)cert_template[0].pValue; | |
| 42 object->isTokenObject = *isTokenObject; | |
| 43 nss_ZFreeIf(isTokenObject); | |
| 44 NSS_CK_ATTRIBUTE_TO_UTF8(&cert_template[1], object->label); | |
| 45 return object; | |
| 46 } | |
| 47 | |
| 48 NSS_IMPLEMENT void | |
| 49 nssCryptokiObject_Destroy( | |
| 50 nssCryptokiObject *object) | |
| 51 { | |
| 52 if (object) { | |
| 53 nssToken_Destroy(object->token); | |
| 54 nss_ZFreeIf(object->label); | |
| 55 nss_ZFreeIf(object); | |
| 56 } | |
| 57 } | |
| 58 | |
| 59 NSS_IMPLEMENT nssCryptokiObject * | |
| 60 nssCryptokiObject_Clone( | |
| 61 nssCryptokiObject *object) | |
| 62 { | |
| 63 nssCryptokiObject *rvObject; | |
| 64 rvObject = nss_ZNEW(NULL, nssCryptokiObject); | |
| 65 if (rvObject) { | |
| 66 rvObject->handle = object->handle; | |
| 67 rvObject->token = nssToken_AddRef(object->token); | |
| 68 rvObject->isTokenObject = object->isTokenObject; | |
| 69 if (object->label) { | |
| 70 rvObject->label = nssUTF8_Duplicate(object->label, NULL); | |
| 71 } | |
| 72 } | |
| 73 return rvObject; | |
| 74 } | |
| 75 | |
| 76 NSS_EXTERN PRBool | |
| 77 nssCryptokiObject_Equal( | |
| 78 nssCryptokiObject *o1, | |
| 79 nssCryptokiObject *o2) | |
| 80 { | |
| 81 return (o1->token == o2->token && o1->handle == o2->handle); | |
| 82 } | |
| 83 | |
| 84 NSS_IMPLEMENT PRUint32 | |
| 85 nssPKCS11String_Length(CK_CHAR *pkcs11Str, PRUint32 bufLen) | |
| 86 { | |
| 87 PRInt32 i; | |
| 88 for (i = bufLen - 1; i >= 0;) { | |
| 89 if (pkcs11Str[i] != ' ' && pkcs11Str[i] != '\0') | |
| 90 break; | |
| 91 --i; | |
| 92 } | |
| 93 return (PRUint32)(i + 1); | |
| 94 } | |
| 95 | |
| 96 /* | |
| 97 * Slot arrays | |
| 98 */ | |
| 99 | |
| 100 NSS_IMPLEMENT NSSSlot ** | |
| 101 nssSlotArray_Clone( | |
| 102 NSSSlot **slots) | |
| 103 { | |
| 104 NSSSlot **rvSlots = NULL; | |
| 105 NSSSlot **sp = slots; | |
| 106 PRUint32 count = 0; | |
| 107 while (sp && *sp) | |
| 108 count++; | |
| 109 if (count > 0) { | |
| 110 rvSlots = nss_ZNEWARRAY(NULL, NSSSlot *, count + 1); | |
| 111 if (rvSlots) { | |
| 112 for (sp = slots, count = 0; *sp; sp++) { | |
| 113 rvSlots[count++] = nssSlot_AddRef(*sp); | |
| 114 } | |
| 115 } | |
| 116 } | |
| 117 return rvSlots; | |
| 118 } | |
| 119 | |
| 120 NSS_IMPLEMENT void | |
| 121 nssSlotArray_Destroy( | |
| 122 NSSSlot **slots) | |
| 123 { | |
| 124 if (slots) { | |
| 125 NSSSlot **slotp; | |
| 126 for (slotp = slots; *slotp; slotp++) { | |
| 127 nssSlot_Destroy(*slotp); | |
| 128 } | |
| 129 nss_ZFreeIf(slots); | |
| 130 } | |
| 131 } | |
| 132 | |
| 133 NSS_IMPLEMENT void | |
| 134 NSSSlotArray_Destroy( | |
| 135 NSSSlot **slots) | |
| 136 { | |
| 137 nssSlotArray_Destroy(slots); | |
| 138 } | |
| 139 | |
| 140 NSS_IMPLEMENT void | |
| 141 nssTokenArray_Destroy( | |
| 142 NSSToken **tokens) | |
| 143 { | |
| 144 if (tokens) { | |
| 145 NSSToken **tokenp; | |
| 146 for (tokenp = tokens; *tokenp; tokenp++) { | |
| 147 nssToken_Destroy(*tokenp); | |
| 148 } | |
| 149 nss_ZFreeIf(tokens); | |
| 150 } | |
| 151 } | |
| 152 | |
| 153 NSS_IMPLEMENT void | |
| 154 NSSTokenArray_Destroy( | |
| 155 NSSToken **tokens) | |
| 156 { | |
| 157 nssTokenArray_Destroy(tokens); | |
| 158 } | |
| 159 | |
| 160 NSS_IMPLEMENT void | |
| 161 nssCryptokiObjectArray_Destroy( | |
| 162 nssCryptokiObject **objects) | |
| 163 { | |
| 164 if (objects) { | |
| 165 nssCryptokiObject **op; | |
| 166 for (op = objects; *op; op++) { | |
| 167 nssCryptokiObject_Destroy(*op); | |
| 168 } | |
| 169 nss_ZFreeIf(objects); | |
| 170 } | |
| 171 } | |
| 172 | |
| 173 /* object cache for token */ | |
| 174 | |
| 175 typedef struct | |
| 176 { | |
| 177 NSSArena *arena; | |
| 178 nssCryptokiObject *object; | |
| 179 CK_ATTRIBUTE_PTR attributes; | |
| 180 CK_ULONG numAttributes; | |
| 181 } nssCryptokiObjectAndAttributes; | |
| 182 | |
| 183 enum { | |
| 184 cachedCerts = 0, | |
| 185 cachedTrust = 1, | |
| 186 cachedCRLs = 2 | |
| 187 } cachedObjectType; | |
| 188 | |
| 189 struct nssTokenObjectCacheStr { | |
| 190 NSSToken *token; | |
| 191 PZLock *lock; | |
| 192 PRBool loggedIn; | |
| 193 PRBool doObjectType[3]; | |
| 194 PRBool searchedObjectType[3]; | |
| 195 nssCryptokiObjectAndAttributes **objects[3]; | |
| 196 }; | |
| 197 | |
| 198 NSS_IMPLEMENT nssTokenObjectCache * | |
| 199 nssTokenObjectCache_Create( | |
| 200 NSSToken *token, | |
| 201 PRBool cacheCerts, | |
| 202 PRBool cacheTrust, | |
| 203 PRBool cacheCRLs) | |
| 204 { | |
| 205 nssTokenObjectCache *rvCache; | |
| 206 rvCache = nss_ZNEW(NULL, nssTokenObjectCache); | |
| 207 if (!rvCache) { | |
| 208 goto loser; | |
| 209 } | |
| 210 rvCache->lock = PZ_NewLock(nssILockOther); /* XXX */ | |
| 211 if (!rvCache->lock) { | |
| 212 goto loser; | |
| 213 } | |
| 214 rvCache->doObjectType[cachedCerts] = cacheCerts; | |
| 215 rvCache->doObjectType[cachedTrust] = cacheTrust; | |
| 216 rvCache->doObjectType[cachedCRLs] = cacheCRLs; | |
| 217 rvCache->token = token; /* cache goes away with token */ | |
| 218 return rvCache; | |
| 219 loser: | |
| 220 nssTokenObjectCache_Destroy(rvCache); | |
| 221 return (nssTokenObjectCache *)NULL; | |
| 222 } | |
| 223 | |
| 224 static void | |
| 225 clear_cache( | |
| 226 nssTokenObjectCache *cache) | |
| 227 { | |
| 228 nssCryptokiObjectAndAttributes **oa; | |
| 229 PRUint32 objectType; | |
| 230 for (objectType = cachedCerts; objectType <= cachedCRLs; objectType++) { | |
| 231 cache->searchedObjectType[objectType] = PR_FALSE; | |
| 232 if (!cache->objects[objectType]) { | |
| 233 continue; | |
| 234 } | |
| 235 for (oa = cache->objects[objectType]; *oa; oa++) { | |
| 236 /* prevent the token from being destroyed */ | |
| 237 (*oa)->object->token = NULL; | |
| 238 nssCryptokiObject_Destroy((*oa)->object); | |
| 239 nssArena_Destroy((*oa)->arena); | |
| 240 } | |
| 241 nss_ZFreeIf(cache->objects[objectType]); | |
| 242 cache->objects[objectType] = NULL; | |
| 243 } | |
| 244 } | |
| 245 | |
| 246 NSS_IMPLEMENT void | |
| 247 nssTokenObjectCache_Clear( | |
| 248 nssTokenObjectCache *cache) | |
| 249 { | |
| 250 if (cache) { | |
| 251 PZ_Lock(cache->lock); | |
| 252 clear_cache(cache); | |
| 253 PZ_Unlock(cache->lock); | |
| 254 } | |
| 255 } | |
| 256 | |
| 257 NSS_IMPLEMENT void | |
| 258 nssTokenObjectCache_Destroy( | |
| 259 nssTokenObjectCache *cache) | |
| 260 { | |
| 261 if (cache) { | |
| 262 clear_cache(cache); | |
| 263 if (cache->lock) { | |
| 264 PZ_DestroyLock(cache->lock); | |
| 265 } | |
| 266 nss_ZFreeIf(cache); | |
| 267 } | |
| 268 } | |
| 269 | |
| 270 NSS_IMPLEMENT PRBool | |
| 271 nssTokenObjectCache_HaveObjectClass( | |
| 272 nssTokenObjectCache *cache, | |
| 273 CK_OBJECT_CLASS objclass) | |
| 274 { | |
| 275 PRBool haveIt; | |
| 276 PZ_Lock(cache->lock); | |
| 277 switch (objclass) { | |
| 278 case CKO_CERTIFICATE: | |
| 279 haveIt = cache->doObjectType[cachedCerts]; | |
| 280 break; | |
| 281 case CKO_NETSCAPE_TRUST: | |
| 282 haveIt = cache->doObjectType[cachedTrust]; | |
| 283 break; | |
| 284 case CKO_NETSCAPE_CRL: | |
| 285 haveIt = cache->doObjectType[cachedCRLs]; | |
| 286 break; | |
| 287 default: | |
| 288 haveIt = PR_FALSE; | |
| 289 } | |
| 290 PZ_Unlock(cache->lock); | |
| 291 return haveIt; | |
| 292 } | |
| 293 | |
| 294 static nssCryptokiObjectAndAttributes ** | |
| 295 create_object_array( | |
| 296 nssCryptokiObject **objects, | |
| 297 PRBool *doObjects, | |
| 298 PRUint32 *numObjects, | |
| 299 PRStatus *status) | |
| 300 { | |
| 301 nssCryptokiObjectAndAttributes **rvOandA = NULL; | |
| 302 *numObjects = 0; | |
| 303 /* There are no objects for this type */ | |
| 304 if (!objects || !*objects) { | |
| 305 *status = PR_SUCCESS; | |
| 306 return rvOandA; | |
| 307 } | |
| 308 while (*objects++) | |
| 309 (*numObjects)++; | |
| 310 if (*numObjects >= MAX_LOCAL_CACHE_OBJECTS) { | |
| 311 /* Hit the maximum allowed, so don't use a cache (there are | |
| 312 * too many objects to make caching worthwhile, presumably, if | |
| 313 * the token can handle that many objects, it can handle searching. | |
| 314 */ | |
| 315 *doObjects = PR_FALSE; | |
| 316 *status = PR_FAILURE; | |
| 317 *numObjects = 0; | |
| 318 } else { | |
| 319 rvOandA = nss_ZNEWARRAY(NULL, | |
| 320 nssCryptokiObjectAndAttributes *, | |
| 321 *numObjects + 1); | |
| 322 *status = rvOandA ? PR_SUCCESS : PR_FAILURE; | |
| 323 } | |
| 324 return rvOandA; | |
| 325 } | |
| 326 | |
| 327 static nssCryptokiObjectAndAttributes * | |
| 328 create_object( | |
| 329 nssCryptokiObject *object, | |
| 330 const CK_ATTRIBUTE_TYPE *types, | |
| 331 PRUint32 numTypes, | |
| 332 PRStatus *status) | |
| 333 { | |
| 334 PRUint32 j; | |
| 335 NSSArena *arena = NULL; | |
| 336 NSSSlot *slot = NULL; | |
| 337 nssSession *session = NULL; | |
| 338 nssCryptokiObjectAndAttributes *rvCachedObject = NULL; | |
| 339 | |
| 340 slot = nssToken_GetSlot(object->token); | |
| 341 if (!slot) { | |
| 342 nss_SetError(NSS_ERROR_INVALID_POINTER); | |
| 343 goto loser; | |
| 344 } | |
| 345 session = nssToken_GetDefaultSession(object->token); | |
| 346 if (!session) { | |
| 347 nss_SetError(NSS_ERROR_INVALID_POINTER); | |
| 348 goto loser; | |
| 349 } | |
| 350 arena = nssArena_Create(); | |
| 351 if (!arena) { | |
| 352 goto loser; | |
| 353 } | |
| 354 rvCachedObject = nss_ZNEW(arena, nssCryptokiObjectAndAttributes); | |
| 355 if (!rvCachedObject) { | |
| 356 goto loser; | |
| 357 } | |
| 358 rvCachedObject->arena = arena; | |
| 359 /* The cache is tied to the token, and therefore the objects | |
| 360 * in it should not hold references to the token. | |
| 361 */ | |
| 362 nssToken_Destroy(object->token); | |
| 363 rvCachedObject->object = object; | |
| 364 rvCachedObject->attributes = nss_ZNEWARRAY(arena, CK_ATTRIBUTE, numTypes); | |
| 365 if (!rvCachedObject->attributes) { | |
| 366 goto loser; | |
| 367 } | |
| 368 for (j = 0; j < numTypes; j++) { | |
| 369 rvCachedObject->attributes[j].type = types[j]; | |
| 370 } | |
| 371 *status = nssCKObject_GetAttributes(object->handle, | |
| 372 rvCachedObject->attributes, | |
| 373 numTypes, | |
| 374 arena, | |
| 375 session, | |
| 376 slot); | |
| 377 if (*status != PR_SUCCESS) { | |
| 378 goto loser; | |
| 379 } | |
| 380 rvCachedObject->numAttributes = numTypes; | |
| 381 *status = PR_SUCCESS; | |
| 382 nssSlot_Destroy(slot); | |
| 383 | |
| 384 return rvCachedObject; | |
| 385 loser: | |
| 386 *status = PR_FAILURE; | |
| 387 if (slot) { | |
| 388 nssSlot_Destroy(slot); | |
| 389 } | |
| 390 if (arena) | |
| 391 nssArena_Destroy(arena); | |
| 392 return (nssCryptokiObjectAndAttributes *)NULL; | |
| 393 } | |
| 394 | |
| 395 /* | |
| 396 * | |
| 397 * State diagram for cache: | |
| 398 * | |
| 399 * token !present token removed | |
| 400 * +-------------------------+<----------------------+ | |
| 401 * | ^ | | |
| 402 * v | | | |
| 403 * +----------+ slot friendly | token present +----------+ | |
| 404 * | cache | -----------------> % ---------------> | cache | | |
| 405 * | unloaded | | loaded | | |
| 406 * +----------+ +----------+ | |
| 407 * ^ | ^ | | |
| 408 * | | slot !friendly slot logged in | | | |
| 409 * | +-----------------------> % ----------------------+ | | |
| 410 * | | | | |
| 411 * | slot logged out v slot !friendly | | |
| 412 * +-----------------------------+<--------------------------+ | |
| 413 * | |
| 414 */ | |
| 415 | |
| 416 /* This function must not be called with cache->lock locked. */ | |
| 417 static PRBool | |
| 418 token_is_present( | |
| 419 nssTokenObjectCache *cache) | |
| 420 { | |
| 421 NSSSlot *slot = nssToken_GetSlot(cache->token); | |
| 422 PRBool tokenPresent = nssSlot_IsTokenPresent(slot); | |
| 423 nssSlot_Destroy(slot); | |
| 424 return tokenPresent; | |
| 425 } | |
| 426 | |
| 427 static PRBool | |
| 428 search_for_objects( | |
| 429 nssTokenObjectCache *cache) | |
| 430 { | |
| 431 PRBool doSearch = PR_FALSE; | |
| 432 NSSSlot *slot = nssToken_GetSlot(cache->token); | |
| 433 /* Handle non-friendly slots (slots which require login for objects) */ | |
| 434 if (!nssSlot_IsFriendly(slot)) { | |
| 435 if (nssSlot_IsLoggedIn(slot)) { | |
| 436 /* Either no state change, or went from !logged in -> logged in */ | |
| 437 cache->loggedIn = PR_TRUE; | |
| 438 doSearch = PR_TRUE; | |
| 439 } else { | |
| 440 if (cache->loggedIn) { | |
| 441 /* went from logged in -> !logged in, destroy cached objects */ | |
| 442 clear_cache(cache); | |
| 443 cache->loggedIn = PR_FALSE; | |
| 444 } /* else no state change, still not logged in, so exit */ | |
| 445 } | |
| 446 } else { | |
| 447 /* slot is friendly, thus always available for search */ | |
| 448 doSearch = PR_TRUE; | |
| 449 } | |
| 450 nssSlot_Destroy(slot); | |
| 451 return doSearch; | |
| 452 } | |
| 453 | |
| 454 static nssCryptokiObjectAndAttributes * | |
| 455 create_cert( | |
| 456 nssCryptokiObject *object, | |
| 457 PRStatus *status) | |
| 458 { | |
| 459 static const CK_ATTRIBUTE_TYPE certAttr[] = { | |
| 460 CKA_CLASS, | |
| 461 CKA_TOKEN, | |
| 462 CKA_LABEL, | |
| 463 CKA_CERTIFICATE_TYPE, | |
| 464 CKA_ID, | |
| 465 CKA_VALUE, | |
| 466 CKA_ISSUER, | |
| 467 CKA_SERIAL_NUMBER, | |
| 468 CKA_SUBJECT, | |
| 469 CKA_NETSCAPE_EMAIL | |
| 470 }; | |
| 471 static const PRUint32 numCertAttr = sizeof(certAttr) / sizeof(certAttr[0]); | |
| 472 return create_object(object, certAttr, numCertAttr, status); | |
| 473 } | |
| 474 | |
| 475 static nssCryptokiObjectAndAttributes * | |
| 476 create_trust( | |
| 477 nssCryptokiObject *object, | |
| 478 PRStatus *status) | |
| 479 { | |
| 480 static const CK_ATTRIBUTE_TYPE trustAttr[] = { | |
| 481 CKA_CLASS, | |
| 482 CKA_TOKEN, | |
| 483 CKA_LABEL, | |
| 484 CKA_CERT_SHA1_HASH, | |
| 485 CKA_CERT_MD5_HASH, | |
| 486 CKA_ISSUER, | |
| 487 CKA_SUBJECT, | |
| 488 CKA_TRUST_SERVER_AUTH, | |
| 489 CKA_TRUST_CLIENT_AUTH, | |
| 490 CKA_TRUST_EMAIL_PROTECTION, | |
| 491 CKA_TRUST_CODE_SIGNING | |
| 492 }; | |
| 493 static const PRUint32 numTrustAttr = sizeof(trustAttr) / sizeof(trustAttr[0]
); | |
| 494 return create_object(object, trustAttr, numTrustAttr, status); | |
| 495 } | |
| 496 | |
| 497 static nssCryptokiObjectAndAttributes * | |
| 498 create_crl( | |
| 499 nssCryptokiObject *object, | |
| 500 PRStatus *status) | |
| 501 { | |
| 502 static const CK_ATTRIBUTE_TYPE crlAttr[] = { | |
| 503 CKA_CLASS, | |
| 504 CKA_TOKEN, | |
| 505 CKA_LABEL, | |
| 506 CKA_VALUE, | |
| 507 CKA_SUBJECT, | |
| 508 CKA_NETSCAPE_KRL, | |
| 509 CKA_NETSCAPE_URL | |
| 510 }; | |
| 511 static const PRUint32 numCRLAttr = sizeof(crlAttr) / sizeof(crlAttr[0]); | |
| 512 return create_object(object, crlAttr, numCRLAttr, status); | |
| 513 } | |
| 514 | |
| 515 /* Dispatch to the create function for the object type */ | |
| 516 static nssCryptokiObjectAndAttributes * | |
| 517 create_object_of_type( | |
| 518 nssCryptokiObject *object, | |
| 519 PRUint32 objectType, | |
| 520 PRStatus *status) | |
| 521 { | |
| 522 if (objectType == cachedCerts) { | |
| 523 return create_cert(object, status); | |
| 524 } | |
| 525 if (objectType == cachedTrust) { | |
| 526 return create_trust(object, status); | |
| 527 } | |
| 528 if (objectType == cachedCRLs) { | |
| 529 return create_crl(object, status); | |
| 530 } | |
| 531 return (nssCryptokiObjectAndAttributes *)NULL; | |
| 532 } | |
| 533 | |
| 534 static PRStatus | |
| 535 get_token_objects_for_cache( | |
| 536 nssTokenObjectCache *cache, | |
| 537 PRUint32 objectType, | |
| 538 CK_OBJECT_CLASS objclass) | |
| 539 { | |
| 540 PRStatus status; | |
| 541 nssCryptokiObject **objects; | |
| 542 PRBool *doIt = &cache->doObjectType[objectType]; | |
| 543 PRUint32 i, numObjects; | |
| 544 | |
| 545 if (!search_for_objects(cache) || | |
| 546 cache->searchedObjectType[objectType] || | |
| 547 !cache->doObjectType[objectType]) { | |
| 548 /* Either there was a state change that prevents a search | |
| 549 * (token logged out), or the search was already done, | |
| 550 * or objects of this type are not being cached. | |
| 551 */ | |
| 552 return PR_SUCCESS; | |
| 553 } | |
| 554 objects = nssToken_FindObjects(cache->token, NULL, objclass, | |
| 555 nssTokenSearchType_TokenForced, | |
| 556 MAX_LOCAL_CACHE_OBJECTS, &status); | |
| 557 if (status != PR_SUCCESS) { | |
| 558 return status; | |
| 559 } | |
| 560 cache->objects[objectType] = create_object_array(objects, | |
| 561 doIt, | |
| 562 &numObjects, | |
| 563 &status); | |
| 564 if (status != PR_SUCCESS) { | |
| 565 nss_ZFreeIf(objects); | |
| 566 return status; | |
| 567 } | |
| 568 for (i = 0; i < numObjects; i++) { | |
| 569 cache->objects[objectType][i] = create_object_of_type(objects[i], | |
| 570 objectType, | |
| 571 &status); | |
| 572 if (status != PR_SUCCESS) { | |
| 573 break; | |
| 574 } | |
| 575 } | |
| 576 if (status == PR_SUCCESS) { | |
| 577 nss_ZFreeIf(objects); | |
| 578 } else { | |
| 579 PRUint32 j; | |
| 580 for (j = 0; j < i; j++) { | |
| 581 /* sigh */ | |
| 582 nssToken_AddRef(cache->objects[objectType][j]->object->token); | |
| 583 nssArena_Destroy(cache->objects[objectType][j]->arena); | |
| 584 } | |
| 585 nss_ZFreeIf(cache->objects[objectType]); | |
| 586 cache->objects[objectType] = NULL; | |
| 587 nssCryptokiObjectArray_Destroy(objects); | |
| 588 } | |
| 589 cache->searchedObjectType[objectType] = PR_TRUE; | |
| 590 return status; | |
| 591 } | |
| 592 | |
| 593 static CK_ATTRIBUTE_PTR | |
| 594 find_attribute_in_object( | |
| 595 nssCryptokiObjectAndAttributes *obj, | |
| 596 CK_ATTRIBUTE_TYPE attrType) | |
| 597 { | |
| 598 PRUint32 j; | |
| 599 for (j = 0; j < obj->numAttributes; j++) { | |
| 600 if (attrType == obj->attributes[j].type) { | |
| 601 return &obj->attributes[j]; | |
| 602 } | |
| 603 } | |
| 604 return (CK_ATTRIBUTE_PTR)NULL; | |
| 605 } | |
| 606 | |
| 607 /* Find all objects in the array that match the supplied template */ | |
| 608 static nssCryptokiObject ** | |
| 609 find_objects_in_array( | |
| 610 nssCryptokiObjectAndAttributes **objArray, | |
| 611 CK_ATTRIBUTE_PTR ot, | |
| 612 CK_ULONG otlen, | |
| 613 PRUint32 maximumOpt) | |
| 614 { | |
| 615 PRIntn oi = 0; | |
| 616 PRUint32 i; | |
| 617 NSSArena *arena; | |
| 618 PRUint32 size = 8; | |
| 619 PRUint32 numMatches = 0; | |
| 620 nssCryptokiObject **objects = NULL; | |
| 621 nssCryptokiObjectAndAttributes **matches = NULL; | |
| 622 CK_ATTRIBUTE_PTR attr; | |
| 623 | |
| 624 if (!objArray) { | |
| 625 return (nssCryptokiObject **)NULL; | |
| 626 } | |
| 627 arena = nssArena_Create(); | |
| 628 if (!arena) { | |
| 629 return (nssCryptokiObject **)NULL; | |
| 630 } | |
| 631 matches = nss_ZNEWARRAY(arena, nssCryptokiObjectAndAttributes *, size); | |
| 632 if (!matches) { | |
| 633 goto loser; | |
| 634 } | |
| 635 if (maximumOpt == 0) | |
| 636 maximumOpt = ~0; | |
| 637 /* loop over the cached objects */ | |
| 638 for (; *objArray && numMatches < maximumOpt; objArray++) { | |
| 639 nssCryptokiObjectAndAttributes *obj = *objArray; | |
| 640 /* loop over the test template */ | |
| 641 for (i = 0; i < otlen; i++) { | |
| 642 /* see if the object has the attribute */ | |
| 643 attr = find_attribute_in_object(obj, ot[i].type); | |
| 644 if (!attr) { | |
| 645 /* nope, match failed */ | |
| 646 break; | |
| 647 } | |
| 648 /* compare the attribute against the test value */ | |
| 649 if (ot[i].ulValueLen != attr->ulValueLen || | |
| 650 !nsslibc_memequal(ot[i].pValue, | |
| 651 attr->pValue, | |
| 652 attr->ulValueLen, NULL)) { | |
| 653 /* nope, match failed */ | |
| 654 break; | |
| 655 } | |
| 656 } | |
| 657 if (i == otlen) { | |
| 658 /* all of the attributes in the test template were found | |
| 659 * in the object's template, and they all matched | |
| 660 */ | |
| 661 matches[numMatches++] = obj; | |
| 662 if (numMatches == size) { | |
| 663 size *= 2; | |
| 664 matches = nss_ZREALLOCARRAY(matches, | |
| 665 nssCryptokiObjectAndAttributes *, | |
| 666 size); | |
| 667 if (!matches) { | |
| 668 goto loser; | |
| 669 } | |
| 670 } | |
| 671 } | |
| 672 } | |
| 673 if (numMatches > 0) { | |
| 674 objects = nss_ZNEWARRAY(NULL, nssCryptokiObject *, numMatches + 1); | |
| 675 if (!objects) { | |
| 676 goto loser; | |
| 677 } | |
| 678 for (oi = 0; oi < (PRIntn)numMatches; oi++) { | |
| 679 objects[oi] = nssCryptokiObject_Clone(matches[oi]->object); | |
| 680 if (!objects[oi]) { | |
| 681 goto loser; | |
| 682 } | |
| 683 } | |
| 684 } | |
| 685 nssArena_Destroy(arena); | |
| 686 return objects; | |
| 687 loser: | |
| 688 nssCryptokiObjectArray_Destroy(objects); | |
| 689 nssArena_Destroy(arena); | |
| 690 return (nssCryptokiObject **)NULL; | |
| 691 } | |
| 692 | |
| 693 NSS_IMPLEMENT nssCryptokiObject ** | |
| 694 nssTokenObjectCache_FindObjectsByTemplate( | |
| 695 nssTokenObjectCache *cache, | |
| 696 CK_OBJECT_CLASS objclass, | |
| 697 CK_ATTRIBUTE_PTR otemplate, | |
| 698 CK_ULONG otlen, | |
| 699 PRUint32 maximumOpt, | |
| 700 PRStatus *statusOpt) | |
| 701 { | |
| 702 PRStatus status = PR_FAILURE; | |
| 703 nssCryptokiObject **rvObjects = NULL; | |
| 704 PRUint32 objectType; | |
| 705 if (!token_is_present(cache)) { | |
| 706 status = PR_SUCCESS; | |
| 707 goto finish; | |
| 708 } | |
| 709 switch (objclass) { | |
| 710 case CKO_CERTIFICATE: | |
| 711 objectType = cachedCerts; | |
| 712 break; | |
| 713 case CKO_NETSCAPE_TRUST: | |
| 714 objectType = cachedTrust; | |
| 715 break; | |
| 716 case CKO_NETSCAPE_CRL: | |
| 717 objectType = cachedCRLs; | |
| 718 break; | |
| 719 default: | |
| 720 goto finish; | |
| 721 } | |
| 722 PZ_Lock(cache->lock); | |
| 723 if (cache->doObjectType[objectType]) { | |
| 724 status = get_token_objects_for_cache(cache, objectType, objclass); | |
| 725 if (status == PR_SUCCESS) { | |
| 726 rvObjects = find_objects_in_array(cache->objects[objectType], | |
| 727 otemplate, otlen, maximumOpt); | |
| 728 } | |
| 729 } | |
| 730 PZ_Unlock(cache->lock); | |
| 731 finish: | |
| 732 if (statusOpt) { | |
| 733 *statusOpt = status; | |
| 734 } | |
| 735 return rvObjects; | |
| 736 } | |
| 737 | |
| 738 static PRBool | |
| 739 cache_available_for_object_type( | |
| 740 nssTokenObjectCache *cache, | |
| 741 PRUint32 objectType) | |
| 742 { | |
| 743 if (!cache->doObjectType[objectType]) { | |
| 744 /* not caching this object kind */ | |
| 745 return PR_FALSE; | |
| 746 } | |
| 747 if (!cache->searchedObjectType[objectType]) { | |
| 748 /* objects are not cached yet */ | |
| 749 return PR_FALSE; | |
| 750 } | |
| 751 if (!search_for_objects(cache)) { | |
| 752 /* not logged in */ | |
| 753 return PR_FALSE; | |
| 754 } | |
| 755 return PR_TRUE; | |
| 756 } | |
| 757 | |
| 758 NSS_IMPLEMENT PRStatus | |
| 759 nssTokenObjectCache_GetObjectAttributes( | |
| 760 nssTokenObjectCache *cache, | |
| 761 NSSArena *arenaOpt, | |
| 762 nssCryptokiObject *object, | |
| 763 CK_OBJECT_CLASS objclass, | |
| 764 CK_ATTRIBUTE_PTR atemplate, | |
| 765 CK_ULONG atlen) | |
| 766 { | |
| 767 PRUint32 i, j; | |
| 768 NSSArena *arena = NULL; | |
| 769 nssArenaMark *mark = NULL; | |
| 770 nssCryptokiObjectAndAttributes *cachedOA = NULL; | |
| 771 nssCryptokiObjectAndAttributes **oa = NULL; | |
| 772 PRUint32 objectType; | |
| 773 if (!token_is_present(cache)) { | |
| 774 return PR_FAILURE; | |
| 775 } | |
| 776 PZ_Lock(cache->lock); | |
| 777 switch (objclass) { | |
| 778 case CKO_CERTIFICATE: | |
| 779 objectType = cachedCerts; | |
| 780 break; | |
| 781 case CKO_NETSCAPE_TRUST: | |
| 782 objectType = cachedTrust; | |
| 783 break; | |
| 784 case CKO_NETSCAPE_CRL: | |
| 785 objectType = cachedCRLs; | |
| 786 break; | |
| 787 default: | |
| 788 goto loser; | |
| 789 } | |
| 790 if (!cache_available_for_object_type(cache, objectType)) { | |
| 791 goto loser; | |
| 792 } | |
| 793 oa = cache->objects[objectType]; | |
| 794 if (!oa) { | |
| 795 goto loser; | |
| 796 } | |
| 797 for (; *oa; oa++) { | |
| 798 if (nssCryptokiObject_Equal((*oa)->object, object)) { | |
| 799 cachedOA = *oa; | |
| 800 break; | |
| 801 } | |
| 802 } | |
| 803 if (!cachedOA) { | |
| 804 goto loser; /* don't have this object */ | |
| 805 } | |
| 806 if (arenaOpt) { | |
| 807 arena = arenaOpt; | |
| 808 mark = nssArena_Mark(arena); | |
| 809 } | |
| 810 for (i = 0; i < atlen; i++) { | |
| 811 for (j = 0; j < cachedOA->numAttributes; j++) { | |
| 812 if (atemplate[i].type == cachedOA->attributes[j].type) { | |
| 813 CK_ATTRIBUTE_PTR attr = &cachedOA->attributes[j]; | |
| 814 if (cachedOA->attributes[j].ulValueLen == 0 || | |
| 815 cachedOA->attributes[j].ulValueLen == (CK_ULONG)-1) { | |
| 816 break; /* invalid attribute */ | |
| 817 } | |
| 818 if (atemplate[i].ulValueLen > 0) { | |
| 819 if (atemplate[i].pValue == NULL || | |
| 820 atemplate[i].ulValueLen < attr->ulValueLen) { | |
| 821 goto loser; | |
| 822 } | |
| 823 } else { | |
| 824 atemplate[i].pValue = nss_ZAlloc(arena, attr->ulValueLen); | |
| 825 if (!atemplate[i].pValue) { | |
| 826 goto loser; | |
| 827 } | |
| 828 } | |
| 829 nsslibc_memcpy(atemplate[i].pValue, | |
| 830 attr->pValue, attr->ulValueLen); | |
| 831 atemplate[i].ulValueLen = attr->ulValueLen; | |
| 832 break; | |
| 833 } | |
| 834 } | |
| 835 if (j == cachedOA->numAttributes) { | |
| 836 atemplate[i].ulValueLen = (CK_ULONG)-1; | |
| 837 } | |
| 838 } | |
| 839 PZ_Unlock(cache->lock); | |
| 840 if (mark) { | |
| 841 nssArena_Unmark(arena, mark); | |
| 842 } | |
| 843 return PR_SUCCESS; | |
| 844 loser: | |
| 845 PZ_Unlock(cache->lock); | |
| 846 if (mark) { | |
| 847 nssArena_Release(arena, mark); | |
| 848 } | |
| 849 return PR_FAILURE; | |
| 850 } | |
| 851 | |
| 852 NSS_IMPLEMENT PRStatus | |
| 853 nssTokenObjectCache_ImportObject( | |
| 854 nssTokenObjectCache *cache, | |
| 855 nssCryptokiObject *object, | |
| 856 CK_OBJECT_CLASS objclass, | |
| 857 CK_ATTRIBUTE_PTR ot, | |
| 858 CK_ULONG otlen) | |
| 859 { | |
| 860 PRStatus status = PR_SUCCESS; | |
| 861 PRUint32 count; | |
| 862 nssCryptokiObjectAndAttributes **oa, ***otype; | |
| 863 PRUint32 objectType; | |
| 864 PRBool haveIt = PR_FALSE; | |
| 865 | |
| 866 if (!token_is_present(cache)) { | |
| 867 return PR_SUCCESS; /* cache not active, ignored */ | |
| 868 } | |
| 869 PZ_Lock(cache->lock); | |
| 870 switch (objclass) { | |
| 871 case CKO_CERTIFICATE: | |
| 872 objectType = cachedCerts; | |
| 873 break; | |
| 874 case CKO_NETSCAPE_TRUST: | |
| 875 objectType = cachedTrust; | |
| 876 break; | |
| 877 case CKO_NETSCAPE_CRL: | |
| 878 objectType = cachedCRLs; | |
| 879 break; | |
| 880 default: | |
| 881 PZ_Unlock(cache->lock); | |
| 882 return PR_SUCCESS; /* don't need to import it here */ | |
| 883 } | |
| 884 if (!cache_available_for_object_type(cache, objectType)) { | |
| 885 PZ_Unlock(cache->lock); | |
| 886 return PR_SUCCESS; /* cache not active, ignored */ | |
| 887 } | |
| 888 count = 0; | |
| 889 otype = &cache->objects[objectType]; /* index into array of types */ | |
| 890 oa = *otype; /* the array of objects for this type *
/ | |
| 891 while (oa && *oa) { | |
| 892 if (nssCryptokiObject_Equal((*oa)->object, object)) { | |
| 893 haveIt = PR_TRUE; | |
| 894 break; | |
| 895 } | |
| 896 count++; | |
| 897 oa++; | |
| 898 } | |
| 899 if (haveIt) { | |
| 900 /* Destroy the old entry */ | |
| 901 (*oa)->object->token = NULL; | |
| 902 nssCryptokiObject_Destroy((*oa)->object); | |
| 903 nssArena_Destroy((*oa)->arena); | |
| 904 } else { | |
| 905 /* Create space for a new entry */ | |
| 906 if (count > 0) { | |
| 907 *otype = nss_ZREALLOCARRAY(*otype, | |
| 908 nssCryptokiObjectAndAttributes *, | |
| 909 count + 2); | |
| 910 } else { | |
| 911 *otype = nss_ZNEWARRAY(NULL, nssCryptokiObjectAndAttributes *, 2); | |
| 912 } | |
| 913 } | |
| 914 if (*otype) { | |
| 915 nssCryptokiObject *copyObject = nssCryptokiObject_Clone(object); | |
| 916 (*otype)[count] = create_object_of_type(copyObject, objectType, | |
| 917 &status); | |
| 918 } else { | |
| 919 status = PR_FAILURE; | |
| 920 } | |
| 921 PZ_Unlock(cache->lock); | |
| 922 return status; | |
| 923 } | |
| 924 | |
| 925 NSS_IMPLEMENT void | |
| 926 nssTokenObjectCache_RemoveObject( | |
| 927 nssTokenObjectCache *cache, | |
| 928 nssCryptokiObject *object) | |
| 929 { | |
| 930 PRUint32 oType; | |
| 931 nssCryptokiObjectAndAttributes **oa, **swp = NULL; | |
| 932 if (!token_is_present(cache)) { | |
| 933 return; | |
| 934 } | |
| 935 PZ_Lock(cache->lock); | |
| 936 for (oType = 0; oType < 3; oType++) { | |
| 937 if (!cache_available_for_object_type(cache, oType) || | |
| 938 !cache->objects[oType]) { | |
| 939 continue; | |
| 940 } | |
| 941 for (oa = cache->objects[oType]; *oa; oa++) { | |
| 942 if (nssCryptokiObject_Equal((*oa)->object, object)) { | |
| 943 swp = oa; /* the entry to remove */ | |
| 944 while (oa[1]) | |
| 945 oa++; /* go to the tail */ | |
| 946 (*swp)->object->token = NULL; | |
| 947 nssCryptokiObject_Destroy((*swp)->object); | |
| 948 nssArena_Destroy((*swp)->arena); /* destroy it */ | |
| 949 *swp = *oa; /* swap the last with the remov
ed */ | |
| 950 *oa = NULL; /* null-terminate the array */ | |
| 951 break; | |
| 952 } | |
| 953 } | |
| 954 if (swp) { | |
| 955 break; | |
| 956 } | |
| 957 } | |
| 958 if ((oType < 3) && | |
| 959 cache->objects[oType] && cache->objects[oType][0] == NULL) { | |
| 960 nss_ZFreeIf(cache->objects[oType]); /* no entries remaining */ | |
| 961 cache->objects[oType] = NULL; | |
| 962 } | |
| 963 PZ_Unlock(cache->lock); | |
| 964 } | |
| 965 | |
| 966 /* These two hash algorithms are presently sufficient. | |
| 967 ** They are used for fingerprints of certs which are stored as the | |
| 968 ** CKA_CERT_SHA1_HASH and CKA_CERT_MD5_HASH attributes. | |
| 969 ** We don't need to add SHAxxx to these now. | |
| 970 */ | |
| 971 /* XXX of course this doesn't belong here */ | |
| 972 NSS_IMPLEMENT NSSAlgorithmAndParameters * | |
| 973 NSSAlgorithmAndParameters_CreateSHA1Digest( | |
| 974 NSSArena *arenaOpt) | |
| 975 { | |
| 976 NSSAlgorithmAndParameters *rvAP = NULL; | |
| 977 rvAP = nss_ZNEW(arenaOpt, NSSAlgorithmAndParameters); | |
| 978 if (rvAP) { | |
| 979 rvAP->mechanism.mechanism = CKM_SHA_1; | |
| 980 rvAP->mechanism.pParameter = NULL; | |
| 981 rvAP->mechanism.ulParameterLen = 0; | |
| 982 } | |
| 983 return rvAP; | |
| 984 } | |
| 985 | |
| 986 NSS_IMPLEMENT NSSAlgorithmAndParameters * | |
| 987 NSSAlgorithmAndParameters_CreateMD5Digest( | |
| 988 NSSArena *arenaOpt) | |
| 989 { | |
| 990 NSSAlgorithmAndParameters *rvAP = NULL; | |
| 991 rvAP = nss_ZNEW(arenaOpt, NSSAlgorithmAndParameters); | |
| 992 if (rvAP) { | |
| 993 rvAP->mechanism.mechanism = CKM_MD5; | |
| 994 rvAP->mechanism.pParameter = NULL; | |
| 995 rvAP->mechanism.ulParameterLen = 0; | |
| 996 } | |
| 997 return rvAP; | |
| 998 } | |
| OLD | NEW |