PageRenderTime 97ms CodeModel.GetById 13ms app.highlight 74ms RepoModel.GetById 1ms app.codeStats 0ms

/security/nss/lib/dev/devtoken.c

http://github.com/zpao/v8monkey
C | 1616 lines | 1376 code | 89 blank | 151 comment | 279 complexity | 04adeedaeac06c307438fecc2eac89db MD5 | raw file

Large files files are truncated, but you can click here to view the full file

   1/* ***** BEGIN LICENSE BLOCK *****
   2 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
   3 *
   4 * The contents of this file are subject to the Mozilla Public License Version
   5 * 1.1 (the "License"); you may not use this file except in compliance with
   6 * the License. You may obtain a copy of the License at
   7 * http://www.mozilla.org/MPL/
   8 *
   9 * Software distributed under the License is distributed on an "AS IS" basis,
  10 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  11 * for the specific language governing rights and limitations under the
  12 * License.
  13 *
  14 * The Original Code is the Netscape security libraries.
  15 *
  16 * The Initial Developer of the Original Code is
  17 * Netscape Communications Corporation.
  18 * Portions created by the Initial Developer are Copyright (C) 1994-2000
  19 * the Initial Developer. All Rights Reserved.
  20 *
  21 * Contributor(s):
  22 *
  23 * Alternatively, the contents of this file may be used under the terms of
  24 * either the GNU General Public License Version 2 or later (the "GPL"), or
  25 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  26 * in which case the provisions of the GPL or the LGPL are applicable instead
  27 * of those above. If you wish to allow use of your version of this file only
  28 * under the terms of either the GPL or the LGPL, and not to allow others to
  29 * use your version of this file under the terms of the MPL, indicate your
  30 * decision by deleting the provisions above and replace them with the notice
  31 * and other provisions required by the GPL or the LGPL. If you do not delete
  32 * the provisions above, a recipient may use your version of this file under
  33 * the terms of any one of the MPL, the GPL or the LGPL.
  34 *
  35 * ***** END LICENSE BLOCK ***** */
  36
  37#ifdef DEBUG
  38static const char CVS_ID[] = "@(#) $RCSfile: devtoken.c,v $ $Revision: 1.56 $ $Date: 2011/07/12 21:29:20 $";
  39#endif /* DEBUG */
  40
  41#include "pkcs11.h"
  42
  43#ifndef DEVM_H
  44#include "devm.h"
  45#endif /* DEVM_H */
  46
  47#ifndef CKHELPER_H
  48#include "ckhelper.h"
  49#endif /* CKHELPER_H */
  50
  51#include "pk11func.h"
  52#include "dev3hack.h"
  53#include "secerr.h"
  54
  55extern const NSSError NSS_ERROR_NOT_FOUND;
  56extern const NSSError NSS_ERROR_INVALID_ARGUMENT;
  57extern const NSSError NSS_ERROR_PKCS11;
  58
  59/* The number of object handles to grab during each call to C_FindObjects */
  60#define OBJECT_STACK_SIZE 16
  61
  62NSS_IMPLEMENT PRStatus
  63nssToken_Destroy (
  64  NSSToken *tok
  65)
  66{
  67    if (tok) {
  68	if (PR_ATOMIC_DECREMENT(&tok->base.refCount) == 0) {
  69	    PZ_DestroyLock(tok->base.lock);
  70	    nssTokenObjectCache_Destroy(tok->cache);
  71	    /* The token holds the first/last reference to the slot.
  72	     * When the token is actually destroyed, that ref must go too.
  73	     */
  74	    (void)nssSlot_Destroy(tok->slot);
  75	    return nssArena_Destroy(tok->base.arena);
  76	}
  77    }
  78    return PR_SUCCESS;
  79}
  80
  81NSS_IMPLEMENT void
  82nssToken_Remove (
  83  NSSToken *tok
  84)
  85{
  86    nssTokenObjectCache_Clear(tok->cache);
  87}
  88
  89NSS_IMPLEMENT void
  90NSSToken_Destroy (
  91  NSSToken *tok
  92)
  93{
  94    (void)nssToken_Destroy(tok);
  95}
  96
  97NSS_IMPLEMENT NSSToken *
  98nssToken_AddRef (
  99  NSSToken *tok
 100)
 101{
 102    PR_ATOMIC_INCREMENT(&tok->base.refCount);
 103    return tok;
 104}
 105
 106NSS_IMPLEMENT NSSSlot *
 107nssToken_GetSlot (
 108  NSSToken *tok
 109)
 110{
 111    return nssSlot_AddRef(tok->slot);
 112}
 113
 114NSS_IMPLEMENT void *
 115nssToken_GetCryptokiEPV (
 116  NSSToken *token
 117)
 118{
 119    return nssSlot_GetCryptokiEPV(token->slot);
 120}
 121
 122NSS_IMPLEMENT nssSession *
 123nssToken_GetDefaultSession (
 124  NSSToken *token
 125)
 126{
 127    return token->defaultSession;
 128}
 129
 130NSS_IMPLEMENT NSSUTF8 *
 131nssToken_GetName (
 132  NSSToken *tok
 133)
 134{
 135    if (tok == NULL) {
 136	return "";
 137    }
 138    if (tok->base.name[0] == 0) {
 139	(void) nssSlot_IsTokenPresent(tok->slot);
 140    } 
 141    return tok->base.name;
 142}
 143
 144NSS_IMPLEMENT NSSUTF8 *
 145NSSToken_GetName (
 146  NSSToken *token
 147)
 148{
 149    return nssToken_GetName(token);
 150}
 151
 152NSS_IMPLEMENT PRBool
 153nssToken_IsLoginRequired (
 154  NSSToken *token
 155)
 156{
 157    return (token->ckFlags & CKF_LOGIN_REQUIRED);
 158}
 159
 160NSS_IMPLEMENT PRBool
 161nssToken_NeedsPINInitialization (
 162  NSSToken *token
 163)
 164{
 165    return (!(token->ckFlags & CKF_USER_PIN_INITIALIZED));
 166}
 167
 168NSS_IMPLEMENT PRStatus
 169nssToken_DeleteStoredObject (
 170  nssCryptokiObject *instance
 171)
 172{
 173    CK_RV ckrv;
 174    PRStatus status;
 175    PRBool createdSession = PR_FALSE;
 176    NSSToken *token = instance->token;
 177    nssSession *session = NULL;
 178    void *epv = nssToken_GetCryptokiEPV(instance->token);
 179    if (token->cache) {
 180	nssTokenObjectCache_RemoveObject(token->cache, instance);
 181    }
 182    if (instance->isTokenObject) {
 183       if (token->defaultSession && 
 184           nssSession_IsReadWrite(token->defaultSession)) {
 185	   session = token->defaultSession;
 186       } else {
 187	   session = nssSlot_CreateSession(token->slot, NULL, PR_TRUE);
 188	   createdSession = PR_TRUE;
 189       }
 190    }
 191    if (session == NULL) {
 192	return PR_FAILURE;
 193    }
 194    nssSession_EnterMonitor(session);
 195    ckrv = CKAPI(epv)->C_DestroyObject(session->handle, instance->handle);
 196    nssSession_ExitMonitor(session);
 197    if (createdSession) {
 198	nssSession_Destroy(session);
 199    }
 200    status = PR_SUCCESS;
 201    if (ckrv != CKR_OK) {
 202	status = PR_FAILURE;
 203	/* use the error stack to pass the PKCS #11 error out  */
 204	nss_SetError(ckrv);
 205	nss_SetError(NSS_ERROR_PKCS11);
 206    }
 207    return status;
 208}
 209
 210static nssCryptokiObject *
 211import_object (
 212  NSSToken *tok,
 213  nssSession *sessionOpt,
 214  CK_ATTRIBUTE_PTR objectTemplate,
 215  CK_ULONG otsize
 216)
 217{
 218    nssSession *session = NULL;
 219    PRBool createdSession = PR_FALSE;
 220    nssCryptokiObject *object = NULL;
 221    CK_OBJECT_HANDLE handle;
 222    CK_RV ckrv;
 223    void *epv = nssToken_GetCryptokiEPV(tok);
 224    if (nssCKObject_IsTokenObjectTemplate(objectTemplate, otsize)) {
 225	if (sessionOpt) {
 226	    if (!nssSession_IsReadWrite(sessionOpt)) {
 227		nss_SetError(NSS_ERROR_INVALID_ARGUMENT);
 228		return NULL;
 229	    }
 230	    session = sessionOpt;
 231	} else if (tok->defaultSession && 
 232	           nssSession_IsReadWrite(tok->defaultSession)) {
 233	    session = tok->defaultSession;
 234	} else {
 235	    session = nssSlot_CreateSession(tok->slot, NULL, PR_TRUE);
 236	    createdSession = PR_TRUE;
 237	}
 238    } else {
 239	session = (sessionOpt) ? sessionOpt : tok->defaultSession;
 240    }
 241    if (session == NULL) {
 242	nss_SetError(NSS_ERROR_INVALID_ARGUMENT);
 243	return NULL;
 244    }
 245    nssSession_EnterMonitor(session);
 246    ckrv = CKAPI(epv)->C_CreateObject(session->handle, 
 247                                      objectTemplate, otsize,
 248                                      &handle);
 249    nssSession_ExitMonitor(session);
 250    if (ckrv == CKR_OK) {
 251	object = nssCryptokiObject_Create(tok, session, handle);
 252    } else {
 253	nss_SetError(ckrv);
 254	nss_SetError(NSS_ERROR_PKCS11);
 255    }
 256    if (createdSession) {
 257	nssSession_Destroy(session);
 258    }
 259    return object;
 260}
 261
 262static nssCryptokiObject **
 263create_objects_from_handles (
 264  NSSToken *tok,
 265  nssSession *session,
 266  CK_OBJECT_HANDLE *handles,
 267  PRUint32 numH
 268)
 269{
 270    nssCryptokiObject **objects;
 271    objects = nss_ZNEWARRAY(NULL, nssCryptokiObject *, numH + 1);
 272    if (objects) {
 273	PRInt32 i;
 274	for (i=0; i<(PRInt32)numH; i++) {
 275	    objects[i] = nssCryptokiObject_Create(tok, session, handles[i]);
 276	    if (!objects[i]) {
 277		for (--i; i>0; --i) {
 278		    nssCryptokiObject_Destroy(objects[i]);
 279		}
 280		nss_ZFreeIf(objects);
 281		objects = NULL;
 282		break;
 283	    }
 284	}
 285    }
 286    return objects;
 287}
 288
 289static nssCryptokiObject **
 290find_objects (
 291  NSSToken *tok,
 292  nssSession *sessionOpt,
 293  CK_ATTRIBUTE_PTR obj_template,
 294  CK_ULONG otsize,
 295  PRUint32 maximumOpt,
 296  PRStatus *statusOpt
 297)
 298{
 299    CK_RV ckrv = CKR_OK;
 300    CK_ULONG count;
 301    CK_OBJECT_HANDLE *objectHandles = NULL;
 302    CK_OBJECT_HANDLE staticObjects[OBJECT_STACK_SIZE];
 303    PRUint32 arraySize, numHandles;
 304    void *epv = nssToken_GetCryptokiEPV(tok);
 305    nssCryptokiObject **objects;
 306    nssSession *session = (sessionOpt) ? sessionOpt : tok->defaultSession;
 307
 308    /* Don't ask the module to use an invalid session handle. */
 309    if (!session || session->handle == CK_INVALID_SESSION) {
 310	ckrv = CKR_SESSION_HANDLE_INVALID;
 311	goto loser;                
 312    }
 313
 314    /* the arena is only for the array of object handles */
 315    if (maximumOpt > 0) {
 316	arraySize = maximumOpt;
 317    } else {
 318	arraySize = OBJECT_STACK_SIZE;
 319    }
 320    numHandles = 0;
 321    if (arraySize <= OBJECT_STACK_SIZE) {
 322	objectHandles = staticObjects;
 323    } else {
 324	objectHandles = nss_ZNEWARRAY(NULL, CK_OBJECT_HANDLE, arraySize);
 325    }
 326    if (!objectHandles) {
 327	ckrv = CKR_HOST_MEMORY;
 328	goto loser;
 329    }
 330    nssSession_EnterMonitor(session); /* ==== session lock === */
 331    /* Initialize the find with the template */
 332    ckrv = CKAPI(epv)->C_FindObjectsInit(session->handle, 
 333                                         obj_template, otsize);
 334    if (ckrv != CKR_OK) {
 335	nssSession_ExitMonitor(session);
 336	goto loser;
 337    }
 338    while (PR_TRUE) {
 339	/* Issue the find for up to arraySize - numHandles objects */
 340	ckrv = CKAPI(epv)->C_FindObjects(session->handle, 
 341	                                 objectHandles + numHandles, 
 342	                                 arraySize - numHandles, 
 343	                                 &count);
 344	if (ckrv != CKR_OK) {
 345	    nssSession_ExitMonitor(session);
 346	    goto loser;
 347	}
 348	/* bump the number of found objects */
 349	numHandles += count;
 350	if (maximumOpt > 0 || numHandles < arraySize) {
 351	    /* When a maximum is provided, the search is done all at once,
 352	     * so the search is finished.  If the number returned was less 
 353	     * than the number sought, the search is finished.
 354	     */
 355	    break;
 356	}
 357	/* the array is filled, double it and continue */
 358	arraySize *= 2;
 359	if (objectHandles == staticObjects) {
 360	    objectHandles = nss_ZNEWARRAY(NULL,CK_OBJECT_HANDLE, arraySize);
 361	    if (objectHandles) {
 362		PORT_Memcpy(objectHandles, staticObjects, 
 363			OBJECT_STACK_SIZE * sizeof(objectHandles[1]));
 364	    }
 365	} else {
 366	    objectHandles = nss_ZREALLOCARRAY(objectHandles, 
 367	                                  CK_OBJECT_HANDLE, 
 368	                                  arraySize);
 369	}
 370	if (!objectHandles) {
 371	    nssSession_ExitMonitor(session);
 372	    ckrv = CKR_HOST_MEMORY;
 373	    goto loser;
 374	}
 375    }
 376    ckrv = CKAPI(epv)->C_FindObjectsFinal(session->handle);
 377    nssSession_ExitMonitor(session); /* ==== end session lock === */
 378    if (ckrv != CKR_OK) {
 379	goto loser;
 380    }
 381    if (numHandles > 0) {
 382	objects = create_objects_from_handles(tok, session,
 383	                                      objectHandles, numHandles);
 384    } else {
 385	nss_SetError(NSS_ERROR_NOT_FOUND);
 386	objects = NULL;
 387    }
 388    if (objectHandles && objectHandles != staticObjects) {
 389	nss_ZFreeIf(objectHandles);
 390    }
 391    if (statusOpt) *statusOpt = PR_SUCCESS;
 392    return objects;
 393loser:
 394    if (objectHandles && objectHandles != staticObjects) {
 395	nss_ZFreeIf(objectHandles);
 396    }
 397    /*
 398     * These errors should be treated the same as if the objects just weren't
 399     * found..
 400     */
 401    if ((ckrv == CKR_ATTRIBUTE_TYPE_INVALID) ||
 402	(ckrv == CKR_ATTRIBUTE_VALUE_INVALID) ||
 403	(ckrv == CKR_DATA_INVALID) ||
 404	(ckrv == CKR_DATA_LEN_RANGE) ||
 405	(ckrv == CKR_FUNCTION_NOT_SUPPORTED) ||
 406	(ckrv == CKR_TEMPLATE_INCOMPLETE) ||
 407	(ckrv == CKR_TEMPLATE_INCONSISTENT)) {
 408
 409	nss_SetError(NSS_ERROR_NOT_FOUND);
 410	if (statusOpt) *statusOpt = PR_SUCCESS;
 411    } else {
 412	nss_SetError(ckrv);
 413	nss_SetError(NSS_ERROR_PKCS11);
 414	if (statusOpt) *statusOpt = PR_FAILURE;
 415    }
 416    return (nssCryptokiObject **)NULL;
 417}
 418
 419static nssCryptokiObject **
 420find_objects_by_template (
 421  NSSToken *token,
 422  nssSession *sessionOpt,
 423  CK_ATTRIBUTE_PTR obj_template,
 424  CK_ULONG otsize,
 425  PRUint32 maximumOpt,
 426  PRStatus *statusOpt
 427)
 428{
 429    CK_OBJECT_CLASS objclass = (CK_OBJECT_CLASS)-1;
 430    nssCryptokiObject **objects = NULL;
 431    PRUint32 i;
 432
 433    if (!token) {
 434    	PORT_SetError(SEC_ERROR_NO_TOKEN);
 435	if (statusOpt) 
 436	    *statusOpt = PR_FAILURE;
 437	return NULL;
 438    }
 439    for (i=0; i<otsize; i++) {
 440	if (obj_template[i].type == CKA_CLASS) {
 441	    objclass = *(CK_OBJECT_CLASS *)obj_template[i].pValue;
 442	    break;
 443	}
 444    }
 445    PR_ASSERT(i < otsize);
 446    if (i == otsize) {
 447	PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
 448	if (statusOpt) *statusOpt = PR_FAILURE;
 449	return NULL;
 450    }
 451    /* If these objects are being cached, try looking there first */
 452    if (token->cache && 
 453        nssTokenObjectCache_HaveObjectClass(token->cache, objclass)) 
 454    {
 455	PRStatus status;
 456	objects = nssTokenObjectCache_FindObjectsByTemplate(token->cache,
 457	                                                    objclass,
 458	                                                    obj_template,
 459	                                                    otsize,
 460	                                                    maximumOpt,
 461	                                                    &status);
 462	if (status == PR_SUCCESS) {
 463	    if (statusOpt) *statusOpt = status;
 464	    return objects;
 465	}
 466    }
 467    /* Either they are not cached, or cache failed; look on token. */
 468    objects = find_objects(token, sessionOpt, 
 469                           obj_template, otsize, 
 470                           maximumOpt, statusOpt);
 471    return objects;
 472}
 473
 474extern const NSSError NSS_ERROR_INVALID_CERTIFICATE;
 475
 476NSS_IMPLEMENT nssCryptokiObject *
 477nssToken_ImportCertificate (
 478  NSSToken *tok,
 479  nssSession *sessionOpt,
 480  NSSCertificateType certType,
 481  NSSItem *id,
 482  const NSSUTF8 *nickname,
 483  NSSDER *encoding,
 484  NSSDER *issuer,
 485  NSSDER *subject,
 486  NSSDER *serial,
 487  NSSASCII7 *email,
 488  PRBool asTokenObject
 489)
 490{
 491    PRStatus status;
 492    CK_CERTIFICATE_TYPE cert_type;
 493    CK_ATTRIBUTE_PTR attr;
 494    CK_ATTRIBUTE cert_tmpl[10];
 495    CK_ULONG ctsize;
 496    nssTokenSearchType searchType;
 497    nssCryptokiObject *rvObject = NULL;
 498
 499    if (!tok) {
 500    	PORT_SetError(SEC_ERROR_NO_TOKEN);
 501	return NULL;
 502    }
 503    if (certType == NSSCertificateType_PKIX) {
 504	cert_type = CKC_X_509;
 505    } else {
 506	return (nssCryptokiObject *)NULL;
 507    }
 508    NSS_CK_TEMPLATE_START(cert_tmpl, attr, ctsize);
 509    if (asTokenObject) {
 510	NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_true);
 511	searchType = nssTokenSearchType_TokenOnly;
 512    } else {
 513	NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_false);
 514	searchType = nssTokenSearchType_SessionOnly;
 515    }
 516    NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_CLASS,            &g_ck_class_cert);
 517    NSS_CK_SET_ATTRIBUTE_VAR( attr, CKA_CERTIFICATE_TYPE,  cert_type);
 518    NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_ID,                id);
 519    NSS_CK_SET_ATTRIBUTE_UTF8(attr, CKA_LABEL,             nickname);
 520    NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_VALUE,             encoding);
 521    NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_ISSUER,            issuer);
 522    NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_SUBJECT,           subject);
 523    NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_SERIAL_NUMBER,     serial);
 524    if (email) {
 525	NSS_CK_SET_ATTRIBUTE_UTF8(attr, CKA_NSS_EMAIL,    email);
 526    }
 527    NSS_CK_TEMPLATE_FINISH(cert_tmpl, attr, ctsize);
 528    /* see if the cert is already there */
 529    rvObject = nssToken_FindCertificateByIssuerAndSerialNumber(tok,
 530                                                               sessionOpt,
 531                                                               issuer,
 532                                                               serial,
 533                                                               searchType,
 534                                                               NULL);
 535    if (rvObject) {
 536	NSSItem existingDER;
 537	NSSSlot *slot = nssToken_GetSlot(tok);
 538	nssSession *session = nssSlot_CreateSession(slot, NULL, PR_TRUE);
 539	if (!session) {
 540	    nssCryptokiObject_Destroy(rvObject);
 541	    nssSlot_Destroy(slot);
 542	    return (nssCryptokiObject *)NULL;
 543	}
 544	/* Reject any attempt to import a new cert that has the same
 545	 * issuer/serial as an existing cert, but does not have the
 546	 * same encoding
 547	 */
 548	NSS_CK_TEMPLATE_START(cert_tmpl, attr, ctsize);
 549	NSS_CK_SET_ATTRIBUTE_NULL(attr, CKA_VALUE);
 550	NSS_CK_TEMPLATE_FINISH(cert_tmpl, attr, ctsize);
 551	status = nssCKObject_GetAttributes(rvObject->handle, 
 552	                                   cert_tmpl, ctsize, NULL,
 553	                                   session, slot);
 554	NSS_CK_ATTRIBUTE_TO_ITEM(cert_tmpl, &existingDER);
 555	if (status == PR_SUCCESS) {
 556	    if (!nssItem_Equal(encoding, &existingDER, NULL)) {
 557		nss_SetError(NSS_ERROR_INVALID_CERTIFICATE);
 558		status = PR_FAILURE;
 559	    }
 560	    nss_ZFreeIf(existingDER.data);
 561	}
 562	if (status == PR_FAILURE) {
 563	    nssCryptokiObject_Destroy(rvObject);
 564	    nssSession_Destroy(session);
 565	    nssSlot_Destroy(slot);
 566	    return (nssCryptokiObject *)NULL;
 567	}
 568	/* according to PKCS#11, label, ID, issuer, and serial number 
 569	 * may change after the object has been created.  For PKIX, the
 570	 * last two attributes can't change, so for now we'll only worry
 571	 * about the first two.
 572	 */
 573	NSS_CK_TEMPLATE_START(cert_tmpl, attr, ctsize);
 574	NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_ID,    id);
 575	NSS_CK_SET_ATTRIBUTE_UTF8(attr, CKA_LABEL, nickname);
 576	NSS_CK_TEMPLATE_FINISH(cert_tmpl, attr, ctsize);
 577	/* reset the mutable attributes on the token */
 578	nssCKObject_SetAttributes(rvObject->handle, 
 579	                          cert_tmpl, ctsize,
 580	                          session, slot);
 581	if (!rvObject->label && nickname) {
 582	    rvObject->label = nssUTF8_Duplicate(nickname, NULL);
 583	}
 584	nssSession_Destroy(session);
 585	nssSlot_Destroy(slot);
 586    } else {
 587	/* Import the certificate onto the token */
 588	rvObject = import_object(tok, sessionOpt, cert_tmpl, ctsize);
 589    }
 590    if (rvObject && tok->cache) {
 591	/* The cache will overwrite the attributes if the object already
 592	 * exists.
 593	 */
 594	nssTokenObjectCache_ImportObject(tok->cache, rvObject,
 595	                                 CKO_CERTIFICATE,
 596	                                 cert_tmpl, ctsize);
 597    }
 598    return rvObject;
 599}
 600
 601/* traverse all objects of the given class - this should only happen
 602 * if the token has been marked as "traversable"
 603 */
 604NSS_IMPLEMENT nssCryptokiObject **
 605nssToken_FindObjects (
 606  NSSToken *token,
 607  nssSession *sessionOpt,
 608  CK_OBJECT_CLASS objclass,
 609  nssTokenSearchType searchType,
 610  PRUint32 maximumOpt,
 611  PRStatus *statusOpt
 612)
 613{
 614    CK_ATTRIBUTE_PTR attr;
 615    CK_ATTRIBUTE obj_template[2];
 616    CK_ULONG obj_size;
 617    nssCryptokiObject **objects;
 618    NSS_CK_TEMPLATE_START(obj_template, attr, obj_size);
 619    /* Set the search to token/session only if provided */
 620    if (searchType == nssTokenSearchType_SessionOnly) {
 621	NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_false);
 622    } else if (searchType == nssTokenSearchType_TokenOnly ||
 623               searchType == nssTokenSearchType_TokenForced) {
 624	NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_true);
 625    }
 626    NSS_CK_SET_ATTRIBUTE_VAR( attr, CKA_CLASS, objclass);
 627    NSS_CK_TEMPLATE_FINISH(obj_template, attr, obj_size);
 628
 629    if (searchType == nssTokenSearchType_TokenForced) {
 630	objects = find_objects(token, sessionOpt,
 631	                       obj_template, obj_size,
 632	                       maximumOpt, statusOpt);
 633    } else {
 634	objects = find_objects_by_template(token, sessionOpt,
 635	                                   obj_template, obj_size,
 636	                                   maximumOpt, statusOpt);
 637    }
 638    return objects;
 639}
 640
 641NSS_IMPLEMENT nssCryptokiObject **
 642nssToken_FindCertificatesBySubject (
 643  NSSToken *token,
 644  nssSession *sessionOpt,
 645  NSSDER *subject,
 646  nssTokenSearchType searchType,
 647  PRUint32 maximumOpt,
 648  PRStatus *statusOpt
 649)
 650{
 651    CK_ATTRIBUTE_PTR attr;
 652    CK_ATTRIBUTE subj_template[3];
 653    CK_ULONG stsize;
 654    nssCryptokiObject **objects;
 655    NSS_CK_TEMPLATE_START(subj_template, attr, stsize);
 656    /* Set the search to token/session only if provided */
 657    if (searchType == nssTokenSearchType_SessionOnly) {
 658	NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_false);
 659    } else if (searchType == nssTokenSearchType_TokenOnly) {
 660	NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_true);
 661    }
 662    NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_CLASS, &g_ck_class_cert);
 663    NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_SUBJECT, subject);
 664    NSS_CK_TEMPLATE_FINISH(subj_template, attr, stsize);
 665    /* now locate the token certs matching this template */
 666    objects = find_objects_by_template(token, sessionOpt,
 667                                       subj_template, stsize,
 668                                       maximumOpt, statusOpt);
 669    return objects;
 670}
 671
 672NSS_IMPLEMENT nssCryptokiObject **
 673nssToken_FindCertificatesByNickname (
 674  NSSToken *token,
 675  nssSession *sessionOpt,
 676  const NSSUTF8 *name,
 677  nssTokenSearchType searchType,
 678  PRUint32 maximumOpt,
 679  PRStatus *statusOpt
 680)
 681{
 682    CK_ATTRIBUTE_PTR attr;
 683    CK_ATTRIBUTE nick_template[3];
 684    CK_ULONG ntsize;
 685    nssCryptokiObject **objects;
 686    NSS_CK_TEMPLATE_START(nick_template, attr, ntsize);
 687    NSS_CK_SET_ATTRIBUTE_UTF8(attr, CKA_LABEL, name);
 688    /* Set the search to token/session only if provided */
 689    if (searchType == nssTokenSearchType_SessionOnly) {
 690	NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_false);
 691    } else if (searchType == nssTokenSearchType_TokenOnly) {
 692	NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_true);
 693    }
 694    NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_CLASS, &g_ck_class_cert);
 695    NSS_CK_TEMPLATE_FINISH(nick_template, attr, ntsize);
 696    /* now locate the token certs matching this template */
 697    objects = find_objects_by_template(token, sessionOpt,
 698                                       nick_template, ntsize, 
 699                                       maximumOpt, statusOpt);
 700    if (!objects) {
 701	/* This is to workaround the fact that PKCS#11 doesn't specify
 702	 * whether the '\0' should be included.  XXX Is that still true?
 703	 * im - this is not needed by the current softoken.  However, I'm 
 704	 * leaving it in until I have surveyed more tokens to see if it needed.
 705	 * well, its needed by the builtin token...
 706	 */
 707	nick_template[0].ulValueLen++;
 708	objects = find_objects_by_template(token, sessionOpt,
 709	                                   nick_template, ntsize, 
 710	                                   maximumOpt, statusOpt);
 711    }
 712    return objects;
 713}
 714
 715/* XXX
 716 * This function *does not* use the token object cache, because not even
 717 * the softoken will return a value for CKA_NSS_EMAIL from a call
 718 * to GetAttributes.  The softoken does allow searches with that attribute,
 719 * it just won't return a value for it.
 720 */
 721NSS_IMPLEMENT nssCryptokiObject **
 722nssToken_FindCertificatesByEmail (
 723  NSSToken *token,
 724  nssSession *sessionOpt,
 725  NSSASCII7 *email,
 726  nssTokenSearchType searchType,
 727  PRUint32 maximumOpt,
 728  PRStatus *statusOpt
 729)
 730{
 731    CK_ATTRIBUTE_PTR attr;
 732    CK_ATTRIBUTE email_template[3];
 733    CK_ULONG etsize;
 734    nssCryptokiObject **objects;
 735    NSS_CK_TEMPLATE_START(email_template, attr, etsize);
 736    NSS_CK_SET_ATTRIBUTE_UTF8(attr, CKA_NSS_EMAIL, email);
 737    /* Set the search to token/session only if provided */
 738    if (searchType == nssTokenSearchType_SessionOnly) {
 739	NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_false);
 740    } else if (searchType == nssTokenSearchType_TokenOnly) {
 741	NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_true);
 742    }
 743    NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_CLASS, &g_ck_class_cert);
 744    NSS_CK_TEMPLATE_FINISH(email_template, attr, etsize);
 745    /* now locate the token certs matching this template */
 746    objects = find_objects(token, sessionOpt,
 747                           email_template, etsize,
 748                           maximumOpt, statusOpt);
 749    if (!objects) {
 750	/* This is to workaround the fact that PKCS#11 doesn't specify
 751	 * whether the '\0' should be included.  XXX Is that still true?
 752	 * im - this is not needed by the current softoken.  However, I'm 
 753	 * leaving it in until I have surveyed more tokens to see if it needed.
 754	 * well, its needed by the builtin token...
 755	 */
 756	email_template[0].ulValueLen++;
 757	objects = find_objects(token, sessionOpt,
 758	                       email_template, etsize,
 759	                       maximumOpt, statusOpt);
 760    }
 761    return objects;
 762}
 763
 764NSS_IMPLEMENT nssCryptokiObject **
 765nssToken_FindCertificatesByID (
 766  NSSToken *token,
 767  nssSession *sessionOpt,
 768  NSSItem *id,
 769  nssTokenSearchType searchType,
 770  PRUint32 maximumOpt,
 771  PRStatus *statusOpt
 772)
 773{
 774    CK_ATTRIBUTE_PTR attr;
 775    CK_ATTRIBUTE id_template[3];
 776    CK_ULONG idtsize;
 777    nssCryptokiObject **objects;
 778    NSS_CK_TEMPLATE_START(id_template, attr, idtsize);
 779    NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_ID, id);
 780    /* Set the search to token/session only if provided */
 781    if (searchType == nssTokenSearchType_SessionOnly) {
 782	NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_false);
 783    } else if (searchType == nssTokenSearchType_TokenOnly) {
 784	NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_true);
 785    }
 786    NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_CLASS, &g_ck_class_cert);
 787    NSS_CK_TEMPLATE_FINISH(id_template, attr, idtsize);
 788    /* now locate the token certs matching this template */
 789    objects = find_objects_by_template(token, sessionOpt,
 790                                       id_template, idtsize,
 791                                       maximumOpt, statusOpt);
 792    return objects;
 793}
 794
 795/*
 796 * decode the serial item and return our result.
 797 * NOTE serialDecode's data is really stored in serial. Don't free it.
 798 */
 799static PRStatus
 800nssToken_decodeSerialItem(NSSItem *serial, NSSItem *serialDecode)
 801{
 802    unsigned char *data = (unsigned char *)serial->data;
 803    int data_left, data_len, index;
 804
 805    if ((serial->size >= 3) && (data[0] == 0x2)) {
 806	/* remove the der encoding of the serial number before generating the
 807	 * key.. */
 808	data_left = serial->size-2;
 809	data_len = data[1];
 810	index = 2;
 811
 812	/* extended length ? (not very likely for a serial number) */
 813	if (data_len & 0x80) {
 814	    int len_count = data_len & 0x7f;
 815
 816	    data_len = 0;
 817	    data_left -= len_count;
 818	    if (data_left > 0) {
 819		while (len_count --) {
 820		    data_len = (data_len << 8) | data[index++];
 821		}
 822	    } 
 823	}
 824	/* XXX leaving any leading zeros on the serial number for backwards
 825	 * compatibility
 826	 */
 827	/* not a valid der, must be just an unlucky serial number value */
 828	if (data_len == data_left) {
 829	    serialDecode->size = data_len;
 830	    serialDecode->data = &data[index];
 831	    return PR_SUCCESS;
 832	}
 833    }
 834    return PR_FAILURE;
 835}
 836
 837NSS_IMPLEMENT nssCryptokiObject *
 838nssToken_FindCertificateByIssuerAndSerialNumber (
 839  NSSToken *token,
 840  nssSession *sessionOpt,
 841  NSSDER *issuer,
 842  NSSDER *serial,
 843  nssTokenSearchType searchType,
 844  PRStatus *statusOpt
 845)
 846{
 847    CK_ATTRIBUTE_PTR attr;
 848    CK_ATTRIBUTE_PTR serialAttr;
 849    CK_ATTRIBUTE cert_template[4];
 850    CK_ULONG ctsize;
 851    nssCryptokiObject **objects;
 852    nssCryptokiObject *rvObject = NULL;
 853    NSS_CK_TEMPLATE_START(cert_template, attr, ctsize);
 854
 855    if (!token) {
 856    	PORT_SetError(SEC_ERROR_NO_TOKEN);
 857	if (statusOpt) 
 858	    *statusOpt = PR_FAILURE;
 859	return NULL;
 860    }
 861    /* Set the search to token/session only if provided */
 862    if (searchType == nssTokenSearchType_SessionOnly) {
 863	NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_false);
 864    } else if ((searchType == nssTokenSearchType_TokenOnly) ||
 865               (searchType == nssTokenSearchType_TokenForced)) {
 866	NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_true);
 867    }
 868    /* Set the unique id */
 869    NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_CLASS,         &g_ck_class_cert);
 870    NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_ISSUER,         issuer);
 871    serialAttr = attr;
 872    NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_SERIAL_NUMBER,  serial);
 873    NSS_CK_TEMPLATE_FINISH(cert_template, attr, ctsize);
 874    /* get the object handle */
 875    if (searchType == nssTokenSearchType_TokenForced) {
 876	objects = find_objects(token, sessionOpt,
 877	                       cert_template, ctsize,
 878	                       1, statusOpt);
 879    } else {
 880	objects = find_objects_by_template(token, sessionOpt,
 881                                       cert_template, ctsize,
 882                                       1, statusOpt);
 883    }
 884    if (objects) {
 885	rvObject = objects[0];
 886	nss_ZFreeIf(objects);
 887    }
 888
 889    /*
 890     * NSS used to incorrectly store serial numbers in their decoded form.
 891     * because of this old tokens have decoded serial numbers.
 892     */
 893    if (!objects) {
 894	NSSItem serialDecode;
 895	PRStatus status;
 896
 897	status = nssToken_decodeSerialItem(serial, &serialDecode);
 898	if (status != PR_SUCCESS) {
 899	    return NULL;
 900	}
 901    	NSS_CK_SET_ATTRIBUTE_ITEM(serialAttr,CKA_SERIAL_NUMBER,&serialDecode);
 902	if (searchType == nssTokenSearchType_TokenForced) {
 903	    objects = find_objects(token, sessionOpt,
 904	                       cert_template, ctsize,
 905	                       1, statusOpt);
 906	} else {
 907	    objects = find_objects_by_template(token, sessionOpt,
 908                                       cert_template, ctsize,
 909                                       1, statusOpt);
 910	}
 911	if (objects) {
 912	    rvObject = objects[0];
 913	    nss_ZFreeIf(objects);
 914	}
 915    }
 916    return rvObject;
 917}
 918
 919NSS_IMPLEMENT nssCryptokiObject *
 920nssToken_FindCertificateByEncodedCertificate (
 921  NSSToken *token,
 922  nssSession *sessionOpt,
 923  NSSBER *encodedCertificate,
 924  nssTokenSearchType searchType,
 925  PRStatus *statusOpt
 926)
 927{
 928    CK_ATTRIBUTE_PTR attr;
 929    CK_ATTRIBUTE cert_template[3];
 930    CK_ULONG ctsize;
 931    nssCryptokiObject **objects;
 932    nssCryptokiObject *rvObject = NULL;
 933    NSS_CK_TEMPLATE_START(cert_template, attr, ctsize);
 934    /* Set the search to token/session only if provided */
 935    if (searchType == nssTokenSearchType_SessionOnly) {
 936	NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_false);
 937    } else if (searchType == nssTokenSearchType_TokenOnly) {
 938	NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_true);
 939    }
 940    NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_CLASS, &g_ck_class_cert);
 941    NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_VALUE, encodedCertificate);
 942    NSS_CK_TEMPLATE_FINISH(cert_template, attr, ctsize);
 943    /* get the object handle */
 944    objects = find_objects_by_template(token, sessionOpt,
 945                                       cert_template, ctsize,
 946                                       1, statusOpt);
 947    if (objects) {
 948	rvObject = objects[0];
 949	nss_ZFreeIf(objects);
 950    }
 951    return rvObject;
 952}
 953
 954NSS_IMPLEMENT nssCryptokiObject **
 955nssToken_FindPrivateKeys (
 956  NSSToken *token,
 957  nssSession *sessionOpt,
 958  nssTokenSearchType searchType,
 959  PRUint32 maximumOpt,
 960  PRStatus *statusOpt
 961)
 962{
 963    CK_ATTRIBUTE_PTR attr;
 964    CK_ATTRIBUTE key_template[2];
 965    CK_ULONG ktsize;
 966    nssCryptokiObject **objects;
 967
 968    NSS_CK_TEMPLATE_START(key_template, attr, ktsize);
 969    NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_CLASS, &g_ck_class_privkey);
 970    if (searchType == nssTokenSearchType_SessionOnly) {
 971	NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_false);
 972    } else if (searchType == nssTokenSearchType_TokenOnly) {
 973	NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_true);
 974    }
 975    NSS_CK_TEMPLATE_FINISH(key_template, attr, ktsize);
 976
 977    objects = find_objects_by_template(token, sessionOpt,
 978                                       key_template, ktsize, 
 979                                       maximumOpt, statusOpt);
 980    return objects;
 981}
 982
 983/* XXX ?there are no session cert objects, so only search token objects */
 984NSS_IMPLEMENT nssCryptokiObject *
 985nssToken_FindPrivateKeyByID (
 986  NSSToken *token,
 987  nssSession *sessionOpt,
 988  NSSItem *keyID
 989)
 990{
 991    CK_ATTRIBUTE_PTR attr;
 992    CK_ATTRIBUTE key_template[3];
 993    CK_ULONG ktsize;
 994    nssCryptokiObject **objects;
 995    nssCryptokiObject *rvKey = NULL;
 996
 997    NSS_CK_TEMPLATE_START(key_template, attr, ktsize);
 998    NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_CLASS, &g_ck_class_privkey);
 999    NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_true);
