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