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