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 |