security/nss/lib/dev/devtoken.c

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

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

mercurial