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