1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/security/nss/lib/dev/devutil.c Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,1006 @@ 1.4 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.5 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.6 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.7 + 1.8 +#ifndef DEVM_H 1.9 +#include "devm.h" 1.10 +#endif /* DEVM_H */ 1.11 + 1.12 +#ifndef CKHELPER_H 1.13 +#include "ckhelper.h" 1.14 +#endif /* CKHELPER_H */ 1.15 + 1.16 +NSS_IMPLEMENT nssCryptokiObject * 1.17 +nssCryptokiObject_Create ( 1.18 + NSSToken *t, 1.19 + nssSession *session, 1.20 + CK_OBJECT_HANDLE h 1.21 +) 1.22 +{ 1.23 + PRStatus status; 1.24 + NSSSlot *slot; 1.25 + nssCryptokiObject *object; 1.26 + CK_BBOOL *isTokenObject; 1.27 + CK_ATTRIBUTE cert_template[] = { 1.28 + { CKA_TOKEN, NULL, 0 }, 1.29 + { CKA_LABEL, NULL, 0 } 1.30 + }; 1.31 + slot = nssToken_GetSlot(t); 1.32 + status = nssCKObject_GetAttributes(h, cert_template, 2, 1.33 + NULL, session, slot); 1.34 + nssSlot_Destroy(slot); 1.35 + if (status != PR_SUCCESS) { 1.36 + /* a failure here indicates a device error */ 1.37 + return (nssCryptokiObject *)NULL; 1.38 + } 1.39 + object = nss_ZNEW(NULL, nssCryptokiObject); 1.40 + if (!object) { 1.41 + return (nssCryptokiObject *)NULL; 1.42 + } 1.43 + object->handle = h; 1.44 + object->token = nssToken_AddRef(t); 1.45 + isTokenObject = (CK_BBOOL *)cert_template[0].pValue; 1.46 + object->isTokenObject = *isTokenObject; 1.47 + nss_ZFreeIf(isTokenObject); 1.48 + NSS_CK_ATTRIBUTE_TO_UTF8(&cert_template[1], object->label); 1.49 + return object; 1.50 +} 1.51 + 1.52 +NSS_IMPLEMENT void 1.53 +nssCryptokiObject_Destroy ( 1.54 + nssCryptokiObject *object 1.55 +) 1.56 +{ 1.57 + if (object) { 1.58 + nssToken_Destroy(object->token); 1.59 + nss_ZFreeIf(object->label); 1.60 + nss_ZFreeIf(object); 1.61 + } 1.62 +} 1.63 + 1.64 +NSS_IMPLEMENT nssCryptokiObject * 1.65 +nssCryptokiObject_Clone ( 1.66 + nssCryptokiObject *object 1.67 +) 1.68 +{ 1.69 + nssCryptokiObject *rvObject; 1.70 + rvObject = nss_ZNEW(NULL, nssCryptokiObject); 1.71 + if (rvObject) { 1.72 + rvObject->handle = object->handle; 1.73 + rvObject->token = nssToken_AddRef(object->token); 1.74 + rvObject->isTokenObject = object->isTokenObject; 1.75 + if (object->label) { 1.76 + rvObject->label = nssUTF8_Duplicate(object->label, NULL); 1.77 + } 1.78 + } 1.79 + return rvObject; 1.80 +} 1.81 + 1.82 +NSS_EXTERN PRBool 1.83 +nssCryptokiObject_Equal ( 1.84 + nssCryptokiObject *o1, 1.85 + nssCryptokiObject *o2 1.86 +) 1.87 +{ 1.88 + return (o1->token == o2->token && o1->handle == o2->handle); 1.89 +} 1.90 + 1.91 +NSS_IMPLEMENT PRUint32 1.92 +nssPKCS11String_Length(CK_CHAR *pkcs11Str, PRUint32 bufLen) 1.93 +{ 1.94 + PRInt32 i; 1.95 + for (i = bufLen - 1; i>=0; ) { 1.96 + if (pkcs11Str[i] != ' ' && pkcs11Str[i] != '\0') break; 1.97 + --i; 1.98 + } 1.99 + return (PRUint32)(i + 1); 1.100 +} 1.101 + 1.102 +/* 1.103 + * Slot arrays 1.104 + */ 1.105 + 1.106 +NSS_IMPLEMENT NSSSlot ** 1.107 +nssSlotArray_Clone ( 1.108 + NSSSlot **slots 1.109 +) 1.110 +{ 1.111 + NSSSlot **rvSlots = NULL; 1.112 + NSSSlot **sp = slots; 1.113 + PRUint32 count = 0; 1.114 + while (sp && *sp) count++; 1.115 + if (count > 0) { 1.116 + rvSlots = nss_ZNEWARRAY(NULL, NSSSlot *, count + 1); 1.117 + if (rvSlots) { 1.118 + for (sp = slots, count = 0; *sp; sp++) { 1.119 + rvSlots[count++] = nssSlot_AddRef(*sp); 1.120 + } 1.121 + } 1.122 + } 1.123 + return rvSlots; 1.124 +} 1.125 + 1.126 +NSS_IMPLEMENT void 1.127 +nssSlotArray_Destroy ( 1.128 + NSSSlot **slots 1.129 +) 1.130 +{ 1.131 + if (slots) { 1.132 + NSSSlot **slotp; 1.133 + for (slotp = slots; *slotp; slotp++) { 1.134 + nssSlot_Destroy(*slotp); 1.135 + } 1.136 + nss_ZFreeIf(slots); 1.137 + } 1.138 +} 1.139 + 1.140 +NSS_IMPLEMENT void 1.141 +NSSSlotArray_Destroy ( 1.142 + NSSSlot **slots 1.143 +) 1.144 +{ 1.145 + nssSlotArray_Destroy(slots); 1.146 +} 1.147 + 1.148 +NSS_IMPLEMENT void 1.149 +nssTokenArray_Destroy ( 1.150 + NSSToken **tokens 1.151 +) 1.152 +{ 1.153 + if (tokens) { 1.154 + NSSToken **tokenp; 1.155 + for (tokenp = tokens; *tokenp; tokenp++) { 1.156 + nssToken_Destroy(*tokenp); 1.157 + } 1.158 + nss_ZFreeIf(tokens); 1.159 + } 1.160 +} 1.161 + 1.162 +NSS_IMPLEMENT void 1.163 +NSSTokenArray_Destroy ( 1.164 + NSSToken **tokens 1.165 +) 1.166 +{ 1.167 + nssTokenArray_Destroy(tokens); 1.168 +} 1.169 + 1.170 +NSS_IMPLEMENT void 1.171 +nssCryptokiObjectArray_Destroy ( 1.172 + nssCryptokiObject **objects 1.173 +) 1.174 +{ 1.175 + if (objects) { 1.176 + nssCryptokiObject **op; 1.177 + for (op = objects; *op; op++) { 1.178 + nssCryptokiObject_Destroy(*op); 1.179 + } 1.180 + nss_ZFreeIf(objects); 1.181 + } 1.182 +} 1.183 + 1.184 +/* object cache for token */ 1.185 + 1.186 +typedef struct 1.187 +{ 1.188 + NSSArena *arena; 1.189 + nssCryptokiObject *object; 1.190 + CK_ATTRIBUTE_PTR attributes; 1.191 + CK_ULONG numAttributes; 1.192 +} 1.193 +nssCryptokiObjectAndAttributes; 1.194 + 1.195 +enum { 1.196 + cachedCerts = 0, 1.197 + cachedTrust = 1, 1.198 + cachedCRLs = 2 1.199 +} cachedObjectType; 1.200 + 1.201 +struct nssTokenObjectCacheStr 1.202 +{ 1.203 + NSSToken *token; 1.204 + PZLock *lock; 1.205 + PRBool loggedIn; 1.206 + PRBool doObjectType[3]; 1.207 + PRBool searchedObjectType[3]; 1.208 + nssCryptokiObjectAndAttributes **objects[3]; 1.209 +}; 1.210 + 1.211 +NSS_IMPLEMENT nssTokenObjectCache * 1.212 +nssTokenObjectCache_Create ( 1.213 + NSSToken *token, 1.214 + PRBool cacheCerts, 1.215 + PRBool cacheTrust, 1.216 + PRBool cacheCRLs 1.217 +) 1.218 +{ 1.219 + nssTokenObjectCache *rvCache; 1.220 + rvCache = nss_ZNEW(NULL, nssTokenObjectCache); 1.221 + if (!rvCache) { 1.222 + goto loser; 1.223 + } 1.224 + rvCache->lock = PZ_NewLock(nssILockOther); /* XXX */ 1.225 + if (!rvCache->lock) { 1.226 + goto loser; 1.227 + } 1.228 + rvCache->doObjectType[cachedCerts] = cacheCerts; 1.229 + rvCache->doObjectType[cachedTrust] = cacheTrust; 1.230 + rvCache->doObjectType[cachedCRLs] = cacheCRLs; 1.231 + rvCache->token = token; /* cache goes away with token */ 1.232 + return rvCache; 1.233 +loser: 1.234 + nssTokenObjectCache_Destroy(rvCache); 1.235 + return (nssTokenObjectCache *)NULL; 1.236 +} 1.237 + 1.238 +static void 1.239 +clear_cache ( 1.240 + nssTokenObjectCache *cache 1.241 +) 1.242 +{ 1.243 + nssCryptokiObjectAndAttributes **oa; 1.244 + PRUint32 objectType; 1.245 + for (objectType = cachedCerts; objectType <= cachedCRLs; objectType++) { 1.246 + cache->searchedObjectType[objectType] = PR_FALSE; 1.247 + if (!cache->objects[objectType]) { 1.248 + continue; 1.249 + } 1.250 + for (oa = cache->objects[objectType]; *oa; oa++) { 1.251 + /* prevent the token from being destroyed */ 1.252 + (*oa)->object->token = NULL; 1.253 + nssCryptokiObject_Destroy((*oa)->object); 1.254 + nssArena_Destroy((*oa)->arena); 1.255 + } 1.256 + nss_ZFreeIf(cache->objects[objectType]); 1.257 + cache->objects[objectType] = NULL; 1.258 + } 1.259 +} 1.260 + 1.261 +NSS_IMPLEMENT void 1.262 +nssTokenObjectCache_Clear ( 1.263 + nssTokenObjectCache *cache 1.264 +) 1.265 +{ 1.266 + if (cache) { 1.267 + PZ_Lock(cache->lock); 1.268 + clear_cache(cache); 1.269 + PZ_Unlock(cache->lock); 1.270 + } 1.271 +} 1.272 + 1.273 +NSS_IMPLEMENT void 1.274 +nssTokenObjectCache_Destroy ( 1.275 + nssTokenObjectCache *cache 1.276 +) 1.277 +{ 1.278 + if (cache) { 1.279 + clear_cache(cache); 1.280 + if (cache->lock) { 1.281 + PZ_DestroyLock(cache->lock); 1.282 + } 1.283 + nss_ZFreeIf(cache); 1.284 + } 1.285 +} 1.286 + 1.287 +NSS_IMPLEMENT PRBool 1.288 +nssTokenObjectCache_HaveObjectClass ( 1.289 + nssTokenObjectCache *cache, 1.290 + CK_OBJECT_CLASS objclass 1.291 +) 1.292 +{ 1.293 + PRBool haveIt; 1.294 + PZ_Lock(cache->lock); 1.295 + switch (objclass) { 1.296 + case CKO_CERTIFICATE: haveIt = cache->doObjectType[cachedCerts]; break; 1.297 + case CKO_NETSCAPE_TRUST: haveIt = cache->doObjectType[cachedTrust]; break; 1.298 + case CKO_NETSCAPE_CRL: haveIt = cache->doObjectType[cachedCRLs]; break; 1.299 + default: haveIt = PR_FALSE; 1.300 + } 1.301 + PZ_Unlock(cache->lock); 1.302 + return haveIt; 1.303 +} 1.304 + 1.305 +static nssCryptokiObjectAndAttributes ** 1.306 +create_object_array ( 1.307 + nssCryptokiObject **objects, 1.308 + PRBool *doObjects, 1.309 + PRUint32 *numObjects, 1.310 + PRStatus *status 1.311 +) 1.312 +{ 1.313 + nssCryptokiObjectAndAttributes **rvOandA = NULL; 1.314 + *numObjects = 0; 1.315 + /* There are no objects for this type */ 1.316 + if (!objects || !*objects) { 1.317 + *status = PR_SUCCESS; 1.318 + return rvOandA; 1.319 + } 1.320 + while (*objects++) (*numObjects)++; 1.321 + if (*numObjects >= MAX_LOCAL_CACHE_OBJECTS) { 1.322 + /* Hit the maximum allowed, so don't use a cache (there are 1.323 + * too many objects to make caching worthwhile, presumably, if 1.324 + * the token can handle that many objects, it can handle searching. 1.325 + */ 1.326 + *doObjects = PR_FALSE; 1.327 + *status = PR_FAILURE; 1.328 + *numObjects = 0; 1.329 + } else { 1.330 + rvOandA = nss_ZNEWARRAY(NULL, 1.331 + nssCryptokiObjectAndAttributes *, 1.332 + *numObjects + 1); 1.333 + *status = rvOandA ? PR_SUCCESS : PR_FAILURE; 1.334 + } 1.335 + return rvOandA; 1.336 +} 1.337 + 1.338 +static nssCryptokiObjectAndAttributes * 1.339 +create_object ( 1.340 + nssCryptokiObject *object, 1.341 + const CK_ATTRIBUTE_TYPE *types, 1.342 + PRUint32 numTypes, 1.343 + PRStatus *status 1.344 +) 1.345 +{ 1.346 + PRUint32 j; 1.347 + NSSArena *arena = NULL; 1.348 + NSSSlot *slot = NULL; 1.349 + nssSession *session = NULL; 1.350 + nssCryptokiObjectAndAttributes *rvCachedObject = NULL; 1.351 + 1.352 + slot = nssToken_GetSlot(object->token); 1.353 + if (!slot) { 1.354 + nss_SetError(NSS_ERROR_INVALID_POINTER); 1.355 + goto loser; 1.356 + } 1.357 + session = nssToken_GetDefaultSession(object->token); 1.358 + if (!session) { 1.359 + nss_SetError(NSS_ERROR_INVALID_POINTER); 1.360 + goto loser; 1.361 + } 1.362 + arena = nssArena_Create(); 1.363 + if (!arena) { 1.364 + goto loser; 1.365 + } 1.366 + rvCachedObject = nss_ZNEW(arena, nssCryptokiObjectAndAttributes); 1.367 + if (!rvCachedObject) { 1.368 + goto loser; 1.369 + } 1.370 + rvCachedObject->arena = arena; 1.371 + /* The cache is tied to the token, and therefore the objects 1.372 + * in it should not hold references to the token. 1.373 + */ 1.374 + nssToken_Destroy(object->token); 1.375 + rvCachedObject->object = object; 1.376 + rvCachedObject->attributes = nss_ZNEWARRAY(arena, CK_ATTRIBUTE, numTypes); 1.377 + if (!rvCachedObject->attributes) { 1.378 + goto loser; 1.379 + } 1.380 + for (j=0; j<numTypes; j++) { 1.381 + rvCachedObject->attributes[j].type = types[j]; 1.382 + } 1.383 + *status = nssCKObject_GetAttributes(object->handle, 1.384 + rvCachedObject->attributes, 1.385 + numTypes, 1.386 + arena, 1.387 + session, 1.388 + slot); 1.389 + if (*status != PR_SUCCESS) { 1.390 + goto loser; 1.391 + } 1.392 + rvCachedObject->numAttributes = numTypes; 1.393 + *status = PR_SUCCESS; 1.394 + nssSlot_Destroy(slot); 1.395 + 1.396 + return rvCachedObject; 1.397 +loser: 1.398 + *status = PR_FAILURE; 1.399 + if (slot) { 1.400 + nssSlot_Destroy(slot); 1.401 + } 1.402 + if (arena) 1.403 + nssArena_Destroy(arena); 1.404 + return (nssCryptokiObjectAndAttributes *)NULL; 1.405 +} 1.406 + 1.407 +/* 1.408 + * 1.409 + * State diagram for cache: 1.410 + * 1.411 + * token !present token removed 1.412 + * +-------------------------+<----------------------+ 1.413 + * | ^ | 1.414 + * v | | 1.415 + * +----------+ slot friendly | token present +----------+ 1.416 + * | cache | -----------------> % ---------------> | cache | 1.417 + * | unloaded | | loaded | 1.418 + * +----------+ +----------+ 1.419 + * ^ | ^ | 1.420 + * | | slot !friendly slot logged in | | 1.421 + * | +-----------------------> % ----------------------+ | 1.422 + * | | | 1.423 + * | slot logged out v slot !friendly | 1.424 + * +-----------------------------+<--------------------------+ 1.425 + * 1.426 + */ 1.427 + 1.428 +/* This function must not be called with cache->lock locked. */ 1.429 +static PRBool 1.430 +token_is_present ( 1.431 + nssTokenObjectCache *cache 1.432 +) 1.433 +{ 1.434 + NSSSlot *slot = nssToken_GetSlot(cache->token); 1.435 + PRBool tokenPresent = nssSlot_IsTokenPresent(slot); 1.436 + nssSlot_Destroy(slot); 1.437 + return tokenPresent; 1.438 +} 1.439 + 1.440 +static PRBool 1.441 +search_for_objects ( 1.442 + nssTokenObjectCache *cache 1.443 +) 1.444 +{ 1.445 + PRBool doSearch = PR_FALSE; 1.446 + NSSSlot *slot = nssToken_GetSlot(cache->token); 1.447 + /* Handle non-friendly slots (slots which require login for objects) */ 1.448 + if (!nssSlot_IsFriendly(slot)) { 1.449 + if (nssSlot_IsLoggedIn(slot)) { 1.450 + /* Either no state change, or went from !logged in -> logged in */ 1.451 + cache->loggedIn = PR_TRUE; 1.452 + doSearch = PR_TRUE; 1.453 + } else { 1.454 + if (cache->loggedIn) { 1.455 + /* went from logged in -> !logged in, destroy cached objects */ 1.456 + clear_cache(cache); 1.457 + cache->loggedIn = PR_FALSE; 1.458 + } /* else no state change, still not logged in, so exit */ 1.459 + } 1.460 + } else { 1.461 + /* slot is friendly, thus always available for search */ 1.462 + doSearch = PR_TRUE; 1.463 + } 1.464 + nssSlot_Destroy(slot); 1.465 + return doSearch; 1.466 +} 1.467 + 1.468 +static nssCryptokiObjectAndAttributes * 1.469 +create_cert ( 1.470 + nssCryptokiObject *object, 1.471 + PRStatus *status 1.472 +) 1.473 +{ 1.474 + static const CK_ATTRIBUTE_TYPE certAttr[] = { 1.475 + CKA_CLASS, 1.476 + CKA_TOKEN, 1.477 + CKA_LABEL, 1.478 + CKA_CERTIFICATE_TYPE, 1.479 + CKA_ID, 1.480 + CKA_VALUE, 1.481 + CKA_ISSUER, 1.482 + CKA_SERIAL_NUMBER, 1.483 + CKA_SUBJECT, 1.484 + CKA_NETSCAPE_EMAIL 1.485 + }; 1.486 + static const PRUint32 numCertAttr = sizeof(certAttr) / sizeof(certAttr[0]); 1.487 + return create_object(object, certAttr, numCertAttr, status); 1.488 +} 1.489 + 1.490 +static nssCryptokiObjectAndAttributes * 1.491 +create_trust ( 1.492 + nssCryptokiObject *object, 1.493 + PRStatus *status 1.494 +) 1.495 +{ 1.496 + static const CK_ATTRIBUTE_TYPE trustAttr[] = { 1.497 + CKA_CLASS, 1.498 + CKA_TOKEN, 1.499 + CKA_LABEL, 1.500 + CKA_CERT_SHA1_HASH, 1.501 + CKA_CERT_MD5_HASH, 1.502 + CKA_ISSUER, 1.503 + CKA_SUBJECT, 1.504 + CKA_TRUST_SERVER_AUTH, 1.505 + CKA_TRUST_CLIENT_AUTH, 1.506 + CKA_TRUST_EMAIL_PROTECTION, 1.507 + CKA_TRUST_CODE_SIGNING 1.508 + }; 1.509 + static const PRUint32 numTrustAttr = sizeof(trustAttr) / sizeof(trustAttr[0]); 1.510 + return create_object(object, trustAttr, numTrustAttr, status); 1.511 +} 1.512 + 1.513 +static nssCryptokiObjectAndAttributes * 1.514 +create_crl ( 1.515 + nssCryptokiObject *object, 1.516 + PRStatus *status 1.517 +) 1.518 +{ 1.519 + static const CK_ATTRIBUTE_TYPE crlAttr[] = { 1.520 + CKA_CLASS, 1.521 + CKA_TOKEN, 1.522 + CKA_LABEL, 1.523 + CKA_VALUE, 1.524 + CKA_SUBJECT, 1.525 + CKA_NETSCAPE_KRL, 1.526 + CKA_NETSCAPE_URL 1.527 + }; 1.528 + static const PRUint32 numCRLAttr = sizeof(crlAttr) / sizeof(crlAttr[0]); 1.529 + return create_object(object, crlAttr, numCRLAttr, status); 1.530 +} 1.531 + 1.532 +/* Dispatch to the create function for the object type */ 1.533 +static nssCryptokiObjectAndAttributes * 1.534 +create_object_of_type ( 1.535 + nssCryptokiObject *object, 1.536 + PRUint32 objectType, 1.537 + PRStatus *status 1.538 +) 1.539 +{ 1.540 + if (objectType == cachedCerts) { 1.541 + return create_cert(object, status); 1.542 + } 1.543 + if (objectType == cachedTrust) { 1.544 + return create_trust(object, status); 1.545 + } 1.546 + if (objectType == cachedCRLs) { 1.547 + return create_crl(object, status); 1.548 + } 1.549 + return (nssCryptokiObjectAndAttributes *)NULL; 1.550 +} 1.551 + 1.552 +static PRStatus 1.553 +get_token_objects_for_cache ( 1.554 + nssTokenObjectCache *cache, 1.555 + PRUint32 objectType, 1.556 + CK_OBJECT_CLASS objclass 1.557 +) 1.558 +{ 1.559 + PRStatus status; 1.560 + nssCryptokiObject **objects; 1.561 + PRBool *doIt = &cache->doObjectType[objectType]; 1.562 + PRUint32 i, numObjects; 1.563 + 1.564 + if (!search_for_objects(cache) || 1.565 + cache->searchedObjectType[objectType] || 1.566 + !cache->doObjectType[objectType]) 1.567 + { 1.568 + /* Either there was a state change that prevents a search 1.569 + * (token logged out), or the search was already done, 1.570 + * or objects of this type are not being cached. 1.571 + */ 1.572 + return PR_SUCCESS; 1.573 + } 1.574 + objects = nssToken_FindObjects(cache->token, NULL, objclass, 1.575 + nssTokenSearchType_TokenForced, 1.576 + MAX_LOCAL_CACHE_OBJECTS, &status); 1.577 + if (status != PR_SUCCESS) { 1.578 + return status; 1.579 + } 1.580 + cache->objects[objectType] = create_object_array(objects, 1.581 + doIt, 1.582 + &numObjects, 1.583 + &status); 1.584 + if (status != PR_SUCCESS) { 1.585 + return status; 1.586 + } 1.587 + for (i=0; i<numObjects; i++) { 1.588 + cache->objects[objectType][i] = create_object_of_type(objects[i], 1.589 + objectType, 1.590 + &status); 1.591 + if (status != PR_SUCCESS) { 1.592 + break; 1.593 + } 1.594 + } 1.595 + if (status == PR_SUCCESS) { 1.596 + nss_ZFreeIf(objects); 1.597 + } else { 1.598 + PRUint32 j; 1.599 + for (j=0; j<i; j++) { 1.600 + /* sigh */ 1.601 + nssToken_AddRef(cache->objects[objectType][j]->object->token); 1.602 + nssArena_Destroy(cache->objects[objectType][j]->arena); 1.603 + } 1.604 + nss_ZFreeIf(cache->objects[objectType]); 1.605 + cache->objects[objectType] = NULL; 1.606 + nssCryptokiObjectArray_Destroy(objects); 1.607 + } 1.608 + cache->searchedObjectType[objectType] = PR_TRUE; 1.609 + return status; 1.610 +} 1.611 + 1.612 +static CK_ATTRIBUTE_PTR 1.613 +find_attribute_in_object ( 1.614 + nssCryptokiObjectAndAttributes *obj, 1.615 + CK_ATTRIBUTE_TYPE attrType 1.616 +) 1.617 +{ 1.618 + PRUint32 j; 1.619 + for (j=0; j<obj->numAttributes; j++) { 1.620 + if (attrType == obj->attributes[j].type) { 1.621 + return &obj->attributes[j]; 1.622 + } 1.623 + } 1.624 + return (CK_ATTRIBUTE_PTR)NULL; 1.625 +} 1.626 + 1.627 +/* Find all objects in the array that match the supplied template */ 1.628 +static nssCryptokiObject ** 1.629 +find_objects_in_array ( 1.630 + nssCryptokiObjectAndAttributes **objArray, 1.631 + CK_ATTRIBUTE_PTR ot, 1.632 + CK_ULONG otlen, 1.633 + PRUint32 maximumOpt 1.634 +) 1.635 +{ 1.636 + PRIntn oi = 0; 1.637 + PRUint32 i; 1.638 + NSSArena *arena; 1.639 + PRUint32 size = 8; 1.640 + PRUint32 numMatches = 0; 1.641 + nssCryptokiObject **objects = NULL; 1.642 + nssCryptokiObjectAndAttributes **matches = NULL; 1.643 + CK_ATTRIBUTE_PTR attr; 1.644 + 1.645 + if (!objArray) { 1.646 + return (nssCryptokiObject **)NULL; 1.647 + } 1.648 + arena = nssArena_Create(); 1.649 + if (!arena) { 1.650 + return (nssCryptokiObject **)NULL; 1.651 + } 1.652 + matches = nss_ZNEWARRAY(arena, nssCryptokiObjectAndAttributes *, size); 1.653 + if (!matches) { 1.654 + goto loser; 1.655 + } 1.656 + if (maximumOpt == 0) maximumOpt = ~0; 1.657 + /* loop over the cached objects */ 1.658 + for (; *objArray && numMatches < maximumOpt; objArray++) { 1.659 + nssCryptokiObjectAndAttributes *obj = *objArray; 1.660 + /* loop over the test template */ 1.661 + for (i=0; i<otlen; i++) { 1.662 + /* see if the object has the attribute */ 1.663 + attr = find_attribute_in_object(obj, ot[i].type); 1.664 + if (!attr) { 1.665 + /* nope, match failed */ 1.666 + break; 1.667 + } 1.668 + /* compare the attribute against the test value */ 1.669 + if (ot[i].ulValueLen != attr->ulValueLen || 1.670 + !nsslibc_memequal(ot[i].pValue, 1.671 + attr->pValue, 1.672 + attr->ulValueLen, NULL)) 1.673 + { 1.674 + /* nope, match failed */ 1.675 + break; 1.676 + } 1.677 + } 1.678 + if (i == otlen) { 1.679 + /* all of the attributes in the test template were found 1.680 + * in the object's template, and they all matched 1.681 + */ 1.682 + matches[numMatches++] = obj; 1.683 + if (numMatches == size) { 1.684 + size *= 2; 1.685 + matches = nss_ZREALLOCARRAY(matches, 1.686 + nssCryptokiObjectAndAttributes *, 1.687 + size); 1.688 + if (!matches) { 1.689 + goto loser; 1.690 + } 1.691 + } 1.692 + } 1.693 + } 1.694 + if (numMatches > 0) { 1.695 + objects = nss_ZNEWARRAY(NULL, nssCryptokiObject *, numMatches + 1); 1.696 + if (!objects) { 1.697 + goto loser; 1.698 + } 1.699 + for (oi=0; oi<(PRIntn)numMatches; oi++) { 1.700 + objects[oi] = nssCryptokiObject_Clone(matches[oi]->object); 1.701 + if (!objects[oi]) { 1.702 + goto loser; 1.703 + } 1.704 + } 1.705 + } 1.706 + nssArena_Destroy(arena); 1.707 + return objects; 1.708 +loser: 1.709 + nssCryptokiObjectArray_Destroy(objects); 1.710 + nssArena_Destroy(arena); 1.711 + return (nssCryptokiObject **)NULL; 1.712 +} 1.713 + 1.714 +NSS_IMPLEMENT nssCryptokiObject ** 1.715 +nssTokenObjectCache_FindObjectsByTemplate ( 1.716 + nssTokenObjectCache *cache, 1.717 + CK_OBJECT_CLASS objclass, 1.718 + CK_ATTRIBUTE_PTR otemplate, 1.719 + CK_ULONG otlen, 1.720 + PRUint32 maximumOpt, 1.721 + PRStatus *statusOpt 1.722 +) 1.723 +{ 1.724 + PRStatus status = PR_FAILURE; 1.725 + nssCryptokiObject **rvObjects = NULL; 1.726 + PRUint32 objectType; 1.727 + if (!token_is_present(cache)) { 1.728 + status = PR_SUCCESS; 1.729 + goto finish; 1.730 + } 1.731 + switch (objclass) { 1.732 + case CKO_CERTIFICATE: objectType = cachedCerts; break; 1.733 + case CKO_NETSCAPE_TRUST: objectType = cachedTrust; break; 1.734 + case CKO_NETSCAPE_CRL: objectType = cachedCRLs; break; 1.735 + default: goto finish; 1.736 + } 1.737 + PZ_Lock(cache->lock); 1.738 + if (cache->doObjectType[objectType]) { 1.739 + status = get_token_objects_for_cache(cache, objectType, objclass); 1.740 + if (status == PR_SUCCESS) { 1.741 + rvObjects = find_objects_in_array(cache->objects[objectType], 1.742 + otemplate, otlen, maximumOpt); 1.743 + } 1.744 + } 1.745 + PZ_Unlock(cache->lock); 1.746 +finish: 1.747 + if (statusOpt) { 1.748 + *statusOpt = status; 1.749 + } 1.750 + return rvObjects; 1.751 +} 1.752 + 1.753 +static PRBool 1.754 +cache_available_for_object_type ( 1.755 + nssTokenObjectCache *cache, 1.756 + PRUint32 objectType 1.757 +) 1.758 +{ 1.759 + if (!cache->doObjectType[objectType]) { 1.760 + /* not caching this object kind */ 1.761 + return PR_FALSE; 1.762 + } 1.763 + if (!cache->searchedObjectType[objectType]) { 1.764 + /* objects are not cached yet */ 1.765 + return PR_FALSE; 1.766 + } 1.767 + if (!search_for_objects(cache)) { 1.768 + /* not logged in */ 1.769 + return PR_FALSE; 1.770 + } 1.771 + return PR_TRUE; 1.772 +} 1.773 + 1.774 +NSS_IMPLEMENT PRStatus 1.775 +nssTokenObjectCache_GetObjectAttributes ( 1.776 + nssTokenObjectCache *cache, 1.777 + NSSArena *arenaOpt, 1.778 + nssCryptokiObject *object, 1.779 + CK_OBJECT_CLASS objclass, 1.780 + CK_ATTRIBUTE_PTR atemplate, 1.781 + CK_ULONG atlen 1.782 +) 1.783 +{ 1.784 + PRUint32 i, j; 1.785 + NSSArena *arena = NULL; 1.786 + nssArenaMark *mark = NULL; 1.787 + nssCryptokiObjectAndAttributes *cachedOA = NULL; 1.788 + nssCryptokiObjectAndAttributes **oa = NULL; 1.789 + PRUint32 objectType; 1.790 + if (!token_is_present(cache)) { 1.791 + return PR_FAILURE; 1.792 + } 1.793 + PZ_Lock(cache->lock); 1.794 + switch (objclass) { 1.795 + case CKO_CERTIFICATE: objectType = cachedCerts; break; 1.796 + case CKO_NETSCAPE_TRUST: objectType = cachedTrust; break; 1.797 + case CKO_NETSCAPE_CRL: objectType = cachedCRLs; break; 1.798 + default: goto loser; 1.799 + } 1.800 + if (!cache_available_for_object_type(cache, objectType)) { 1.801 + goto loser; 1.802 + } 1.803 + oa = cache->objects[objectType]; 1.804 + if (!oa) { 1.805 + goto loser; 1.806 + } 1.807 + for (; *oa; oa++) { 1.808 + if (nssCryptokiObject_Equal((*oa)->object, object)) { 1.809 + cachedOA = *oa; 1.810 + break; 1.811 + } 1.812 + } 1.813 + if (!cachedOA) { 1.814 + goto loser; /* don't have this object */ 1.815 + } 1.816 + if (arenaOpt) { 1.817 + arena = arenaOpt; 1.818 + mark = nssArena_Mark(arena); 1.819 + } 1.820 + for (i=0; i<atlen; i++) { 1.821 + for (j=0; j<cachedOA->numAttributes; j++) { 1.822 + if (atemplate[i].type == cachedOA->attributes[j].type) { 1.823 + CK_ATTRIBUTE_PTR attr = &cachedOA->attributes[j]; 1.824 + if (cachedOA->attributes[j].ulValueLen == 0 || 1.825 + cachedOA->attributes[j].ulValueLen == (CK_ULONG)-1) 1.826 + { 1.827 + break; /* invalid attribute */ 1.828 + } 1.829 + if (atemplate[i].ulValueLen > 0) { 1.830 + if (atemplate[i].pValue == NULL || 1.831 + atemplate[i].ulValueLen < attr->ulValueLen) 1.832 + { 1.833 + goto loser; 1.834 + } 1.835 + } else { 1.836 + atemplate[i].pValue = nss_ZAlloc(arena, attr->ulValueLen); 1.837 + if (!atemplate[i].pValue) { 1.838 + goto loser; 1.839 + } 1.840 + } 1.841 + nsslibc_memcpy(atemplate[i].pValue, 1.842 + attr->pValue, attr->ulValueLen); 1.843 + atemplate[i].ulValueLen = attr->ulValueLen; 1.844 + break; 1.845 + } 1.846 + } 1.847 + if (j == cachedOA->numAttributes) { 1.848 + atemplate[i].ulValueLen = (CK_ULONG)-1; 1.849 + } 1.850 + } 1.851 + PZ_Unlock(cache->lock); 1.852 + if (mark) { 1.853 + nssArena_Unmark(arena, mark); 1.854 + } 1.855 + return PR_SUCCESS; 1.856 +loser: 1.857 + PZ_Unlock(cache->lock); 1.858 + if (mark) { 1.859 + nssArena_Release(arena, mark); 1.860 + } 1.861 + return PR_FAILURE; 1.862 +} 1.863 + 1.864 +NSS_IMPLEMENT PRStatus 1.865 +nssTokenObjectCache_ImportObject ( 1.866 + nssTokenObjectCache *cache, 1.867 + nssCryptokiObject *object, 1.868 + CK_OBJECT_CLASS objclass, 1.869 + CK_ATTRIBUTE_PTR ot, 1.870 + CK_ULONG otlen 1.871 +) 1.872 +{ 1.873 + PRStatus status = PR_SUCCESS; 1.874 + PRUint32 count; 1.875 + nssCryptokiObjectAndAttributes **oa, ***otype; 1.876 + PRUint32 objectType; 1.877 + PRBool haveIt = PR_FALSE; 1.878 + 1.879 + if (!token_is_present(cache)) { 1.880 + return PR_SUCCESS; /* cache not active, ignored */ 1.881 + } 1.882 + PZ_Lock(cache->lock); 1.883 + switch (objclass) { 1.884 + case CKO_CERTIFICATE: objectType = cachedCerts; break; 1.885 + case CKO_NETSCAPE_TRUST: objectType = cachedTrust; break; 1.886 + case CKO_NETSCAPE_CRL: objectType = cachedCRLs; break; 1.887 + default: 1.888 + PZ_Unlock(cache->lock); 1.889 + return PR_SUCCESS; /* don't need to import it here */ 1.890 + } 1.891 + if (!cache_available_for_object_type(cache, objectType)) { 1.892 + PZ_Unlock(cache->lock); 1.893 + return PR_SUCCESS; /* cache not active, ignored */ 1.894 + } 1.895 + count = 0; 1.896 + otype = &cache->objects[objectType]; /* index into array of types */ 1.897 + oa = *otype; /* the array of objects for this type */ 1.898 + while (oa && *oa) { 1.899 + if (nssCryptokiObject_Equal((*oa)->object, object)) { 1.900 + haveIt = PR_TRUE; 1.901 + break; 1.902 + } 1.903 + count++; 1.904 + oa++; 1.905 + } 1.906 + if (haveIt) { 1.907 + /* Destroy the old entry */ 1.908 + (*oa)->object->token = NULL; 1.909 + nssCryptokiObject_Destroy((*oa)->object); 1.910 + nssArena_Destroy((*oa)->arena); 1.911 + } else { 1.912 + /* Create space for a new entry */ 1.913 + if (count > 0) { 1.914 + *otype = nss_ZREALLOCARRAY(*otype, 1.915 + nssCryptokiObjectAndAttributes *, 1.916 + count + 2); 1.917 + } else { 1.918 + *otype = nss_ZNEWARRAY(NULL, nssCryptokiObjectAndAttributes *, 2); 1.919 + } 1.920 + } 1.921 + if (*otype) { 1.922 + nssCryptokiObject *copyObject = nssCryptokiObject_Clone(object); 1.923 + (*otype)[count] = create_object_of_type(copyObject, objectType, 1.924 + &status); 1.925 + } else { 1.926 + status = PR_FAILURE; 1.927 + } 1.928 + PZ_Unlock(cache->lock); 1.929 + return status; 1.930 +} 1.931 + 1.932 +NSS_IMPLEMENT void 1.933 +nssTokenObjectCache_RemoveObject ( 1.934 + nssTokenObjectCache *cache, 1.935 + nssCryptokiObject *object 1.936 +) 1.937 +{ 1.938 + PRUint32 oType; 1.939 + nssCryptokiObjectAndAttributes **oa, **swp = NULL; 1.940 + if (!token_is_present(cache)) { 1.941 + return; 1.942 + } 1.943 + PZ_Lock(cache->lock); 1.944 + for (oType=0; oType<3; oType++) { 1.945 + if (!cache_available_for_object_type(cache, oType) || 1.946 + !cache->objects[oType]) 1.947 + { 1.948 + continue; 1.949 + } 1.950 + for (oa = cache->objects[oType]; *oa; oa++) { 1.951 + if (nssCryptokiObject_Equal((*oa)->object, object)) { 1.952 + swp = oa; /* the entry to remove */ 1.953 + while (oa[1]) oa++; /* go to the tail */ 1.954 + (*swp)->object->token = NULL; 1.955 + nssCryptokiObject_Destroy((*swp)->object); 1.956 + nssArena_Destroy((*swp)->arena); /* destroy it */ 1.957 + *swp = *oa; /* swap the last with the removed */ 1.958 + *oa = NULL; /* null-terminate the array */ 1.959 + break; 1.960 + } 1.961 + } 1.962 + if (swp) { 1.963 + break; 1.964 + } 1.965 + } 1.966 + if ((oType <3) && 1.967 + cache->objects[oType] && cache->objects[oType][0] == NULL) { 1.968 + nss_ZFreeIf(cache->objects[oType]); /* no entries remaining */ 1.969 + cache->objects[oType] = NULL; 1.970 + } 1.971 + PZ_Unlock(cache->lock); 1.972 +} 1.973 + 1.974 +/* These two hash algorithms are presently sufficient. 1.975 +** They are used for fingerprints of certs which are stored as the 1.976 +** CKA_CERT_SHA1_HASH and CKA_CERT_MD5_HASH attributes. 1.977 +** We don't need to add SHAxxx to these now. 1.978 +*/ 1.979 +/* XXX of course this doesn't belong here */ 1.980 +NSS_IMPLEMENT NSSAlgorithmAndParameters * 1.981 +NSSAlgorithmAndParameters_CreateSHA1Digest ( 1.982 + NSSArena *arenaOpt 1.983 +) 1.984 +{ 1.985 + NSSAlgorithmAndParameters *rvAP = NULL; 1.986 + rvAP = nss_ZNEW(arenaOpt, NSSAlgorithmAndParameters); 1.987 + if (rvAP) { 1.988 + rvAP->mechanism.mechanism = CKM_SHA_1; 1.989 + rvAP->mechanism.pParameter = NULL; 1.990 + rvAP->mechanism.ulParameterLen = 0; 1.991 + } 1.992 + return rvAP; 1.993 +} 1.994 + 1.995 +NSS_IMPLEMENT NSSAlgorithmAndParameters * 1.996 +NSSAlgorithmAndParameters_CreateMD5Digest ( 1.997 + NSSArena *arenaOpt 1.998 +) 1.999 +{ 1.1000 + NSSAlgorithmAndParameters *rvAP = NULL; 1.1001 + rvAP = nss_ZNEW(arenaOpt, NSSAlgorithmAndParameters); 1.1002 + if (rvAP) { 1.1003 + rvAP->mechanism.mechanism = CKM_MD5; 1.1004 + rvAP->mechanism.pParameter = NULL; 1.1005 + rvAP->mechanism.ulParameterLen = 0; 1.1006 + } 1.1007 + return rvAP; 1.1008 +} 1.1009 +