1000    NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_ID, keyID);
1001    NSS_CK_TEMPLATE_FINISH(key_template, attr, ktsize);
1002
1003    objects = find_objects_by_template(token, sessionOpt,
1004                                       key_template, ktsize, 
1005                                       1, NULL);
1006    if (objects) {
1007	rvKey = objects[0];
1008	nss_ZFreeIf(objects);
1009    }
1010    return rvKey;
1011}
1012
1013/* XXX ?there are no session cert objects, so only search token objects */
1014NSS_IMPLEMENT nssCryptokiObject *
1015nssToken_FindPublicKeyByID (
1016  NSSToken *token,
1017  nssSession *sessionOpt,
1018  NSSItem *keyID
1019)
1020{
1021    CK_ATTRIBUTE_PTR attr;
1022    CK_ATTRIBUTE key_template[3];
1023    CK_ULONG ktsize;
1024    nssCryptokiObject **objects;
1025    nssCryptokiObject *rvKey = NULL;
1026
1027    NSS_CK_TEMPLATE_START(key_template, attr, ktsize);
1028    NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_CLASS, &g_ck_class_pubkey);
1029    NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_true);
1030    NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_ID, keyID);
1031    NSS_CK_TEMPLATE_FINISH(key_template, attr, ktsize);
1032
1033    objects = find_objects_by_template(token, sessionOpt,
1034                                       key_template, ktsize, 
1035                                       1, NULL);
1036    if (objects) {
1037	rvKey = objects[0];
1038	nss_ZFreeIf(objects);
1039    }
1040    return rvKey;
1041}
1042
1043static void
1044sha1_hash(NSSItem *input, NSSItem *output)
1045{
1046    NSSAlgorithmAndParameters *ap;
1047    PK11SlotInfo *internal = PK11_GetInternalSlot();
1048    NSSToken *token = PK11Slot_GetNSSToken(internal);
1049    ap = NSSAlgorithmAndParameters_CreateSHA1Digest(NULL);
1050    (void)nssToken_Digest(token, NULL, ap, input, output, NULL);
1051    PK11_FreeSlot(token->pk11slot);
1052    nss_ZFreeIf(ap);
1053}
1054
1055static void
1056md5_hash(NSSItem *input, NSSItem *output)
1057{
1058    NSSAlgorithmAndParameters *ap;
1059    PK11SlotInfo *internal = PK11_GetInternalSlot();
1060    NSSToken *token = PK11Slot_GetNSSToken(internal);
1061    ap = NSSAlgorithmAndParameters_CreateMD5Digest(NULL);
1062    (void)nssToken_Digest(token, NULL, ap, input, output, NULL);
1063    PK11_FreeSlot(token->pk11slot);
1064    nss_ZFreeIf(ap);
1065}
1066
1067static CK_TRUST
1068get_ck_trust (
1069  nssTrustLevel nssTrust
1070)
1071{
1072    CK_TRUST t;
1073    switch (nssTrust) {
1074    case nssTrustLevel_NotTrusted: t = CKT_NSS_NOT_TRUSTED; break;
1075    case nssTrustLevel_TrustedDelegator: t = CKT_NSS_TRUSTED_DELEGATOR; 
1076	break;
1077    case nssTrustLevel_ValidDelegator: t = CKT_NSS_VALID_DELEGATOR; break;
1078    case nssTrustLevel_Trusted: t = CKT_NSS_TRUSTED; break;
1079    case nssTrustLevel_MustVerify: t = CKT_NSS_MUST_VERIFY_TRUST; break;
1080    case nssTrustLevel_Unknown:
1081    default: t = CKT_NSS_TRUST_UNKNOWN; break;
1082    }
1083    return t;
1084}
1085 
1086NSS_IMPLEMENT nssCryptokiObject *
1087nssToken_ImportTrust (
1088  NSSToken *tok,
1089  nssSession *sessionOpt,
1090  NSSDER *certEncoding,
1091  NSSDER *certIssuer,
1092  NSSDER *certSerial,
1093  nssTrustLevel serverAuth,
1094  nssTrustLevel clientAuth,
1095  nssTrustLevel codeSigning,
1096  nssTrustLevel emailProtection,
1097  PRBool stepUpApproved,
1098  PRBool asTokenObject
1099)
1100{
1101    nssCryptokiObject *object;
1102    CK_OBJECT_CLASS tobjc = CKO_NSS_TRUST;
1103    CK_TRUST ckSA, ckCA, ckCS, ckEP;
1104    CK_ATTRIBUTE_PTR attr;
1105    CK_ATTRIBUTE trust_tmpl[11];
1106    CK_ULONG tsize;
1107    PRUint8 sha1[20]; /* this is cheating... */
1108    PRUint8 md5[16];
1109    NSSItem sha1_result, md5_result;
1110    sha1_result.data = sha1; sha1_result.size = sizeof sha1;
1111    md5_result.data = md5; md5_result.size = sizeof md5;
1112    sha1_hash(certEncoding, &sha1_result);
1113    md5_hash(certEncoding, &md5_result);
1114    ckSA = get_ck_trust(serverAuth);
1115    ckCA = get_ck_trust(clientAuth);
1116    ckCS = get_ck_trust(codeSigning);
1117    ckEP = get_ck_trust(emailProtection);
1118    NSS_CK_TEMPLATE_START(trust_tmpl, attr, tsize);
1119    if (asTokenObject) {
1120	NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_true);
1121    } else {
1122	NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_false);
1123    }
1124    NSS_CK_SET_ATTRIBUTE_VAR( attr, CKA_CLASS,           tobjc);
1125    NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_ISSUER,          certIssuer);
1126    NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_SERIAL_NUMBER,   certSerial);
1127    NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_CERT_SHA1_HASH, &sha1_result);
1128    NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_CERT_MD5_HASH,  &md5_result);
1129    /* now set the trust values */
1130    NSS_CK_SET_ATTRIBUTE_VAR(attr, CKA_TRUST_SERVER_AUTH,      ckSA);
1131    NSS_CK_SET_ATTRIBUTE_VAR(attr, CKA_TRUST_CLIENT_AUTH,      ckCA);
1132    NSS_CK_SET_ATTRIBUTE_VAR(attr, CKA_TRUST_CODE_SIGNING,     ckCS);
1133    NSS_CK_SET_ATTRIBUTE_VAR(attr, CKA_TRUST_EMAIL_PROTECTION, ckEP);
1134    if (stepUpApproved) {
1135	NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TRUST_STEP_UP_APPROVED, 
1136	                          &g_ck_true);
1137    } else {
1138	NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TRUST_STEP_UP_APPROVED, 
1139	                          &g_ck_false);
1140    }
1141    NSS_CK_TEMPLATE_FINISH(trust_tmpl, attr, tsize);
1142    /* import the trust object onto the token */
1143    object = import_object(tok, sessionOpt, trust_tmpl, tsize);
1144    if (object && tok->cache) {
1145	nssTokenObjectCache_ImportObject(tok->cache, object, tobjc,
1146	                                 trust_tmpl, tsize);
1147    }
1148    return object;
1149}
1150
1151NSS_IMPLEMENT nssCryptokiObject *
1152nssToken_FindTrustForCertificate (
1153  NSSToken *token,
1154  nssSession *sessionOpt,
1155  NSSDER *certEncoding,
1156  NSSDER *certIssuer,
1157  NSSDER *certSerial,
1158  nssTokenSearchType searchType
1159)
1160{
1161    CK_OBJECT_CLASS tobjc = CKO_NSS_TRUST;
1162    CK_ATTRIBUTE_PTR attr;
1163    CK_ATTRIBUTE tobj_template[5];
1164    CK_ULONG tobj_size;
1165    nssSession *session = sessionOpt ? sessionOpt : token->defaultSession;
1166    nssCryptokiObject *object = NULL, **objects;
1167
1168    /* Don't ask the module to use an invalid session handle. */
1169    if (!session || session->handle == CK_INVALID_SESSION) {
1170	PORT_SetError(SEC_ERROR_NO_TOKEN);
1171	return object;
1172    }
1173
1174    NSS_CK_TEMPLATE_START(tobj_template, attr, tobj_size);
1175    if (searchType == nssTokenSearchType_TokenOnly) {
1176	NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_true);
1177    }
1178    NSS_CK_SET_ATTRIBUTE_VAR( attr, CKA_CLASS,          tobjc);
1179    NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_ISSUER,         certIssuer);
1180    NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_SERIAL_NUMBER , certSerial);
1181    NSS_CK_TEMPLATE_FINISH(tobj_template, attr, tobj_size);
1182    objects = find_objects_by_template(token, session,
1183                                       tobj_template, tobj_size,
1184                                       1, NULL);
1185    if (objects) {
1186	object = objects[0];
1187	nss_ZFreeIf(objects);
1188    }
1189    return object;
1190}
1191 
1192NSS_IMPLEMENT nssCryptokiObject *
1193nssToken_ImportCRL (
1194  NSSToken *token,
1195  nssSession *sessionOpt,
1196  NSSDER *subject,
1197  NSSDER *encoding,
1198  PRBool isKRL,
1199  NSSUTF8 *url,
1200  PRBool asTokenObject
1201)
1202{
1203    nssCryptokiObject *object;
1204    CK_OBJECT_CLASS crlobjc = CKO_NSS_CRL;
1205    CK_ATTRIBUTE_PTR attr;
1206    CK_ATTRIBUTE crl_tmpl[6];
1207    CK_ULONG crlsize;
1208
1209    NSS_CK_TEMPLATE_START(crl_tmpl, attr, crlsize);
1210    if (asTokenObject) {
1211	NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_true);
1212    } else {
1213	NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_false);
1214    }
1215    NSS_CK_SET_ATTRIBUTE_VAR( attr, CKA_CLASS,        crlobjc);
1216    NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_SUBJECT,      subject);
1217    NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_VALUE,        encoding);
1218    NSS_CK_SET_ATTRIBUTE_UTF8(attr, CKA_NSS_URL, url);
1219    if (isKRL) {
1220	NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_NSS_KRL, &g_ck_true);
1221    } else {
1222	NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_NSS_KRL, &g_ck_false);
1223    }
1224    NSS_CK_TEMPLATE_FINISH(crl_tmpl, attr, crlsize);
1225
1226    /* import the crl object onto the token */
1227    object = import_object(token, sessionOpt, crl_tmpl, crlsize);
1228    if (object && token->cache) {
1229	nssTokenObjectCache_ImportObject(token->cache, object, crlobjc,
1230	                                 crl_tmpl, crlsize);
1231    }
1232    return object;
1233}
1234
1235NSS_IMPLEMENT nssCryptokiObject **
1236nssToken_FindCRLsBySubject (
1237  NSSToken *token,
1238  nssSession *sessionOpt,
1239  NSSDER *subject,
1240  nssTokenSearchType searchType,
1241  PRUint32 maximumOpt,
1242  PRStatus *statusOpt
1243)
1244{
1245    CK_OBJECT_CLASS crlobjc = CKO_NSS_CRL;
1246    CK_ATTRIBUTE_PTR attr;
1247    CK_ATTRIBUTE crlobj_template[3];
1248    CK_ULONG crlobj_size;
1249    nssCryptokiObject **objects = NULL;
1250    nssSession *session = sessionOpt ? sessionOpt : token->defaultSession;
1251
1252    /* Don't ask the module to use an invalid session handle. */
1253    if (!session || session->handle == CK_INVALID_SESSION) {
1254	PORT_SetError(SEC_ERROR_NO_TOKEN);
1255	return objects;
1256    }
1257
1258    NSS_CK_TEMPLATE_START(crlobj_template, attr, crlobj_size);
1259    if (searchType == nssTokenSearchType_SessionOnly) {
1260	NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_false);
1261    } else if (searchType == nssTokenSearchType_TokenOnly ||
1262               searchType == nssTokenSearchType_TokenForced) {
1263	NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_true);
1264    }
1265    NSS_CK_SET_ATTRIBUTE_VAR( attr, CKA_CLASS, crlobjc);
1266    NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_SUBJECT, subject);
1267    NSS_CK_TEMPLATE_FINISH(crlobj_template, attr, crlobj_size);
1268
1269    objects = find_objects_by_template(token, session,
1270                                       crlobj_template, crlobj_size,
1271                                       maximumOpt, statusOpt);
1272    return objects;
1273}
1274
1275NSS_IMPLEMENT PRStatus
1276nssToken_GetCachedObjectAttributes (
1277  NSSToken *token,
1278  NSSArena *arenaOpt,
1279  nssCryptokiObject *object,
1280  CK_OBJECT_CLASS objclass,
1281  CK_ATTRIBUTE_PTR atemplate,
1282  CK_ULONG atlen
1283)
1284{
1285    if (!token->cache) {
1286	return PR_FAILURE;
1287    }
1288    return nssTokenObjectCache_GetObjectAttributes(token->cache, arenaOpt,
1289                                                   object, objclass,
1290                                                   atemplate, atlen);
1291}
1292
1293NSS_IMPLEMENT NSSItem *
1294nssToken_Digest (
1295  NSSToken *tok,
1296  nssSession *sessionOpt,
1297  NSSAlgorithmAndParameters *ap,
1298  NSSItem *data,
1299  NSSItem *rvOpt,
1300  NSSArena *arenaOpt
1301)
1302{
1303    CK_RV ckrv;
1304    CK_ULONG digestLen;
1305    CK_BYTE_PTR digest;
1306    NSSItem *rvItem = NULL;
1307    void *epv = nssToken_GetCryptokiEPV(tok);
1308    nssSession *session = (sessionOpt) ? sessionOpt : tok->defaultSession;
1309
1310    /* Don't ask the module to use an invalid session handle. */
1311    if (!session || session->handle == CK_INVALID_SESSION) {
1312	PORT_SetError(SEC_ERROR_NO_TOKEN);
1313	return rvItem;
1314    }
1315
1316    nssSession_EnterMonitor(session);
1317    ckrv = CKAPI(epv)->C_DigestInit(session->handle, &ap->mechanism);
1318    if (ckrv != CKR_OK) {
1319	nssSession_ExitMonitor(session);
1320	return NULL;
1321    }
1322#if 0
1323    /* XXX the standard says this should work, but it doesn't */
1324    ckrv = CKAPI(epv)->C_Digest(session->handle, NULL, 0, NULL, &digestLen);
1325    if (ckrv != CKR_OK) {
1326	nssSession_ExitMonitor(session);
1327	return NULL;
1328    }
1329#endif
1330    digestLen = 0; /* XXX for now */
1331    digest = NULL;
1332    if (rvOpt) {
1333	if (rvOpt->size > 0 && rvOpt->size < digestLen) {
1334	    nssSession_ExitMonitor(session);
1335	    /* the error should be bad args */
1336	    return NULL;
1337	}
1338	if (rvOpt->data) {
1339	    digest = rvOpt->data;
1340	}
1341	digestLen = rvOpt->size;
1342    }
1343    if (!digest) {
1344	digest = (CK_BYTE_PTR)nss_ZAlloc(arenaOpt, digestLen);
1345	if (!digest) {
1346	    nssSession_ExitMonitor(session);
1347	    return NULL;
1348	}
1349    }
1350    ckrv = CKAPI(epv)->C_Digest(session->handle, 
1351                                (CK_BYTE_PTR)data->data, 
1352                                (CK_ULONG)data->size,
1353                                (CK_BYTE_PTR)digest,
1354                                &digestLen);
1355    nssSession_ExitMonitor(session);
1356    if (ckrv != CKR_OK) {
1357	nss_ZFreeIf(digest);
1358	return NULL;
1359    }
1360    if (!rvOpt) {
1361	rvItem = nssItem_Create(arenaOpt, NULL, digestLen, (void *)digest);
1362    }
1363    return rvItem;
1364}
1365
1366NSS_IMPLEMENT PRStatus
1367nssToken_BeginDigest (
1368  NSSToken *tok,
1369  nssSession *sessionOpt,
1370  NSSAlgorithmAndParameters *ap
1371)
1372{
1373    CK_RV ckrv;
1374    void *epv = nssToken_GetCryptokiEPV(tok);
1375    nssSession *session = (sessionOpt) ? sessionOpt : tok->defaultSession;
1376
1377    /* Don't ask the module to use an invalid session handle. */
1378    if (!session || session->handle == CK_INVALID_SESSION) {
1379	PORT_SetError(SEC_ERROR_NO_TOKEN);
1380	return PR_FAILURE;
1381    }
1382
1383    nssSession_EnterMonitor(session);
1384    ckrv = CKAPI(epv)->C_DigestInit(session->handle, &ap->mechanism);
1385    nssSession_ExitMonitor(session);
1386    return (ckrv == CKR_OK) ? PR_SUCCESS : PR_FAILURE;
1387}
1388
1389NSS_IMPLEMENT PRStatus
1390nssToken_ContinueDigest (
1391  NSSToken *tok,
1392  nssSession *sessionOpt,
1393  NSSItem *item
1394)
1395{
1396    CK_RV ckrv;
1397    void *epv = nssToken_GetCryptokiEPV(tok);
1398    nssSession *session = (sessionOpt) ? sessionOpt : tok->defaultSession;
1399
1400    /* Don't ask the module to use an invalid session handle. */
1401    if (!session || session->handle == CK_INVALID_SESSION) {
1402	PORT_SetError(SEC_ERROR_NO_TOKEN);
1403	return PR_FAILURE;
1404    }
1405
1406    nssSession_EnterMonitor(session);
1407    ckrv = CKAPI(epv)->C_DigestUpdate(session->handle, 
1408                                      (CK_BYTE_PTR)item->data, 
1409                                      (CK_ULONG)item->size);
1410    nssSession_ExitMonitor(session);
1411    return (ckrv == CKR_OK) ? PR_SUCCESS : PR_FAILURE;
1412}
1413
1414NSS_IMPLEMENT NSSItem *
1415nssToken_FinishDigest (
1416  NSSToken *tok,
1417  nssSession *sessionOpt,
1418  NSSItem *rvOpt,
1419  NSSArena *arenaOpt
1420)
1421{
1422    CK_RV ckrv;
1423    CK_ULONG digestLen;
1424    CK_BYTE_PTR digest;
1425    NSSItem *rvItem = NULL;
1426    void *epv = nssToken_GetCryptokiEPV(tok);
1427    nssSession *session = (sessionOpt) ? sessionOpt : tok->defaultSession;
1428
1429    /* Don't ask the module to use an invalid session handle. */
1430    if (!session || session->handle == CK_INVALID_SESSION) {
1431	PORT_SetError(SEC_ERROR_NO_TOKEN);
1432	return NULL;
1433    }
1434
1435    nssSession_EnterMonitor(session);
1436    ckrv = CKAPI(epv)->C_DigestFinal(session->handle, NULL, &digestLen);
1437    if (ckrv != CKR_OK || digestLen == 0) {
1438	nssSession_ExitMonitor(session);
1439	return NULL;
1440    }
1441    digest = NULL;
1442    if (rvOpt) {
1443	if (rvOpt->size > 0 && rvOpt->size < digestLen) {
1444	    nssSession_ExitMonitor(session);
1445	    /* the error should be bad args */
1446	    return NULL;
1447	}
1448	if (rvOpt->data) {
1449	    digest = rvOpt->data;
1450	}
1451	digestLen = rvOpt->size;
1452    }
1453    if (!digest) {
1454	digest = (CK_BYTE_PTR)nss_ZAlloc(arenaOpt, digestLen);
1455	if (!digest) {
1456	    nssSession_ExitMonitor(session);
1457	    return NULL;
1458	}
1459    }
1460    ckrv = CKAPI(epv)->C_DigestFinal(session->handle, digest, &digestLen);
1461    nssSession_ExitMonitor(session);
1462    if (ckrv != CKR_OK) {
1463	nss_ZFreeIf(digest);
1464	return NULL;
1465    }
1466    if (!rvOpt) {
1467	rvItem = nssItem_Create(arenaOpt, NULL, digestLen, (void *)digest);
1468    }
1469    return rvItem;
1470}
1471
1472NSS_IMPLEMENT PRBool
1473nssToken_IsPresent (
1474  NSSToken *token
1475)
1476{
1477    return nssSlot_IsTokenPresent(token->slot);
1478}
1479
1480/* Sigh.  The methods to find objects declared above cause problems with
1481 * the low-level object cache in the softoken -- the objects are found in 
1482 * toto, then one wave of GetAttributes is done, then another.  Having a 
1483 * large number of objects causes the cache to be thrashed, as the objects 
1484 * are gone before there's any chance to ask for their attributes.
1485 * So, for now, bringing back traversal methods for certs.  This way all of 
1486 * the cert's attributes can be grabbed immediately after finding it,
1487 * increasing the likelihood that the cache takes care of it.
1488 */
1489NSS_IMPLEMENT PRStatus
1490nssToken_TraverseCertificates (
1491  NSSToken *token,
1492  nssSession *sessionOpt,
1493  nssTokenSearchType searchType,
1494  PRStatus (* callback)(nssCryptokiObject *instance, void *arg),
1495  void *arg
1496)
1497{
1498    CK_RV ckrv;
1499    CK_ULONG count;
1500    CK_OBJECT_HANDLE *objectHandles;
1501    CK_ATTRIBUTE_PTR attr;
1502    CK_ATTRIBUTE cert_template[2];
1503    CK_ULONG ctsize;
1504    NSSArena *arena;
1505    PRStatus status;
1506    PRUint32 arraySize, numHandles;
1507    nssCryptokiObject **objects;
1508    void *epv = nssToken_GetCryptokiEPV(token);
1509    nssSession *session = (sessionOpt) ? sessionOpt : token->defaultSession;
1510
1511    /* Don't ask the module to use an invalid session handle. */
1512    if (!session || session->handle == CK_INVALID_SESSION) {
1513	PORT_SetError(SEC_ERROR_NO_TOKEN);
1514	return PR_FAILURE;
1515    }
1516
1517    /* template for all certs */
1518    NSS_CK_TEMPLATE_START(cert_template, attr, ctsize);
1519    if (searchType == nssTokenSearchType_SessionOnly) {
1520	NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_false);
1521    } else if (searchType == nssTokenSearchType_TokenOnly ||
1522               searchType == nssTokenSearchType_TokenForced) {
1523	NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_true);
1524    }
1525    NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_CLASS, &g_ck_class_cert);
1526    NSS_CK_TEMPLATE_FINISH(cert_template, attr, ctsize);
1527
1528    /* the arena is only for the array of object handles */
1529    arena = nssArena_Create();
1530    if (!arena) {
1531	return PR_FAILURE;
1532    }
1533    arraySize = OBJECT_STACK_SIZE;
1534    numHandles = 0;
1535    objectHandles = nss_ZNEWARRAY(arena, CK_OBJECT_HANDLE, arraySize);
1536    if (!objectHandles) {
1537	goto loser;
1538    }
1539    nssSession_EnterMonitor(session); /* ==== session lock === */
1540    /* Initialize the find with the template */
1541    ckrv = CKAPI(epv)->C_FindObjectsInit(session->handle, 
1542                                         cert_template, ctsize);
1543    if (ckrv != CKR_OK) {
1544	nssSession_ExitMonitor(session);
1545	goto loser;
1546    }
1547    while (PR_TRUE) {
1548	/* Issue the find for up to arraySize - numHandles objects */
1549	ckrv = CKAPI(epv)->C_FindObjects(session->handle, 
1550	                                 objectHandles + numHandles, 
1551	                                 arraySize - numHandles, 
1552	                                 &count);
1553	if (ckrv != CKR_OK) {
1554	    nssSession_ExitMonitor(session);
1555	    goto loser;
1556	}
1557	/* bump the number of found objects */
1558	numHandles += count;
1559	if (numHandles < arraySize) {
1560	    break;
1561	}
1562	/* the array is filled, double it and continue */
1563	arraySize *= 2;
1564	objectHandles = nss_ZREALLOCARRAY(objectHandles, 
1565	                                  CK_OBJECT_HANDLE, 
1566	                                  arraySize);
1567	if (!objectHandles) {
1568	    nssSession_ExitMonitor(session);
1569	    goto loser;
1570	}
1571    }
1572    ckrv = CKAPI(epv)->C_FindObjectsFinal(session->handle);
1573    nssSession_ExitMonitor(session); /* ==== end session lock === */
1574    if (ckrv != CKR_OK) {
1575	goto loser;
1576    }
1577    if (numHandles > 0) {
1578	objects = create_objects_from_handles(token, session,
1579	                                      objectHandles, numHandles);
1580	if (objects) {
1581	    nssCryptokiObject **op;
1582	    for (op = objects; *op; op++) {
1583		status = (*callback)(*op, arg);
1584	    }
1585	    nss_ZFreeIf(objects);
1586	}
1587    }
1588    nssArena_Destroy(arena);
1589    return PR_SUCCESS;
1590loser:
1591    nssArena_Destroy(arena);
1592    return PR_FAILURE;
1593}
1594
1595NSS_IMPLEMENT PRBool
1596nssToken_IsPrivateKeyAvailable (
1597  NSSToken *token,
1598  NSSCertificate *c,
1599  nssCryptokiObject *instance
1600)
1601{
1602    CK_OBJECT_CLASS theClass;
1603
1604    if (token == NULL) return PR_FALSE;
1605    if (c == NULL) return PR_FALSE;
1606
1607    theClass = CKO_PRIVATE_KEY;
1608    if (!nssSlot_IsLoggedIn(token->slot)) {
1609	theClass = CKO_PUBLIC_KEY;
1610    }
1611    if (PK11_MatchItem(token->pk11slot, instance->handle, theClass) 
1612						!= CK_

Large files files are truncated, but you can click here to view the full file