security/nss/lib/dev/devtoken.c

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/security/nss/lib/dev/devtoken.c	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,1580 @@
     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 +#include "pkcs11.h"
     1.9 +
    1.10 +#ifndef DEVM_H
    1.11 +#include "devm.h"
    1.12 +#endif /* DEVM_H */
    1.13 +
    1.14 +#ifndef CKHELPER_H
    1.15 +#include "ckhelper.h"
    1.16 +#endif /* CKHELPER_H */
    1.17 +
    1.18 +#include "pk11func.h"
    1.19 +#include "dev3hack.h"
    1.20 +#include "secerr.h"
    1.21 +
    1.22 +extern const NSSError NSS_ERROR_NOT_FOUND;
    1.23 +extern const NSSError NSS_ERROR_INVALID_ARGUMENT;
    1.24 +extern const NSSError NSS_ERROR_PKCS11;
    1.25 +
    1.26 +/* The number of object handles to grab during each call to C_FindObjects */
    1.27 +#define OBJECT_STACK_SIZE 16
    1.28 +
    1.29 +NSS_IMPLEMENT PRStatus
    1.30 +nssToken_Destroy (
    1.31 +  NSSToken *tok
    1.32 +)
    1.33 +{
    1.34 +    if (tok) {
    1.35 +	if (PR_ATOMIC_DECREMENT(&tok->base.refCount) == 0) {
    1.36 +	    PZ_DestroyLock(tok->base.lock);
    1.37 +	    nssTokenObjectCache_Destroy(tok->cache);
    1.38 +	    /* The token holds the first/last reference to the slot.
    1.39 +	     * When the token is actually destroyed, that ref must go too.
    1.40 +	     */
    1.41 +	    (void)nssSlot_Destroy(tok->slot);
    1.42 +	    return nssArena_Destroy(tok->base.arena);
    1.43 +	}
    1.44 +    }
    1.45 +    return PR_SUCCESS;
    1.46 +}
    1.47 +
    1.48 +NSS_IMPLEMENT void
    1.49 +nssToken_Remove (
    1.50 +  NSSToken *tok
    1.51 +)
    1.52 +{
    1.53 +    nssTokenObjectCache_Clear(tok->cache);
    1.54 +}
    1.55 +
    1.56 +NSS_IMPLEMENT void
    1.57 +NSSToken_Destroy (
    1.58 +  NSSToken *tok
    1.59 +)
    1.60 +{
    1.61 +    (void)nssToken_Destroy(tok);
    1.62 +}
    1.63 +
    1.64 +NSS_IMPLEMENT NSSToken *
    1.65 +nssToken_AddRef (
    1.66 +  NSSToken *tok
    1.67 +)
    1.68 +{
    1.69 +    PR_ATOMIC_INCREMENT(&tok->base.refCount);
    1.70 +    return tok;
    1.71 +}
    1.72 +
    1.73 +NSS_IMPLEMENT NSSSlot *
    1.74 +nssToken_GetSlot (
    1.75 +  NSSToken *tok
    1.76 +)
    1.77 +{
    1.78 +    return nssSlot_AddRef(tok->slot);
    1.79 +}
    1.80 +
    1.81 +NSS_IMPLEMENT void *
    1.82 +nssToken_GetCryptokiEPV (
    1.83 +  NSSToken *token
    1.84 +)
    1.85 +{
    1.86 +    return nssSlot_GetCryptokiEPV(token->slot);
    1.87 +}
    1.88 +
    1.89 +NSS_IMPLEMENT nssSession *
    1.90 +nssToken_GetDefaultSession (
    1.91 +  NSSToken *token
    1.92 +)
    1.93 +{
    1.94 +    return token->defaultSession;
    1.95 +}
    1.96 +
    1.97 +NSS_IMPLEMENT NSSUTF8 *
    1.98 +nssToken_GetName (
    1.99 +  NSSToken *tok
   1.100 +)
   1.101 +{
   1.102 +    if (tok == NULL) {
   1.103 +	return "";
   1.104 +    }
   1.105 +    if (tok->base.name[0] == 0) {
   1.106 +	(void) nssSlot_IsTokenPresent(tok->slot);
   1.107 +    } 
   1.108 +    return tok->base.name;
   1.109 +}
   1.110 +
   1.111 +NSS_IMPLEMENT NSSUTF8 *
   1.112 +NSSToken_GetName (
   1.113 +  NSSToken *token
   1.114 +)
   1.115 +{
   1.116 +    return nssToken_GetName(token);
   1.117 +}
   1.118 +
   1.119 +NSS_IMPLEMENT PRBool
   1.120 +nssToken_IsLoginRequired (
   1.121 +  NSSToken *token
   1.122 +)
   1.123 +{
   1.124 +    return (token->ckFlags & CKF_LOGIN_REQUIRED);
   1.125 +}
   1.126 +
   1.127 +NSS_IMPLEMENT PRBool
   1.128 +nssToken_NeedsPINInitialization (
   1.129 +  NSSToken *token
   1.130 +)
   1.131 +{
   1.132 +    return (!(token->ckFlags & CKF_USER_PIN_INITIALIZED));
   1.133 +}
   1.134 +
   1.135 +NSS_IMPLEMENT PRStatus
   1.136 +nssToken_DeleteStoredObject (
   1.137 +  nssCryptokiObject *instance
   1.138 +)
   1.139 +{
   1.140 +    CK_RV ckrv;
   1.141 +    PRStatus status;
   1.142 +    PRBool createdSession = PR_FALSE;
   1.143 +    NSSToken *token = instance->token;
   1.144 +    nssSession *session = NULL;
   1.145 +    void *epv = nssToken_GetCryptokiEPV(instance->token);
   1.146 +    if (token->cache) {
   1.147 +	nssTokenObjectCache_RemoveObject(token->cache, instance);
   1.148 +    }
   1.149 +    if (instance->isTokenObject) {
   1.150 +       if (token->defaultSession && 
   1.151 +           nssSession_IsReadWrite(token->defaultSession)) {
   1.152 +	   session = token->defaultSession;
   1.153 +       } else {
   1.154 +	   session = nssSlot_CreateSession(token->slot, NULL, PR_TRUE);
   1.155 +	   createdSession = PR_TRUE;
   1.156 +       }
   1.157 +    }
   1.158 +    if (session == NULL) {
   1.159 +	return PR_FAILURE;
   1.160 +    }
   1.161 +    nssSession_EnterMonitor(session);
   1.162 +    ckrv = CKAPI(epv)->C_DestroyObject(session->handle, instance->handle);
   1.163 +    nssSession_ExitMonitor(session);
   1.164 +    if (createdSession) {
   1.165 +	nssSession_Destroy(session);
   1.166 +    }
   1.167 +    status = PR_SUCCESS;
   1.168 +    if (ckrv != CKR_OK) {
   1.169 +	status = PR_FAILURE;
   1.170 +	/* use the error stack to pass the PKCS #11 error out  */
   1.171 +	nss_SetError(ckrv);
   1.172 +	nss_SetError(NSS_ERROR_PKCS11);
   1.173 +    }
   1.174 +    return status;
   1.175 +}
   1.176 +
   1.177 +static nssCryptokiObject *
   1.178 +import_object (
   1.179 +  NSSToken *tok,
   1.180 +  nssSession *sessionOpt,
   1.181 +  CK_ATTRIBUTE_PTR objectTemplate,
   1.182 +  CK_ULONG otsize
   1.183 +)
   1.184 +{
   1.185 +    nssSession *session = NULL;
   1.186 +    PRBool createdSession = PR_FALSE;
   1.187 +    nssCryptokiObject *object = NULL;
   1.188 +    CK_OBJECT_HANDLE handle;
   1.189 +    CK_RV ckrv;
   1.190 +    void *epv = nssToken_GetCryptokiEPV(tok);
   1.191 +    if (nssCKObject_IsTokenObjectTemplate(objectTemplate, otsize)) {
   1.192 +	if (sessionOpt) {
   1.193 +	    if (!nssSession_IsReadWrite(sessionOpt)) {
   1.194 +		nss_SetError(NSS_ERROR_INVALID_ARGUMENT);
   1.195 +		return NULL;
   1.196 +	    }
   1.197 +	    session = sessionOpt;
   1.198 +	} else if (tok->defaultSession && 
   1.199 +	           nssSession_IsReadWrite(tok->defaultSession)) {
   1.200 +	    session = tok->defaultSession;
   1.201 +	} else {
   1.202 +	    session = nssSlot_CreateSession(tok->slot, NULL, PR_TRUE);
   1.203 +	    createdSession = PR_TRUE;
   1.204 +	}
   1.205 +    } else {
   1.206 +	session = (sessionOpt) ? sessionOpt : tok->defaultSession;
   1.207 +    }
   1.208 +    if (session == NULL) {
   1.209 +	nss_SetError(NSS_ERROR_INVALID_ARGUMENT);
   1.210 +	return NULL;
   1.211 +    }
   1.212 +    nssSession_EnterMonitor(session);
   1.213 +    ckrv = CKAPI(epv)->C_CreateObject(session->handle, 
   1.214 +                                      objectTemplate, otsize,
   1.215 +                                      &handle);
   1.216 +    nssSession_ExitMonitor(session);
   1.217 +    if (ckrv == CKR_OK) {
   1.218 +	object = nssCryptokiObject_Create(tok, session, handle);
   1.219 +    } else {
   1.220 +	nss_SetError(ckrv);
   1.221 +	nss_SetError(NSS_ERROR_PKCS11);
   1.222 +    }
   1.223 +    if (createdSession) {
   1.224 +	nssSession_Destroy(session);
   1.225 +    }
   1.226 +    return object;
   1.227 +}
   1.228 +
   1.229 +static nssCryptokiObject **
   1.230 +create_objects_from_handles (
   1.231 +  NSSToken *tok,
   1.232 +  nssSession *session,
   1.233 +  CK_OBJECT_HANDLE *handles,
   1.234 +  PRUint32 numH
   1.235 +)
   1.236 +{
   1.237 +    nssCryptokiObject **objects;
   1.238 +    objects = nss_ZNEWARRAY(NULL, nssCryptokiObject *, numH + 1);
   1.239 +    if (objects) {
   1.240 +	PRInt32 i;
   1.241 +	for (i=0; i<(PRInt32)numH; i++) {
   1.242 +	    objects[i] = nssCryptokiObject_Create(tok, session, handles[i]);
   1.243 +	    if (!objects[i]) {
   1.244 +		for (--i; i>0; --i) {
   1.245 +		    nssCryptokiObject_Destroy(objects[i]);
   1.246 +		}
   1.247 +		nss_ZFreeIf(objects);
   1.248 +		objects = NULL;
   1.249 +		break;
   1.250 +	    }
   1.251 +	}
   1.252 +    }
   1.253 +    return objects;
   1.254 +}
   1.255 +
   1.256 +static nssCryptokiObject **
   1.257 +find_objects (
   1.258 +  NSSToken *tok,
   1.259 +  nssSession *sessionOpt,
   1.260 +  CK_ATTRIBUTE_PTR obj_template,
   1.261 +  CK_ULONG otsize,
   1.262 +  PRUint32 maximumOpt,
   1.263 +  PRStatus *statusOpt
   1.264 +)
   1.265 +{
   1.266 +    CK_RV ckrv = CKR_OK;
   1.267 +    CK_ULONG count;
   1.268 +    CK_OBJECT_HANDLE *objectHandles = NULL;
   1.269 +    CK_OBJECT_HANDLE staticObjects[OBJECT_STACK_SIZE];
   1.270 +    PRUint32 arraySize, numHandles;
   1.271 +    void *epv = nssToken_GetCryptokiEPV(tok);
   1.272 +    nssCryptokiObject **objects;
   1.273 +    nssSession *session = (sessionOpt) ? sessionOpt : tok->defaultSession;
   1.274 +
   1.275 +    /* Don't ask the module to use an invalid session handle. */
   1.276 +    if (!session || session->handle == CK_INVALID_SESSION) {
   1.277 +	ckrv = CKR_SESSION_HANDLE_INVALID;
   1.278 +	goto loser;                
   1.279 +    }
   1.280 +
   1.281 +    /* the arena is only for the array of object handles */
   1.282 +    if (maximumOpt > 0) {
   1.283 +	arraySize = maximumOpt;
   1.284 +    } else {
   1.285 +	arraySize = OBJECT_STACK_SIZE;
   1.286 +    }
   1.287 +    numHandles = 0;
   1.288 +    if (arraySize <= OBJECT_STACK_SIZE) {
   1.289 +	objectHandles = staticObjects;
   1.290 +    } else {
   1.291 +	objectHandles = nss_ZNEWARRAY(NULL, CK_OBJECT_HANDLE, arraySize);
   1.292 +    }
   1.293 +    if (!objectHandles) {
   1.294 +	ckrv = CKR_HOST_MEMORY;
   1.295 +	goto loser;
   1.296 +    }
   1.297 +    nssSession_EnterMonitor(session); /* ==== session lock === */
   1.298 +    /* Initialize the find with the template */
   1.299 +    ckrv = CKAPI(epv)->C_FindObjectsInit(session->handle, 
   1.300 +                                         obj_template, otsize);
   1.301 +    if (ckrv != CKR_OK) {
   1.302 +	nssSession_ExitMonitor(session);
   1.303 +	goto loser;
   1.304 +    }
   1.305 +    while (PR_TRUE) {
   1.306 +	/* Issue the find for up to arraySize - numHandles objects */
   1.307 +	ckrv = CKAPI(epv)->C_FindObjects(session->handle, 
   1.308 +	                                 objectHandles + numHandles, 
   1.309 +	                                 arraySize - numHandles, 
   1.310 +	                                 &count);
   1.311 +	if (ckrv != CKR_OK) {
   1.312 +	    nssSession_ExitMonitor(session);
   1.313 +	    goto loser;
   1.314 +	}
   1.315 +	/* bump the number of found objects */
   1.316 +	numHandles += count;
   1.317 +	if (maximumOpt > 0 || numHandles < arraySize) {
   1.318 +	    /* When a maximum is provided, the search is done all at once,
   1.319 +	     * so the search is finished.  If the number returned was less 
   1.320 +	     * than the number sought, the search is finished.
   1.321 +	     */
   1.322 +	    break;
   1.323 +	}
   1.324 +	/* the array is filled, double it and continue */
   1.325 +	arraySize *= 2;
   1.326 +	if (objectHandles == staticObjects) {
   1.327 +	    objectHandles = nss_ZNEWARRAY(NULL,CK_OBJECT_HANDLE, arraySize);
   1.328 +	    if (objectHandles) {
   1.329 +		PORT_Memcpy(objectHandles, staticObjects, 
   1.330 +			OBJECT_STACK_SIZE * sizeof(objectHandles[1]));
   1.331 +	    }
   1.332 +	} else {
   1.333 +	    objectHandles = nss_ZREALLOCARRAY(objectHandles, 
   1.334 +	                                  CK_OBJECT_HANDLE, 
   1.335 +	                                  arraySize);
   1.336 +	}
   1.337 +	if (!objectHandles) {
   1.338 +	    nssSession_ExitMonitor(session);
   1.339 +	    ckrv = CKR_HOST_MEMORY;
   1.340 +	    goto loser;
   1.341 +	}
   1.342 +    }
   1.343 +    ckrv = CKAPI(epv)->C_FindObjectsFinal(session->handle);
   1.344 +    nssSession_ExitMonitor(session); /* ==== end session lock === */
   1.345 +    if (ckrv != CKR_OK) {
   1.346 +	goto loser;
   1.347 +    }
   1.348 +    if (numHandles > 0) {
   1.349 +	objects = create_objects_from_handles(tok, session,
   1.350 +	                                      objectHandles, numHandles);
   1.351 +    } else {
   1.352 +	nss_SetError(NSS_ERROR_NOT_FOUND);
   1.353 +	objects = NULL;
   1.354 +    }
   1.355 +    if (objectHandles && objectHandles != staticObjects) {
   1.356 +	nss_ZFreeIf(objectHandles);
   1.357 +    }
   1.358 +    if (statusOpt) *statusOpt = PR_SUCCESS;
   1.359 +    return objects;
   1.360 +loser:
   1.361 +    if (objectHandles && objectHandles != staticObjects) {
   1.362 +	nss_ZFreeIf(objectHandles);
   1.363 +    }
   1.364 +    /*
   1.365 +     * These errors should be treated the same as if the objects just weren't
   1.366 +     * found..
   1.367 +     */
   1.368 +    if ((ckrv == CKR_ATTRIBUTE_TYPE_INVALID) ||
   1.369 +	(ckrv == CKR_ATTRIBUTE_VALUE_INVALID) ||
   1.370 +	(ckrv == CKR_DATA_INVALID) ||
   1.371 +	(ckrv == CKR_DATA_LEN_RANGE) ||
   1.372 +	(ckrv == CKR_FUNCTION_NOT_SUPPORTED) ||
   1.373 +	(ckrv == CKR_TEMPLATE_INCOMPLETE) ||
   1.374 +	(ckrv == CKR_TEMPLATE_INCONSISTENT)) {
   1.375 +
   1.376 +	nss_SetError(NSS_ERROR_NOT_FOUND);
   1.377 +	if (statusOpt) *statusOpt = PR_SUCCESS;
   1.378 +    } else {
   1.379 +	nss_SetError(ckrv);
   1.380 +	nss_SetError(NSS_ERROR_PKCS11);
   1.381 +	if (statusOpt) *statusOpt = PR_FAILURE;
   1.382 +    }
   1.383 +    return (nssCryptokiObject **)NULL;
   1.384 +}
   1.385 +
   1.386 +static nssCryptokiObject **
   1.387 +find_objects_by_template (
   1.388 +  NSSToken *token,
   1.389 +  nssSession *sessionOpt,
   1.390 +  CK_ATTRIBUTE_PTR obj_template,
   1.391 +  CK_ULONG otsize,
   1.392 +  PRUint32 maximumOpt,
   1.393 +  PRStatus *statusOpt
   1.394 +)
   1.395 +{
   1.396 +    CK_OBJECT_CLASS objclass = (CK_OBJECT_CLASS)-1;
   1.397 +    nssCryptokiObject **objects = NULL;
   1.398 +    PRUint32 i;
   1.399 +
   1.400 +    if (!token) {
   1.401 +    	PORT_SetError(SEC_ERROR_NO_TOKEN);
   1.402 +	if (statusOpt) 
   1.403 +	    *statusOpt = PR_FAILURE;
   1.404 +	return NULL;
   1.405 +    }
   1.406 +    for (i=0; i<otsize; i++) {
   1.407 +	if (obj_template[i].type == CKA_CLASS) {
   1.408 +	    objclass = *(CK_OBJECT_CLASS *)obj_template[i].pValue;
   1.409 +	    break;
   1.410 +	}
   1.411 +    }
   1.412 +    PR_ASSERT(i < otsize);
   1.413 +    if (i == otsize) {
   1.414 +	PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
   1.415 +	if (statusOpt) *statusOpt = PR_FAILURE;
   1.416 +	return NULL;
   1.417 +    }
   1.418 +    /* If these objects are being cached, try looking there first */
   1.419 +    if (token->cache && 
   1.420 +        nssTokenObjectCache_HaveObjectClass(token->cache, objclass)) 
   1.421 +    {
   1.422 +	PRStatus status;
   1.423 +	objects = nssTokenObjectCache_FindObjectsByTemplate(token->cache,
   1.424 +	                                                    objclass,
   1.425 +	                                                    obj_template,
   1.426 +	                                                    otsize,
   1.427 +	                                                    maximumOpt,
   1.428 +	                                                    &status);
   1.429 +	if (status == PR_SUCCESS) {
   1.430 +	    if (statusOpt) *statusOpt = status;
   1.431 +	    return objects;
   1.432 +	}
   1.433 +    }
   1.434 +    /* Either they are not cached, or cache failed; look on token. */
   1.435 +    objects = find_objects(token, sessionOpt, 
   1.436 +                           obj_template, otsize, 
   1.437 +                           maximumOpt, statusOpt);
   1.438 +    return objects;
   1.439 +}
   1.440 +
   1.441 +extern const NSSError NSS_ERROR_INVALID_CERTIFICATE;
   1.442 +
   1.443 +NSS_IMPLEMENT nssCryptokiObject *
   1.444 +nssToken_ImportCertificate (
   1.445 +  NSSToken *tok,
   1.446 +  nssSession *sessionOpt,
   1.447 +  NSSCertificateType certType,
   1.448 +  NSSItem *id,
   1.449 +  const NSSUTF8 *nickname,
   1.450 +  NSSDER *encoding,
   1.451 +  NSSDER *issuer,
   1.452 +  NSSDER *subject,
   1.453 +  NSSDER *serial,
   1.454 +  NSSASCII7 *email,
   1.455 +  PRBool asTokenObject
   1.456 +)
   1.457 +{
   1.458 +    PRStatus status;
   1.459 +    CK_CERTIFICATE_TYPE cert_type;
   1.460 +    CK_ATTRIBUTE_PTR attr;
   1.461 +    CK_ATTRIBUTE cert_tmpl[10];
   1.462 +    CK_ULONG ctsize;
   1.463 +    nssTokenSearchType searchType;
   1.464 +    nssCryptokiObject *rvObject = NULL;
   1.465 +
   1.466 +    if (!tok) {
   1.467 +    	PORT_SetError(SEC_ERROR_NO_TOKEN);
   1.468 +	return NULL;
   1.469 +    }
   1.470 +    if (certType == NSSCertificateType_PKIX) {
   1.471 +	cert_type = CKC_X_509;
   1.472 +    } else {
   1.473 +	return (nssCryptokiObject *)NULL;
   1.474 +    }
   1.475 +    NSS_CK_TEMPLATE_START(cert_tmpl, attr, ctsize);
   1.476 +    if (asTokenObject) {
   1.477 +	NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_true);
   1.478 +	searchType = nssTokenSearchType_TokenOnly;
   1.479 +    } else {
   1.480 +	NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_false);
   1.481 +	searchType = nssTokenSearchType_SessionOnly;
   1.482 +    }
   1.483 +    NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_CLASS,            &g_ck_class_cert);
   1.484 +    NSS_CK_SET_ATTRIBUTE_VAR( attr, CKA_CERTIFICATE_TYPE,  cert_type);
   1.485 +    NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_ID,                id);
   1.486 +    NSS_CK_SET_ATTRIBUTE_UTF8(attr, CKA_LABEL,             nickname);
   1.487 +    NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_VALUE,             encoding);
   1.488 +    NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_ISSUER,            issuer);
   1.489 +    NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_SUBJECT,           subject);
   1.490 +    NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_SERIAL_NUMBER,     serial);
   1.491 +    if (email) {
   1.492 +	NSS_CK_SET_ATTRIBUTE_UTF8(attr, CKA_NSS_EMAIL,    email);
   1.493 +    }
   1.494 +    NSS_CK_TEMPLATE_FINISH(cert_tmpl, attr, ctsize);
   1.495 +    /* see if the cert is already there */
   1.496 +    rvObject = nssToken_FindCertificateByIssuerAndSerialNumber(tok,
   1.497 +                                                               sessionOpt,
   1.498 +                                                               issuer,
   1.499 +                                                               serial,
   1.500 +                                                               searchType,
   1.501 +                                                               NULL);
   1.502 +    if (rvObject) {
   1.503 +	NSSItem existingDER;
   1.504 +	NSSSlot *slot = nssToken_GetSlot(tok);
   1.505 +	nssSession *session = nssSlot_CreateSession(slot, NULL, PR_TRUE);
   1.506 +	if (!session) {
   1.507 +	    nssCryptokiObject_Destroy(rvObject);
   1.508 +	    nssSlot_Destroy(slot);
   1.509 +	    return (nssCryptokiObject *)NULL;
   1.510 +	}
   1.511 +	/* Reject any attempt to import a new cert that has the same
   1.512 +	 * issuer/serial as an existing cert, but does not have the
   1.513 +	 * same encoding
   1.514 +	 */
   1.515 +	NSS_CK_TEMPLATE_START(cert_tmpl, attr, ctsize);
   1.516 +	NSS_CK_SET_ATTRIBUTE_NULL(attr, CKA_VALUE);
   1.517 +	NSS_CK_TEMPLATE_FINISH(cert_tmpl, attr, ctsize);
   1.518 +	status = nssCKObject_GetAttributes(rvObject->handle, 
   1.519 +	                                   cert_tmpl, ctsize, NULL,
   1.520 +	                                   session, slot);
   1.521 +	NSS_CK_ATTRIBUTE_TO_ITEM(cert_tmpl, &existingDER);
   1.522 +	if (status == PR_SUCCESS) {
   1.523 +	    if (!nssItem_Equal(encoding, &existingDER, NULL)) {
   1.524 +		nss_SetError(NSS_ERROR_INVALID_CERTIFICATE);
   1.525 +		status = PR_FAILURE;
   1.526 +	    }
   1.527 +	    nss_ZFreeIf(existingDER.data);
   1.528 +	}
   1.529 +	if (status == PR_FAILURE) {
   1.530 +	    nssCryptokiObject_Destroy(rvObject);
   1.531 +	    nssSession_Destroy(session);
   1.532 +	    nssSlot_Destroy(slot);
   1.533 +	    return (nssCryptokiObject *)NULL;
   1.534 +	}
   1.535 +	/* according to PKCS#11, label, ID, issuer, and serial number 
   1.536 +	 * may change after the object has been created.  For PKIX, the
   1.537 +	 * last two attributes can't change, so for now we'll only worry
   1.538 +	 * about the first two.
   1.539 +	 */
   1.540 +	NSS_CK_TEMPLATE_START(cert_tmpl, attr, ctsize);
   1.541 +	NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_ID,    id);
   1.542 +	NSS_CK_SET_ATTRIBUTE_UTF8(attr, CKA_LABEL, nickname);
   1.543 +	NSS_CK_TEMPLATE_FINISH(cert_tmpl, attr, ctsize);
   1.544 +	/* reset the mutable attributes on the token */
   1.545 +	nssCKObject_SetAttributes(rvObject->handle, 
   1.546 +	                          cert_tmpl, ctsize,
   1.547 +	                          session, slot);
   1.548 +	if (!rvObject->label && nickname) {
   1.549 +	    rvObject->label = nssUTF8_Duplicate(nickname, NULL);
   1.550 +	}
   1.551 +	nssSession_Destroy(session);
   1.552 +	nssSlot_Destroy(slot);
   1.553 +    } else {
   1.554 +	/* Import the certificate onto the token */
   1.555 +	rvObject = import_object(tok, sessionOpt, cert_tmpl, ctsize);
   1.556 +    }
   1.557 +    if (rvObject && tok->cache) {
   1.558 +	/* The cache will overwrite the attributes if the object already
   1.559 +	 * exists.
   1.560 +	 */
   1.561 +	nssTokenObjectCache_ImportObject(tok->cache, rvObject,
   1.562 +	                                 CKO_CERTIFICATE,
   1.563 +	                                 cert_tmpl, ctsize);
   1.564 +    }
   1.565 +    return rvObject;
   1.566 +}
   1.567 +
   1.568 +/* traverse all objects of the given class - this should only happen
   1.569 + * if the token has been marked as "traversable"
   1.570 + */
   1.571 +NSS_IMPLEMENT nssCryptokiObject **
   1.572 +nssToken_FindObjects (
   1.573 +  NSSToken *token,
   1.574 +  nssSession *sessionOpt,
   1.575 +  CK_OBJECT_CLASS objclass,
   1.576 +  nssTokenSearchType searchType,
   1.577 +  PRUint32 maximumOpt,
   1.578 +  PRStatus *statusOpt
   1.579 +)
   1.580 +{
   1.581 +    CK_ATTRIBUTE_PTR attr;
   1.582 +    CK_ATTRIBUTE obj_template[2];
   1.583 +    CK_ULONG obj_size;
   1.584 +    nssCryptokiObject **objects;
   1.585 +    NSS_CK_TEMPLATE_START(obj_template, attr, obj_size);
   1.586 +    /* Set the search to token/session only if provided */
   1.587 +    if (searchType == nssTokenSearchType_SessionOnly) {
   1.588 +	NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_false);
   1.589 +    } else if (searchType == nssTokenSearchType_TokenOnly ||
   1.590 +               searchType == nssTokenSearchType_TokenForced) {
   1.591 +	NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_true);
   1.592 +    }
   1.593 +    NSS_CK_SET_ATTRIBUTE_VAR( attr, CKA_CLASS, objclass);
   1.594 +    NSS_CK_TEMPLATE_FINISH(obj_template, attr, obj_size);
   1.595 +
   1.596 +    if (searchType == nssTokenSearchType_TokenForced) {
   1.597 +	objects = find_objects(token, sessionOpt,
   1.598 +	                       obj_template, obj_size,
   1.599 +	                       maximumOpt, statusOpt);
   1.600 +    } else {
   1.601 +	objects = find_objects_by_template(token, sessionOpt,
   1.602 +	                                   obj_template, obj_size,
   1.603 +	                                   maximumOpt, statusOpt);
   1.604 +    }
   1.605 +    return objects;
   1.606 +}
   1.607 +
   1.608 +NSS_IMPLEMENT nssCryptokiObject **
   1.609 +nssToken_FindCertificatesBySubject (
   1.610 +  NSSToken *token,
   1.611 +  nssSession *sessionOpt,
   1.612 +  NSSDER *subject,
   1.613 +  nssTokenSearchType searchType,
   1.614 +  PRUint32 maximumOpt,
   1.615 +  PRStatus *statusOpt
   1.616 +)
   1.617 +{
   1.618 +    CK_ATTRIBUTE_PTR attr;
   1.619 +    CK_ATTRIBUTE subj_template[3];
   1.620 +    CK_ULONG stsize;
   1.621 +    nssCryptokiObject **objects;
   1.622 +    NSS_CK_TEMPLATE_START(subj_template, attr, stsize);
   1.623 +    /* Set the search to token/session only if provided */
   1.624 +    if (searchType == nssTokenSearchType_SessionOnly) {
   1.625 +	NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_false);
   1.626 +    } else if (searchType == nssTokenSearchType_TokenOnly) {
   1.627 +	NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_true);
   1.628 +    }
   1.629 +    NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_CLASS, &g_ck_class_cert);
   1.630 +    NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_SUBJECT, subject);
   1.631 +    NSS_CK_TEMPLATE_FINISH(subj_template, attr, stsize);
   1.632 +    /* now locate the token certs matching this template */
   1.633 +    objects = find_objects_by_template(token, sessionOpt,
   1.634 +                                       subj_template, stsize,
   1.635 +                                       maximumOpt, statusOpt);
   1.636 +    return objects;
   1.637 +}
   1.638 +
   1.639 +NSS_IMPLEMENT nssCryptokiObject **
   1.640 +nssToken_FindCertificatesByNickname (
   1.641 +  NSSToken *token,
   1.642 +  nssSession *sessionOpt,
   1.643 +  const NSSUTF8 *name,
   1.644 +  nssTokenSearchType searchType,
   1.645 +  PRUint32 maximumOpt,
   1.646 +  PRStatus *statusOpt
   1.647 +)
   1.648 +{
   1.649 +    CK_ATTRIBUTE_PTR attr;
   1.650 +    CK_ATTRIBUTE nick_template[3];
   1.651 +    CK_ULONG ntsize;
   1.652 +    nssCryptokiObject **objects;
   1.653 +    NSS_CK_TEMPLATE_START(nick_template, attr, ntsize);
   1.654 +    NSS_CK_SET_ATTRIBUTE_UTF8(attr, CKA_LABEL, name);
   1.655 +    /* Set the search to token/session only if provided */
   1.656 +    if (searchType == nssTokenSearchType_SessionOnly) {
   1.657 +	NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_false);
   1.658 +    } else if (searchType == nssTokenSearchType_TokenOnly) {
   1.659 +	NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_true);
   1.660 +    }
   1.661 +    NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_CLASS, &g_ck_class_cert);
   1.662 +    NSS_CK_TEMPLATE_FINISH(nick_template, attr, ntsize);
   1.663 +    /* now locate the token certs matching this template */
   1.664 +    objects = find_objects_by_template(token, sessionOpt,
   1.665 +                                       nick_template, ntsize, 
   1.666 +                                       maximumOpt, statusOpt);
   1.667 +    if (!objects) {
   1.668 +	/* This is to workaround the fact that PKCS#11 doesn't specify
   1.669 +	 * whether the '\0' should be included.  XXX Is that still true?
   1.670 +	 * im - this is not needed by the current softoken.  However, I'm 
   1.671 +	 * leaving it in until I have surveyed more tokens to see if it needed.
   1.672 +	 * well, its needed by the builtin token...
   1.673 +	 */
   1.674 +	nick_template[0].ulValueLen++;
   1.675 +	objects = find_objects_by_template(token, sessionOpt,
   1.676 +	                                   nick_template, ntsize, 
   1.677 +	                                   maximumOpt, statusOpt);
   1.678 +    }
   1.679 +    return objects;
   1.680 +}
   1.681 +
   1.682 +/* XXX
   1.683 + * This function *does not* use the token object cache, because not even
   1.684 + * the softoken will return a value for CKA_NSS_EMAIL from a call
   1.685 + * to GetAttributes.  The softoken does allow searches with that attribute,
   1.686 + * it just won't return a value for it.
   1.687 + */
   1.688 +NSS_IMPLEMENT nssCryptokiObject **
   1.689 +nssToken_FindCertificatesByEmail (
   1.690 +  NSSToken *token,
   1.691 +  nssSession *sessionOpt,
   1.692 +  NSSASCII7 *email,
   1.693 +  nssTokenSearchType searchType,
   1.694 +  PRUint32 maximumOpt,
   1.695 +  PRStatus *statusOpt
   1.696 +)
   1.697 +{
   1.698 +    CK_ATTRIBUTE_PTR attr;
   1.699 +    CK_ATTRIBUTE email_template[3];
   1.700 +    CK_ULONG etsize;
   1.701 +    nssCryptokiObject **objects;
   1.702 +    NSS_CK_TEMPLATE_START(email_template, attr, etsize);
   1.703 +    NSS_CK_SET_ATTRIBUTE_UTF8(attr, CKA_NSS_EMAIL, email);
   1.704 +    /* Set the search to token/session only if provided */
   1.705 +    if (searchType == nssTokenSearchType_SessionOnly) {
   1.706 +	NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_false);
   1.707 +    } else if (searchType == nssTokenSearchType_TokenOnly) {
   1.708 +	NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_true);
   1.709 +    }
   1.710 +    NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_CLASS, &g_ck_class_cert);
   1.711 +    NSS_CK_TEMPLATE_FINISH(email_template, attr, etsize);
   1.712 +    /* now locate the token certs matching this template */
   1.713 +    objects = find_objects(token, sessionOpt,
   1.714 +                           email_template, etsize,
   1.715 +                           maximumOpt, statusOpt);
   1.716 +    if (!objects) {
   1.717 +	/* This is to workaround the fact that PKCS#11 doesn't specify
   1.718 +	 * whether the '\0' should be included.  XXX Is that still true?
   1.719 +	 * im - this is not needed by the current softoken.  However, I'm 
   1.720 +	 * leaving it in until I have surveyed more tokens to see if it needed.
   1.721 +	 * well, its needed by the builtin token...
   1.722 +	 */
   1.723 +	email_template[0].ulValueLen++;
   1.724 +	objects = find_objects(token, sessionOpt,
   1.725 +	                       email_template, etsize,
   1.726 +	                       maximumOpt, statusOpt);
   1.727 +    }
   1.728 +    return objects;
   1.729 +}
   1.730 +
   1.731 +NSS_IMPLEMENT nssCryptokiObject **
   1.732 +nssToken_FindCertificatesByID (
   1.733 +  NSSToken *token,
   1.734 +  nssSession *sessionOpt,
   1.735 +  NSSItem *id,
   1.736 +  nssTokenSearchType searchType,
   1.737 +  PRUint32 maximumOpt,
   1.738 +  PRStatus *statusOpt
   1.739 +)
   1.740 +{
   1.741 +    CK_ATTRIBUTE_PTR attr;
   1.742 +    CK_ATTRIBUTE id_template[3];
   1.743 +    CK_ULONG idtsize;
   1.744 +    nssCryptokiObject **objects;
   1.745 +    NSS_CK_TEMPLATE_START(id_template, attr, idtsize);
   1.746 +    NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_ID, id);
   1.747 +    /* Set the search to token/session only if provided */
   1.748 +    if (searchType == nssTokenSearchType_SessionOnly) {
   1.749 +	NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_false);
   1.750 +    } else if (searchType == nssTokenSearchType_TokenOnly) {
   1.751 +	NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_true);
   1.752 +    }
   1.753 +    NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_CLASS, &g_ck_class_cert);
   1.754 +    NSS_CK_TEMPLATE_FINISH(id_template, attr, idtsize);
   1.755 +    /* now locate the token certs matching this template */
   1.756 +    objects = find_objects_by_template(token, sessionOpt,
   1.757 +                                       id_template, idtsize,
   1.758 +                                       maximumOpt, statusOpt);
   1.759 +    return objects;
   1.760 +}
   1.761 +
   1.762 +/*
   1.763 + * decode the serial item and return our result.
   1.764 + * NOTE serialDecode's data is really stored in serial. Don't free it.
   1.765 + */
   1.766 +static PRStatus
   1.767 +nssToken_decodeSerialItem(NSSItem *serial, NSSItem *serialDecode)
   1.768 +{
   1.769 +    unsigned char *data = (unsigned char *)serial->data;
   1.770 +    int data_left, data_len, index;
   1.771 +
   1.772 +    if ((serial->size >= 3) && (data[0] == 0x2)) {
   1.773 +	/* remove the der encoding of the serial number before generating the
   1.774 +	 * key.. */
   1.775 +	data_left = serial->size-2;
   1.776 +	data_len = data[1];
   1.777 +	index = 2;
   1.778 +
   1.779 +	/* extended length ? (not very likely for a serial number) */
   1.780 +	if (data_len & 0x80) {
   1.781 +	    int len_count = data_len & 0x7f;
   1.782 +
   1.783 +	    data_len = 0;
   1.784 +	    data_left -= len_count;
   1.785 +	    if (data_left > 0) {
   1.786 +		while (len_count --) {
   1.787 +		    data_len = (data_len << 8) | data[index++];
   1.788 +		}
   1.789 +	    } 
   1.790 +	}
   1.791 +	/* XXX leaving any leading zeros on the serial number for backwards
   1.792 +	 * compatibility
   1.793 +	 */
   1.794 +	/* not a valid der, must be just an unlucky serial number value */
   1.795 +	if (data_len == data_left) {
   1.796 +	    serialDecode->size = data_len;
   1.797 +	    serialDecode->data = &data[index];
   1.798 +	    return PR_SUCCESS;
   1.799 +	}
   1.800 +    }
   1.801 +    return PR_FAILURE;
   1.802 +}
   1.803 +
   1.804 +NSS_IMPLEMENT nssCryptokiObject *
   1.805 +nssToken_FindCertificateByIssuerAndSerialNumber (
   1.806 +  NSSToken *token,
   1.807 +  nssSession *sessionOpt,
   1.808 +  NSSDER *issuer,
   1.809 +  NSSDER *serial,
   1.810 +  nssTokenSearchType searchType,
   1.811 +  PRStatus *statusOpt
   1.812 +)
   1.813 +{
   1.814 +    CK_ATTRIBUTE_PTR attr;
   1.815 +    CK_ATTRIBUTE_PTR serialAttr;
   1.816 +    CK_ATTRIBUTE cert_template[4];
   1.817 +    CK_ULONG ctsize;
   1.818 +    nssCryptokiObject **objects;
   1.819 +    nssCryptokiObject *rvObject = NULL;
   1.820 +    NSS_CK_TEMPLATE_START(cert_template, attr, ctsize);
   1.821 +
   1.822 +    if (!token) {
   1.823 +    	PORT_SetError(SEC_ERROR_NO_TOKEN);
   1.824 +	if (statusOpt) 
   1.825 +	    *statusOpt = PR_FAILURE;
   1.826 +	return NULL;
   1.827 +    }
   1.828 +    /* Set the search to token/session only if provided */
   1.829 +    if (searchType == nssTokenSearchType_SessionOnly) {
   1.830 +	NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_false);
   1.831 +    } else if ((searchType == nssTokenSearchType_TokenOnly) ||
   1.832 +               (searchType == nssTokenSearchType_TokenForced)) {
   1.833 +	NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_true);
   1.834 +    }
   1.835 +    /* Set the unique id */
   1.836 +    NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_CLASS,         &g_ck_class_cert);
   1.837 +    NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_ISSUER,         issuer);
   1.838 +    serialAttr = attr;
   1.839 +    NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_SERIAL_NUMBER,  serial);
   1.840 +    NSS_CK_TEMPLATE_FINISH(cert_template, attr, ctsize);
   1.841 +    /* get the object handle */
   1.842 +    if (searchType == nssTokenSearchType_TokenForced) {
   1.843 +	objects = find_objects(token, sessionOpt,
   1.844 +	                       cert_template, ctsize,
   1.845 +	                       1, statusOpt);
   1.846 +    } else {
   1.847 +	objects = find_objects_by_template(token, sessionOpt,
   1.848 +                                       cert_template, ctsize,
   1.849 +                                       1, statusOpt);
   1.850 +    }
   1.851 +    if (objects) {
   1.852 +	rvObject = objects[0];
   1.853 +	nss_ZFreeIf(objects);
   1.854 +    }
   1.855 +
   1.856 +    /*
   1.857 +     * NSS used to incorrectly store serial numbers in their decoded form.
   1.858 +     * because of this old tokens have decoded serial numbers.
   1.859 +     */
   1.860 +    if (!objects) {
   1.861 +	NSSItem serialDecode;
   1.862 +	PRStatus status;
   1.863 +
   1.864 +	status = nssToken_decodeSerialItem(serial, &serialDecode);
   1.865 +	if (status != PR_SUCCESS) {
   1.866 +	    return NULL;
   1.867 +	}
   1.868 +    	NSS_CK_SET_ATTRIBUTE_ITEM(serialAttr,CKA_SERIAL_NUMBER,&serialDecode);
   1.869 +	if (searchType == nssTokenSearchType_TokenForced) {
   1.870 +	    objects = find_objects(token, sessionOpt,
   1.871 +	                       cert_template, ctsize,
   1.872 +	                       1, statusOpt);
   1.873 +	} else {
   1.874 +	    objects = find_objects_by_template(token, sessionOpt,
   1.875 +                                       cert_template, ctsize,
   1.876 +                                       1, statusOpt);
   1.877 +	}
   1.878 +	if (objects) {
   1.879 +	    rvObject = objects[0];
   1.880 +	    nss_ZFreeIf(objects);
   1.881 +	}
   1.882 +    }
   1.883 +    return rvObject;
   1.884 +}
   1.885 +
   1.886 +NSS_IMPLEMENT nssCryptokiObject *
   1.887 +nssToken_FindCertificateByEncodedCertificate (
   1.888 +  NSSToken *token,
   1.889 +  nssSession *sessionOpt,
   1.890 +  NSSBER *encodedCertificate,
   1.891 +  nssTokenSearchType searchType,
   1.892 +  PRStatus *statusOpt
   1.893 +)
   1.894 +{
   1.895 +    CK_ATTRIBUTE_PTR attr;
   1.896 +    CK_ATTRIBUTE cert_template[3];
   1.897 +    CK_ULONG ctsize;
   1.898 +    nssCryptokiObject **objects;
   1.899 +    nssCryptokiObject *rvObject = NULL;
   1.900 +    NSS_CK_TEMPLATE_START(cert_template, attr, ctsize);
   1.901 +    /* Set the search to token/session only if provided */
   1.902 +    if (searchType == nssTokenSearchType_SessionOnly) {
   1.903 +	NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_false);
   1.904 +    } else if (searchType == nssTokenSearchType_TokenOnly) {
   1.905 +	NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_true);
   1.906 +    }
   1.907 +    NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_CLASS, &g_ck_class_cert);
   1.908 +    NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_VALUE, encodedCertificate);
   1.909 +    NSS_CK_TEMPLATE_FINISH(cert_template, attr, ctsize);
   1.910 +    /* get the object handle */
   1.911 +    objects = find_objects_by_template(token, sessionOpt,
   1.912 +                                       cert_template, ctsize,
   1.913 +                                       1, statusOpt);
   1.914 +    if (objects) {
   1.915 +	rvObject = objects[0];
   1.916 +	nss_ZFreeIf(objects);
   1.917 +    }
   1.918 +    return rvObject;
   1.919 +}
   1.920 +
   1.921 +NSS_IMPLEMENT nssCryptokiObject **
   1.922 +nssToken_FindPrivateKeys (
   1.923 +  NSSToken *token,
   1.924 +  nssSession *sessionOpt,
   1.925 +  nssTokenSearchType searchType,
   1.926 +  PRUint32 maximumOpt,
   1.927 +  PRStatus *statusOpt
   1.928 +)
   1.929 +{
   1.930 +    CK_ATTRIBUTE_PTR attr;
   1.931 +    CK_ATTRIBUTE key_template[2];
   1.932 +    CK_ULONG ktsize;
   1.933 +    nssCryptokiObject **objects;
   1.934 +
   1.935 +    NSS_CK_TEMPLATE_START(key_template, attr, ktsize);
   1.936 +    NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_CLASS, &g_ck_class_privkey);
   1.937 +    if (searchType == nssTokenSearchType_SessionOnly) {
   1.938 +	NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_false);
   1.939 +    } else if (searchType == nssTokenSearchType_TokenOnly) {
   1.940 +	NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_true);
   1.941 +    }
   1.942 +    NSS_CK_TEMPLATE_FINISH(key_template, attr, ktsize);
   1.943 +
   1.944 +    objects = find_objects_by_template(token, sessionOpt,
   1.945 +                                       key_template, ktsize, 
   1.946 +                                       maximumOpt, statusOpt);
   1.947 +    return objects;
   1.948 +}
   1.949 +
   1.950 +/* XXX ?there are no session cert objects, so only search token objects */
   1.951 +NSS_IMPLEMENT nssCryptokiObject *
   1.952 +nssToken_FindPrivateKeyByID (
   1.953 +  NSSToken *token,
   1.954 +  nssSession *sessionOpt,
   1.955 +  NSSItem *keyID
   1.956 +)
   1.957 +{
   1.958 +    CK_ATTRIBUTE_PTR attr;
   1.959 +    CK_ATTRIBUTE key_template[3];
   1.960 +    CK_ULONG ktsize;
   1.961 +    nssCryptokiObject **objects;
   1.962 +    nssCryptokiObject *rvKey = NULL;
   1.963 +
   1.964 +    NSS_CK_TEMPLATE_START(key_template, attr, ktsize);
   1.965 +    NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_CLASS, &g_ck_class_privkey);
   1.966 +    NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_true);
   1.967 +    NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_ID, keyID);
   1.968 +    NSS_CK_TEMPLATE_FINISH(key_template, attr, ktsize);
   1.969 +
   1.970 +    objects = find_objects_by_template(token, sessionOpt,
   1.971 +                                       key_template, ktsize, 
   1.972 +                                       1, NULL);
   1.973 +    if (objects) {
   1.974 +	rvKey = objects[0];
   1.975 +	nss_ZFreeIf(objects);
   1.976 +    }
   1.977 +    return rvKey;
   1.978 +}
   1.979 +
   1.980 +/* XXX ?there are no session cert objects, so only search token objects */
   1.981 +NSS_IMPLEMENT nssCryptokiObject *
   1.982 +nssToken_FindPublicKeyByID (
   1.983 +  NSSToken *token,
   1.984 +  nssSession *sessionOpt,
   1.985 +  NSSItem *keyID
   1.986 +)
   1.987 +{
   1.988 +    CK_ATTRIBUTE_PTR attr;
   1.989 +    CK_ATTRIBUTE key_template[3];
   1.990 +    CK_ULONG ktsize;
   1.991 +    nssCryptokiObject **objects;
   1.992 +    nssCryptokiObject *rvKey = NULL;
   1.993 +
   1.994 +    NSS_CK_TEMPLATE_START(key_template, attr, ktsize);
   1.995 +    NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_CLASS, &g_ck_class_pubkey);
   1.996 +    NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_true);
   1.997 +    NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_ID, keyID);
   1.998 +    NSS_CK_TEMPLATE_FINISH(key_template, attr, ktsize);
   1.999 +
  1.1000 +    objects = find_objects_by_template(token, sessionOpt,
  1.1001 +                                       key_template, ktsize, 
  1.1002 +                                       1, NULL);
  1.1003 +    if (objects) {
  1.1004 +	rvKey = objects[0];
  1.1005 +	nss_ZFreeIf(objects);
  1.1006 +    }
  1.1007 +    return rvKey;
  1.1008 +}
  1.1009 +
  1.1010 +static void
  1.1011 +sha1_hash(NSSItem *input, NSSItem *output)
  1.1012 +{
  1.1013 +    NSSAlgorithmAndParameters *ap;
  1.1014 +    PK11SlotInfo *internal = PK11_GetInternalSlot();
  1.1015 +    NSSToken *token = PK11Slot_GetNSSToken(internal);
  1.1016 +    ap = NSSAlgorithmAndParameters_CreateSHA1Digest(NULL);
  1.1017 +    (void)nssToken_Digest(token, NULL, ap, input, output, NULL);
  1.1018 +    PK11_FreeSlot(token->pk11slot);
  1.1019 +    nss_ZFreeIf(ap);
  1.1020 +}
  1.1021 +
  1.1022 +static void
  1.1023 +md5_hash(NSSItem *input, NSSItem *output)
  1.1024 +{
  1.1025 +    NSSAlgorithmAndParameters *ap;
  1.1026 +    PK11SlotInfo *internal = PK11_GetInternalSlot();
  1.1027 +    NSSToken *token = PK11Slot_GetNSSToken(internal);
  1.1028 +    ap = NSSAlgorithmAndParameters_CreateMD5Digest(NULL);
  1.1029 +    (void)nssToken_Digest(token, NULL, ap, input, output, NULL);
  1.1030 +    PK11_FreeSlot(token->pk11slot);
  1.1031 +    nss_ZFreeIf(ap);
  1.1032 +}
  1.1033 +
  1.1034 +static CK_TRUST
  1.1035 +get_ck_trust (
  1.1036 +  nssTrustLevel nssTrust
  1.1037 +)
  1.1038 +{
  1.1039 +    CK_TRUST t;
  1.1040 +    switch (nssTrust) {
  1.1041 +    case nssTrustLevel_NotTrusted: t = CKT_NSS_NOT_TRUSTED; break;
  1.1042 +    case nssTrustLevel_TrustedDelegator: t = CKT_NSS_TRUSTED_DELEGATOR; 
  1.1043 +	break;
  1.1044 +    case nssTrustLevel_ValidDelegator: t = CKT_NSS_VALID_DELEGATOR; break;
  1.1045 +    case nssTrustLevel_Trusted: t = CKT_NSS_TRUSTED; break;
  1.1046 +    case nssTrustLevel_MustVerify: t = CKT_NSS_MUST_VERIFY_TRUST; break;
  1.1047 +    case nssTrustLevel_Unknown:
  1.1048 +    default: t = CKT_NSS_TRUST_UNKNOWN; break;
  1.1049 +    }
  1.1050 +    return t;
  1.1051 +}
  1.1052 + 
  1.1053 +NSS_IMPLEMENT nssCryptokiObject *
  1.1054 +nssToken_ImportTrust (
  1.1055 +  NSSToken *tok,
  1.1056 +  nssSession *sessionOpt,
  1.1057 +  NSSDER *certEncoding,
  1.1058 +  NSSDER *certIssuer,
  1.1059 +  NSSDER *certSerial,
  1.1060 +  nssTrustLevel serverAuth,
  1.1061 +  nssTrustLevel clientAuth,
  1.1062 +  nssTrustLevel codeSigning,
  1.1063 +  nssTrustLevel emailProtection,
  1.1064 +  PRBool stepUpApproved,
  1.1065 +  PRBool asTokenObject
  1.1066 +)
  1.1067 +{
  1.1068 +    nssCryptokiObject *object;
  1.1069 +    CK_OBJECT_CLASS tobjc = CKO_NSS_TRUST;
  1.1070 +    CK_TRUST ckSA, ckCA, ckCS, ckEP;
  1.1071 +    CK_ATTRIBUTE_PTR attr;
  1.1072 +    CK_ATTRIBUTE trust_tmpl[11];
  1.1073 +    CK_ULONG tsize;
  1.1074 +    PRUint8 sha1[20]; /* this is cheating... */
  1.1075 +    PRUint8 md5[16];
  1.1076 +    NSSItem sha1_result, md5_result;
  1.1077 +    sha1_result.data = sha1; sha1_result.size = sizeof sha1;
  1.1078 +    md5_result.data = md5; md5_result.size = sizeof md5;
  1.1079 +    sha1_hash(certEncoding, &sha1_result);
  1.1080 +    md5_hash(certEncoding, &md5_result);
  1.1081 +    ckSA = get_ck_trust(serverAuth);
  1.1082 +    ckCA = get_ck_trust(clientAuth);
  1.1083 +    ckCS = get_ck_trust(codeSigning);
  1.1084 +    ckEP = get_ck_trust(emailProtection);
  1.1085 +    NSS_CK_TEMPLATE_START(trust_tmpl, attr, tsize);
  1.1086 +    if (asTokenObject) {
  1.1087 +	NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_true);
  1.1088 +    } else {
  1.1089 +	NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_false);
  1.1090 +    }
  1.1091 +    NSS_CK_SET_ATTRIBUTE_VAR( attr, CKA_CLASS,           tobjc);
  1.1092 +    NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_ISSUER,          certIssuer);
  1.1093 +    NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_SERIAL_NUMBER,   certSerial);
  1.1094 +    NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_CERT_SHA1_HASH, &sha1_result);
  1.1095 +    NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_CERT_MD5_HASH,  &md5_result);
  1.1096 +    /* now set the trust values */
  1.1097 +    NSS_CK_SET_ATTRIBUTE_VAR(attr, CKA_TRUST_SERVER_AUTH,      ckSA);
  1.1098 +    NSS_CK_SET_ATTRIBUTE_VAR(attr, CKA_TRUST_CLIENT_AUTH,      ckCA);
  1.1099 +    NSS_CK_SET_ATTRIBUTE_VAR(attr, CKA_TRUST_CODE_SIGNING,     ckCS);
  1.1100 +    NSS_CK_SET_ATTRIBUTE_VAR(attr, CKA_TRUST_EMAIL_PROTECTION, ckEP);
  1.1101 +    if (stepUpApproved) {
  1.1102 +	NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TRUST_STEP_UP_APPROVED, 
  1.1103 +	                          &g_ck_true);
  1.1104 +    } else {
  1.1105 +	NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TRUST_STEP_UP_APPROVED, 
  1.1106 +	                          &g_ck_false);
  1.1107 +    }
  1.1108 +    NSS_CK_TEMPLATE_FINISH(trust_tmpl, attr, tsize);
  1.1109 +    /* import the trust object onto the token */
  1.1110 +    object = import_object(tok, sessionOpt, trust_tmpl, tsize);
  1.1111 +    if (object && tok->cache) {
  1.1112 +	nssTokenObjectCache_ImportObject(tok->cache, object, tobjc,
  1.1113 +	                                 trust_tmpl, tsize);
  1.1114 +    }
  1.1115 +    return object;
  1.1116 +}
  1.1117 +
  1.1118 +NSS_IMPLEMENT nssCryptokiObject *
  1.1119 +nssToken_FindTrustForCertificate (
  1.1120 +  NSSToken *token,
  1.1121 +  nssSession *sessionOpt,
  1.1122 +  NSSDER *certEncoding,
  1.1123 +  NSSDER *certIssuer,
  1.1124 +  NSSDER *certSerial,
  1.1125 +  nssTokenSearchType searchType
  1.1126 +)
  1.1127 +{
  1.1128 +    CK_OBJECT_CLASS tobjc = CKO_NSS_TRUST;
  1.1129 +    CK_ATTRIBUTE_PTR attr;
  1.1130 +    CK_ATTRIBUTE tobj_template[5];
  1.1131 +    CK_ULONG tobj_size;
  1.1132 +    nssSession *session = sessionOpt ? sessionOpt : token->defaultSession;
  1.1133 +    nssCryptokiObject *object = NULL, **objects;
  1.1134 +
  1.1135 +    /* Don't ask the module to use an invalid session handle. */
  1.1136 +    if (!session || session->handle == CK_INVALID_SESSION) {
  1.1137 +	PORT_SetError(SEC_ERROR_NO_TOKEN);
  1.1138 +	return object;
  1.1139 +    }
  1.1140 +
  1.1141 +    NSS_CK_TEMPLATE_START(tobj_template, attr, tobj_size);
  1.1142 +    if (searchType == nssTokenSearchType_TokenOnly) {
  1.1143 +	NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_true);
  1.1144 +    }
  1.1145 +    NSS_CK_SET_ATTRIBUTE_VAR( attr, CKA_CLASS,          tobjc);
  1.1146 +    NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_ISSUER,         certIssuer);
  1.1147 +    NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_SERIAL_NUMBER , certSerial);
  1.1148 +    NSS_CK_TEMPLATE_FINISH(tobj_template, attr, tobj_size);
  1.1149 +    objects = find_objects_by_template(token, session,
  1.1150 +                                       tobj_template, tobj_size,
  1.1151 +                                       1, NULL);
  1.1152 +    if (objects) {
  1.1153 +	object = objects[0];
  1.1154 +	nss_ZFreeIf(objects);
  1.1155 +    }
  1.1156 +    return object;
  1.1157 +}
  1.1158 + 
  1.1159 +NSS_IMPLEMENT nssCryptokiObject *
  1.1160 +nssToken_ImportCRL (
  1.1161 +  NSSToken *token,
  1.1162 +  nssSession *sessionOpt,
  1.1163 +  NSSDER *subject,
  1.1164 +  NSSDER *encoding,
  1.1165 +  PRBool isKRL,
  1.1166 +  NSSUTF8 *url,
  1.1167 +  PRBool asTokenObject
  1.1168 +)
  1.1169 +{
  1.1170 +    nssCryptokiObject *object;
  1.1171 +    CK_OBJECT_CLASS crlobjc = CKO_NSS_CRL;
  1.1172 +    CK_ATTRIBUTE_PTR attr;
  1.1173 +    CK_ATTRIBUTE crl_tmpl[6];
  1.1174 +    CK_ULONG crlsize;
  1.1175 +
  1.1176 +    NSS_CK_TEMPLATE_START(crl_tmpl, attr, crlsize);
  1.1177 +    if (asTokenObject) {
  1.1178 +	NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_true);
  1.1179 +    } else {
  1.1180 +	NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_false);
  1.1181 +    }
  1.1182 +    NSS_CK_SET_ATTRIBUTE_VAR( attr, CKA_CLASS,        crlobjc);
  1.1183 +    NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_SUBJECT,      subject);
  1.1184 +    NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_VALUE,        encoding);
  1.1185 +    NSS_CK_SET_ATTRIBUTE_UTF8(attr, CKA_NSS_URL, url);
  1.1186 +    if (isKRL) {
  1.1187 +	NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_NSS_KRL, &g_ck_true);
  1.1188 +    } else {
  1.1189 +	NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_NSS_KRL, &g_ck_false);
  1.1190 +    }
  1.1191 +    NSS_CK_TEMPLATE_FINISH(crl_tmpl, attr, crlsize);
  1.1192 +
  1.1193 +    /* import the crl object onto the token */
  1.1194 +    object = import_object(token, sessionOpt, crl_tmpl, crlsize);
  1.1195 +    if (object && token->cache) {
  1.1196 +	nssTokenObjectCache_ImportObject(token->cache, object, crlobjc,
  1.1197 +	                                 crl_tmpl, crlsize);
  1.1198 +    }
  1.1199 +    return object;
  1.1200 +}
  1.1201 +
  1.1202 +NSS_IMPLEMENT nssCryptokiObject **
  1.1203 +nssToken_FindCRLsBySubject (
  1.1204 +  NSSToken *token,
  1.1205 +  nssSession *sessionOpt,
  1.1206 +  NSSDER *subject,
  1.1207 +  nssTokenSearchType searchType,
  1.1208 +  PRUint32 maximumOpt,
  1.1209 +  PRStatus *statusOpt
  1.1210 +)
  1.1211 +{
  1.1212 +    CK_OBJECT_CLASS crlobjc = CKO_NSS_CRL;
  1.1213 +    CK_ATTRIBUTE_PTR attr;
  1.1214 +    CK_ATTRIBUTE crlobj_template[3];
  1.1215 +    CK_ULONG crlobj_size;
  1.1216 +    nssCryptokiObject **objects = NULL;
  1.1217 +    nssSession *session = sessionOpt ? sessionOpt : token->defaultSession;
  1.1218 +
  1.1219 +    /* Don't ask the module to use an invalid session handle. */
  1.1220 +    if (!session || session->handle == CK_INVALID_SESSION) {
  1.1221 +	PORT_SetError(SEC_ERROR_NO_TOKEN);
  1.1222 +	return objects;
  1.1223 +    }
  1.1224 +
  1.1225 +    NSS_CK_TEMPLATE_START(crlobj_template, attr, crlobj_size);
  1.1226 +    if (searchType == nssTokenSearchType_SessionOnly) {
  1.1227 +	NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_false);
  1.1228 +    } else if (searchType == nssTokenSearchType_TokenOnly ||
  1.1229 +               searchType == nssTokenSearchType_TokenForced) {
  1.1230 +	NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_true);
  1.1231 +    }
  1.1232 +    NSS_CK_SET_ATTRIBUTE_VAR( attr, CKA_CLASS, crlobjc);
  1.1233 +    NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_SUBJECT, subject);
  1.1234 +    NSS_CK_TEMPLATE_FINISH(crlobj_template, attr, crlobj_size);
  1.1235 +
  1.1236 +    objects = find_objects_by_template(token, session,
  1.1237 +                                       crlobj_template, crlobj_size,
  1.1238 +                                       maximumOpt, statusOpt);
  1.1239 +    return objects;
  1.1240 +}
  1.1241 +
  1.1242 +NSS_IMPLEMENT PRStatus
  1.1243 +nssToken_GetCachedObjectAttributes (
  1.1244 +  NSSToken *token,
  1.1245 +  NSSArena *arenaOpt,
  1.1246 +  nssCryptokiObject *object,
  1.1247 +  CK_OBJECT_CLASS objclass,
  1.1248 +  CK_ATTRIBUTE_PTR atemplate,
  1.1249 +  CK_ULONG atlen
  1.1250 +)
  1.1251 +{
  1.1252 +    if (!token->cache) {
  1.1253 +	return PR_FAILURE;
  1.1254 +    }
  1.1255 +    return nssTokenObjectCache_GetObjectAttributes(token->cache, arenaOpt,
  1.1256 +                                                   object, objclass,
  1.1257 +                                                   atemplate, atlen);
  1.1258 +}
  1.1259 +
  1.1260 +NSS_IMPLEMENT NSSItem *
  1.1261 +nssToken_Digest (
  1.1262 +  NSSToken *tok,
  1.1263 +  nssSession *sessionOpt,
  1.1264 +  NSSAlgorithmAndParameters *ap,
  1.1265 +  NSSItem *data,
  1.1266 +  NSSItem *rvOpt,
  1.1267 +  NSSArena *arenaOpt
  1.1268 +)
  1.1269 +{
  1.1270 +    CK_RV ckrv;
  1.1271 +    CK_ULONG digestLen;
  1.1272 +    CK_BYTE_PTR digest;
  1.1273 +    NSSItem *rvItem = NULL;
  1.1274 +    void *epv = nssToken_GetCryptokiEPV(tok);
  1.1275 +    nssSession *session = (sessionOpt) ? sessionOpt : tok->defaultSession;
  1.1276 +
  1.1277 +    /* Don't ask the module to use an invalid session handle. */
  1.1278 +    if (!session || session->handle == CK_INVALID_SESSION) {
  1.1279 +	PORT_SetError(SEC_ERROR_NO_TOKEN);
  1.1280 +	return rvItem;
  1.1281 +    }
  1.1282 +
  1.1283 +    nssSession_EnterMonitor(session);
  1.1284 +    ckrv = CKAPI(epv)->C_DigestInit(session->handle, &ap->mechanism);
  1.1285 +    if (ckrv != CKR_OK) {
  1.1286 +	nssSession_ExitMonitor(session);
  1.1287 +	return NULL;
  1.1288 +    }
  1.1289 +#if 0
  1.1290 +    /* XXX the standard says this should work, but it doesn't */
  1.1291 +    ckrv = CKAPI(epv)->C_Digest(session->handle, NULL, 0, NULL, &digestLen);
  1.1292 +    if (ckrv != CKR_OK) {
  1.1293 +	nssSession_ExitMonitor(session);
  1.1294 +	return NULL;
  1.1295 +    }
  1.1296 +#endif
  1.1297 +    digestLen = 0; /* XXX for now */
  1.1298 +    digest = NULL;
  1.1299 +    if (rvOpt) {
  1.1300 +	if (rvOpt->size > 0 && rvOpt->size < digestLen) {
  1.1301 +	    nssSession_ExitMonitor(session);
  1.1302 +	    /* the error should be bad args */
  1.1303 +	    return NULL;
  1.1304 +	}
  1.1305 +	if (rvOpt->data) {
  1.1306 +	    digest = rvOpt->data;
  1.1307 +	}
  1.1308 +	digestLen = rvOpt->size;
  1.1309 +    }
  1.1310 +    if (!digest) {
  1.1311 +	digest = (CK_BYTE_PTR)nss_ZAlloc(arenaOpt, digestLen);
  1.1312 +	if (!digest) {
  1.1313 +	    nssSession_ExitMonitor(session);
  1.1314 +	    return NULL;
  1.1315 +	}
  1.1316 +    }
  1.1317 +    ckrv = CKAPI(epv)->C_Digest(session->handle, 
  1.1318 +                                (CK_BYTE_PTR)data->data, 
  1.1319 +                                (CK_ULONG)data->size,
  1.1320 +                                (CK_BYTE_PTR)digest,
  1.1321 +                                &digestLen);
  1.1322 +    nssSession_ExitMonitor(session);
  1.1323 +    if (ckrv != CKR_OK) {
  1.1324 +	nss_ZFreeIf(digest);
  1.1325 +	return NULL;
  1.1326 +    }
  1.1327 +    if (!rvOpt) {
  1.1328 +	rvItem = nssItem_Create(arenaOpt, NULL, digestLen, (void *)digest);
  1.1329 +    }
  1.1330 +    return rvItem;
  1.1331 +}
  1.1332 +
  1.1333 +NSS_IMPLEMENT PRStatus
  1.1334 +nssToken_BeginDigest (
  1.1335 +  NSSToken *tok,
  1.1336 +  nssSession *sessionOpt,
  1.1337 +  NSSAlgorithmAndParameters *ap
  1.1338 +)
  1.1339 +{
  1.1340 +    CK_RV ckrv;
  1.1341 +    void *epv = nssToken_GetCryptokiEPV(tok);
  1.1342 +    nssSession *session = (sessionOpt) ? sessionOpt : tok->defaultSession;
  1.1343 +
  1.1344 +    /* Don't ask the module to use an invalid session handle. */
  1.1345 +    if (!session || session->handle == CK_INVALID_SESSION) {
  1.1346 +	PORT_SetError(SEC_ERROR_NO_TOKEN);
  1.1347 +	return PR_FAILURE;
  1.1348 +    }
  1.1349 +
  1.1350 +    nssSession_EnterMonitor(session);
  1.1351 +    ckrv = CKAPI(epv)->C_DigestInit(session->handle, &ap->mechanism);
  1.1352 +    nssSession_ExitMonitor(session);
  1.1353 +    return (ckrv == CKR_OK) ? PR_SUCCESS : PR_FAILURE;
  1.1354 +}
  1.1355 +
  1.1356 +NSS_IMPLEMENT PRStatus
  1.1357 +nssToken_ContinueDigest (
  1.1358 +  NSSToken *tok,
  1.1359 +  nssSession *sessionOpt,
  1.1360 +  NSSItem *item
  1.1361 +)
  1.1362 +{
  1.1363 +    CK_RV ckrv;
  1.1364 +    void *epv = nssToken_GetCryptokiEPV(tok);
  1.1365 +    nssSession *session = (sessionOpt) ? sessionOpt : tok->defaultSession;
  1.1366 +
  1.1367 +    /* Don't ask the module to use an invalid session handle. */
  1.1368 +    if (!session || session->handle == CK_INVALID_SESSION) {
  1.1369 +	PORT_SetError(SEC_ERROR_NO_TOKEN);
  1.1370 +	return PR_FAILURE;
  1.1371 +    }
  1.1372 +
  1.1373 +    nssSession_EnterMonitor(session);
  1.1374 +    ckrv = CKAPI(epv)->C_DigestUpdate(session->handle, 
  1.1375 +                                      (CK_BYTE_PTR)item->data, 
  1.1376 +                                      (CK_ULONG)item->size);
  1.1377 +    nssSession_ExitMonitor(session);
  1.1378 +    return (ckrv == CKR_OK) ? PR_SUCCESS : PR_FAILURE;
  1.1379 +}
  1.1380 +
  1.1381 +NSS_IMPLEMENT NSSItem *
  1.1382 +nssToken_FinishDigest (
  1.1383 +  NSSToken *tok,
  1.1384 +  nssSession *sessionOpt,
  1.1385 +  NSSItem *rvOpt,
  1.1386 +  NSSArena *arenaOpt
  1.1387 +)
  1.1388 +{
  1.1389 +    CK_RV ckrv;
  1.1390 +    CK_ULONG digestLen;
  1.1391 +    CK_BYTE_PTR digest;
  1.1392 +    NSSItem *rvItem = NULL;
  1.1393 +    void *epv = nssToken_GetCryptokiEPV(tok);
  1.1394 +    nssSession *session = (sessionOpt) ? sessionOpt : tok->defaultSession;
  1.1395 +
  1.1396 +    /* Don't ask the module to use an invalid session handle. */
  1.1397 +    if (!session || session->handle == CK_INVALID_SESSION) {
  1.1398 +	PORT_SetError(SEC_ERROR_NO_TOKEN);
  1.1399 +	return NULL;
  1.1400 +    }
  1.1401 +
  1.1402 +    nssSession_EnterMonitor(session);
  1.1403 +    ckrv = CKAPI(epv)->C_DigestFinal(session->handle, NULL, &digestLen);
  1.1404 +    if (ckrv != CKR_OK || digestLen == 0) {
  1.1405 +	nssSession_ExitMonitor(session);
  1.1406 +	return NULL;
  1.1407 +    }
  1.1408 +    digest = NULL;
  1.1409 +    if (rvOpt) {
  1.1410 +	if (rvOpt->size > 0 && rvOpt->size < digestLen) {
  1.1411 +	    nssSession_ExitMonitor(session);
  1.1412 +	    /* the error should be bad args */
  1.1413 +	    return NULL;
  1.1414 +	}
  1.1415 +	if (rvOpt->data) {
  1.1416 +	    digest = rvOpt->data;
  1.1417 +	}
  1.1418 +	digestLen = rvOpt->size;
  1.1419 +    }
  1.1420 +    if (!digest) {
  1.1421 +	digest = (CK_BYTE_PTR)nss_ZAlloc(arenaOpt, digestLen);
  1.1422 +	if (!digest) {
  1.1423 +	    nssSession_ExitMonitor(session);
  1.1424 +	    return NULL;
  1.1425 +	}
  1.1426 +    }
  1.1427 +    ckrv = CKAPI(epv)->C_DigestFinal(session->handle, digest, &digestLen);
  1.1428 +    nssSession_ExitMonitor(session);
  1.1429 +    if (ckrv != CKR_OK) {
  1.1430 +	nss_ZFreeIf(digest);
  1.1431 +	return NULL;
  1.1432 +    }
  1.1433 +    if (!rvOpt) {
  1.1434 +	rvItem = nssItem_Create(arenaOpt, NULL, digestLen, (void *)digest);
  1.1435 +    }
  1.1436 +    return rvItem;
  1.1437 +}
  1.1438 +
  1.1439 +NSS_IMPLEMENT PRBool
  1.1440 +nssToken_IsPresent (
  1.1441 +  NSSToken *token
  1.1442 +)
  1.1443 +{
  1.1444 +    return nssSlot_IsTokenPresent(token->slot);
  1.1445 +}
  1.1446 +
  1.1447 +/* Sigh.  The methods to find objects declared above cause problems with
  1.1448 + * the low-level object cache in the softoken -- the objects are found in 
  1.1449 + * toto, then one wave of GetAttributes is done, then another.  Having a 
  1.1450 + * large number of objects causes the cache to be thrashed, as the objects 
  1.1451 + * are gone before there's any chance to ask for their attributes.
  1.1452 + * So, for now, bringing back traversal methods for certs.  This way all of 
  1.1453 + * the cert's attributes can be grabbed immediately after finding it,
  1.1454 + * increasing the likelihood that the cache takes care of it.
  1.1455 + */
  1.1456 +NSS_IMPLEMENT PRStatus
  1.1457 +nssToken_TraverseCertificates (
  1.1458 +  NSSToken *token,
  1.1459 +  nssSession *sessionOpt,
  1.1460 +  nssTokenSearchType searchType,
  1.1461 +  PRStatus (* callback)(nssCryptokiObject *instance, void *arg),
  1.1462 +  void *arg
  1.1463 +)
  1.1464 +{
  1.1465 +    CK_RV ckrv;
  1.1466 +    CK_ULONG count;
  1.1467 +    CK_OBJECT_HANDLE *objectHandles;
  1.1468 +    CK_ATTRIBUTE_PTR attr;
  1.1469 +    CK_ATTRIBUTE cert_template[2];
  1.1470 +    CK_ULONG ctsize;
  1.1471 +    NSSArena *arena;
  1.1472 +    PRStatus status;
  1.1473 +    PRUint32 arraySize, numHandles;
  1.1474 +    nssCryptokiObject **objects;
  1.1475 +    void *epv = nssToken_GetCryptokiEPV(token);
  1.1476 +    nssSession *session = (sessionOpt) ? sessionOpt : token->defaultSession;
  1.1477 +
  1.1478 +    /* Don't ask the module to use an invalid session handle. */
  1.1479 +    if (!session || session->handle == CK_INVALID_SESSION) {
  1.1480 +	PORT_SetError(SEC_ERROR_NO_TOKEN);
  1.1481 +	return PR_FAILURE;
  1.1482 +    }
  1.1483 +
  1.1484 +    /* template for all certs */
  1.1485 +    NSS_CK_TEMPLATE_START(cert_template, attr, ctsize);
  1.1486 +    if (searchType == nssTokenSearchType_SessionOnly) {
  1.1487 +	NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_false);
  1.1488 +    } else if (searchType == nssTokenSearchType_TokenOnly ||
  1.1489 +               searchType == nssTokenSearchType_TokenForced) {
  1.1490 +	NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_true);
  1.1491 +    }
  1.1492 +    NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_CLASS, &g_ck_class_cert);
  1.1493 +    NSS_CK_TEMPLATE_FINISH(cert_template, attr, ctsize);
  1.1494 +
  1.1495 +    /* the arena is only for the array of object handles */
  1.1496 +    arena = nssArena_Create();
  1.1497 +    if (!arena) {
  1.1498 +	return PR_FAILURE;
  1.1499 +    }
  1.1500 +    arraySize = OBJECT_STACK_SIZE;
  1.1501 +    numHandles = 0;
  1.1502 +    objectHandles = nss_ZNEWARRAY(arena, CK_OBJECT_HANDLE, arraySize);
  1.1503 +    if (!objectHandles) {
  1.1504 +	goto loser;
  1.1505 +    }
  1.1506 +    nssSession_EnterMonitor(session); /* ==== session lock === */
  1.1507 +    /* Initialize the find with the template */
  1.1508 +    ckrv = CKAPI(epv)->C_FindObjectsInit(session->handle, 
  1.1509 +                                         cert_template, ctsize);
  1.1510 +    if (ckrv != CKR_OK) {
  1.1511 +	nssSession_ExitMonitor(session);
  1.1512 +	goto loser;
  1.1513 +    }
  1.1514 +    while (PR_TRUE) {
  1.1515 +	/* Issue the find for up to arraySize - numHandles objects */
  1.1516 +	ckrv = CKAPI(epv)->C_FindObjects(session->handle, 
  1.1517 +	                                 objectHandles + numHandles, 
  1.1518 +	                                 arraySize - numHandles, 
  1.1519 +	                                 &count);
  1.1520 +	if (ckrv != CKR_OK) {
  1.1521 +	    nssSession_ExitMonitor(session);
  1.1522 +	    goto loser;
  1.1523 +	}
  1.1524 +	/* bump the number of found objects */
  1.1525 +	numHandles += count;
  1.1526 +	if (numHandles < arraySize) {
  1.1527 +	    break;
  1.1528 +	}
  1.1529 +	/* the array is filled, double it and continue */
  1.1530 +	arraySize *= 2;
  1.1531 +	objectHandles = nss_ZREALLOCARRAY(objectHandles, 
  1.1532 +	                                  CK_OBJECT_HANDLE, 
  1.1533 +	                                  arraySize);
  1.1534 +	if (!objectHandles) {
  1.1535 +	    nssSession_ExitMonitor(session);
  1.1536 +	    goto loser;
  1.1537 +	}
  1.1538 +    }
  1.1539 +    ckrv = CKAPI(epv)->C_FindObjectsFinal(session->handle);
  1.1540 +    nssSession_ExitMonitor(session); /* ==== end session lock === */
  1.1541 +    if (ckrv != CKR_OK) {
  1.1542 +	goto loser;
  1.1543 +    }
  1.1544 +    if (numHandles > 0) {
  1.1545 +	objects = create_objects_from_handles(token, session,
  1.1546 +	                                      objectHandles, numHandles);
  1.1547 +	if (objects) {
  1.1548 +	    nssCryptokiObject **op;
  1.1549 +	    for (op = objects; *op; op++) {
  1.1550 +		status = (*callback)(*op, arg);
  1.1551 +	    }
  1.1552 +	    nss_ZFreeIf(objects);
  1.1553 +	}
  1.1554 +    }
  1.1555 +    nssArena_Destroy(arena);
  1.1556 +    return PR_SUCCESS;
  1.1557 +loser:
  1.1558 +    nssArena_Destroy(arena);
  1.1559 +    return PR_FAILURE;
  1.1560 +}
  1.1561 +
  1.1562 +NSS_IMPLEMENT PRBool
  1.1563 +nssToken_IsPrivateKeyAvailable (
  1.1564 +  NSSToken *token,
  1.1565 +  NSSCertificate *c,
  1.1566 +  nssCryptokiObject *instance
  1.1567 +)
  1.1568 +{
  1.1569 +    CK_OBJECT_CLASS theClass;
  1.1570 +
  1.1571 +    if (token == NULL) return PR_FALSE;
  1.1572 +    if (c == NULL) return PR_FALSE;
  1.1573 +
  1.1574 +    theClass = CKO_PRIVATE_KEY;
  1.1575 +    if (!nssSlot_IsLoggedIn(token->slot)) {
  1.1576 +	theClass = CKO_PUBLIC_KEY;
  1.1577 +    }
  1.1578 +    if (PK11_MatchItem(token->pk11slot, instance->handle, theClass) 
  1.1579 +						!= CK_INVALID_HANDLE) {
  1.1580 +	return PR_TRUE;
  1.1581 +    }
  1.1582 +    return PR_FALSE;
  1.1583 +}

mercurial