security/nss/lib/dev/devutil.c

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

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

mercurial