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