comparison nss/lib/dev/devtoken.c @ 0:1e5118fa0cb1

This is NSS with a Cmake Buildsyste To compile a static NSS library for Windows we've used the Chromium-NSS fork and added a Cmake buildsystem to compile it statically for Windows. See README.chromium for chromium changes and README.trustbridge for our modifications.
author Andre Heinecke <andre.heinecke@intevation.de>
date Mon, 28 Jul 2014 10:47:06 +0200
parents
children
comparison
equal deleted inserted replaced
-1:000000000000 0:1e5118fa0cb1
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 }
This site is hosted by Intevation GmbH (Datenschutzerklärung und Impressum | Privacy Policy and Imprint)