security/nss/lib/dev/devutil.c

changeset 0
6474c204b198
     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 +

mercurial