Import 1.9b4 NSS tag from cvs
[mozilla-nss.git] / security / nss / lib / dev / devtoken.c
blobfb1f9bf7da415e501f4ae43e66e939bd19a6eca4
1 /* ***** BEGIN LICENSE BLOCK *****
2 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4 * The contents of this file are subject to the Mozilla Public License Version
5 * 1.1 (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 * http://www.mozilla.org/MPL/
9 * Software distributed under the License is distributed on an "AS IS" basis,
10 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
11 * for the specific language governing rights and limitations under the
12 * License.
14 * The Original Code is the Netscape security libraries.
16 * The Initial Developer of the Original Code is
17 * Netscape Communications Corporation.
18 * Portions created by the Initial Developer are Copyright (C) 1994-2000
19 * the Initial Developer. All Rights Reserved.
21 * Contributor(s):
23 * Alternatively, the contents of this file may be used under the terms of
24 * either the GNU General Public License Version 2 or later (the "GPL"), or
25 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
26 * in which case the provisions of the GPL or the LGPL are applicable instead
27 * of those above. If you wish to allow use of your version of this file only
28 * under the terms of either the GPL or the LGPL, and not to allow others to
29 * use your version of this file under the terms of the MPL, indicate your
30 * decision by deleting the provisions above and replace them with the notice
31 * and other provisions required by the GPL or the LGPL. If you do not delete
32 * the provisions above, a recipient may use your version of this file under
33 * the terms of any one of the MPL, the GPL or the LGPL.
35 * ***** END LICENSE BLOCK ***** */
37 #ifdef DEBUG
38 static const char CVS_ID[] = "@(#) $RCSfile: devtoken.c,v $ $Revision: 1.43 $ $Date: 2008/02/05 03:22:38 $";
39 #endif /* DEBUG */
41 #ifndef NSSCKEPV_H
42 #include "nssckepv.h"
43 #endif /* NSSCKEPV_H */
45 #ifndef DEVM_H
46 #include "devm.h"
47 #endif /* DEVM_H */
49 #ifndef CKHELPER_H
50 #include "ckhelper.h"
51 #endif /* CKHELPER_H */
53 #include "pk11func.h"
54 #include "dev3hack.h"
55 #include "secerr.h"
57 extern const NSSError NSS_ERROR_NOT_FOUND;
58 extern const NSSError NSS_ERROR_INVALID_ARGUMENT;
59 extern const NSSError NSS_ERROR_PKCS11;
61 /* The number of object handles to grab during each call to C_FindObjects */
62 #define OBJECT_STACK_SIZE 16
64 NSS_IMPLEMENT PRStatus
65 nssToken_Destroy (
66 NSSToken *tok
69 if (tok) {
70 if (PR_AtomicDecrement(&tok->base.refCount) == 0) {
71 PZ_DestroyLock(tok->base.lock);
72 nssTokenObjectCache_Destroy(tok->cache);
73 return nssArena_Destroy(tok->base.arena);
76 return PR_SUCCESS;
79 NSS_IMPLEMENT void
80 nssToken_Remove (
81 NSSToken *tok
84 nssTokenObjectCache_Clear(tok->cache);
87 NSS_IMPLEMENT void
88 NSSToken_Destroy (
89 NSSToken *tok
92 (void)nssToken_Destroy(tok);
95 NSS_IMPLEMENT NSSToken *
96 nssToken_AddRef (
97 NSSToken *tok
100 PR_AtomicIncrement(&tok->base.refCount);
101 return tok;
104 NSS_IMPLEMENT NSSSlot *
105 nssToken_GetSlot (
106 NSSToken *tok
109 return nssSlot_AddRef(tok->slot);
112 NSS_IMPLEMENT void *
113 nssToken_GetCryptokiEPV (
114 NSSToken *token
117 return nssSlot_GetCryptokiEPV(token->slot);
120 NSS_IMPLEMENT nssSession *
121 nssToken_GetDefaultSession (
122 NSSToken *token
125 return token->defaultSession;
128 NSS_IMPLEMENT NSSUTF8 *
129 nssToken_GetName (
130 NSSToken *tok
133 if (tok == NULL) {
134 return "";
136 if (tok->base.name[0] == 0) {
137 (void) nssSlot_IsTokenPresent(tok->slot);
139 return tok->base.name;
142 NSS_IMPLEMENT NSSUTF8 *
143 NSSToken_GetName (
144 NSSToken *token
147 return nssToken_GetName(token);
150 NSS_IMPLEMENT PRBool
151 nssToken_IsLoginRequired (
152 NSSToken *token
155 return (token->ckFlags & CKF_LOGIN_REQUIRED);
158 NSS_IMPLEMENT PRBool
159 nssToken_NeedsPINInitialization (
160 NSSToken *token
163 return (!(token->ckFlags & CKF_USER_PIN_INITIALIZED));
166 NSS_IMPLEMENT PRStatus
167 nssToken_DeleteStoredObject (
168 nssCryptokiObject *instance
171 CK_RV ckrv;
172 PRStatus status;
173 PRBool createdSession = PR_FALSE;
174 NSSToken *token = instance->token;
175 nssSession *session = NULL;
176 void *epv = nssToken_GetCryptokiEPV(instance->token);
177 if (token->cache) {
178 nssTokenObjectCache_RemoveObject(token->cache, instance);
180 if (instance->isTokenObject) {
181 if (nssSession_IsReadWrite(token->defaultSession)) {
182 session = token->defaultSession;
183 } else {
184 session = nssSlot_CreateSession(token->slot, NULL, PR_TRUE);
185 createdSession = PR_TRUE;
188 if (session == NULL) {
189 return PR_FAILURE;
191 nssSession_EnterMonitor(session);
192 ckrv = CKAPI(epv)->C_DestroyObject(session->handle, instance->handle);
193 nssSession_ExitMonitor(session);
194 if (createdSession) {
195 nssSession_Destroy(session);
197 status = PR_SUCCESS;
198 if (ckrv != CKR_OK) {
199 status = PR_FAILURE;
200 /* use the error stack to pass the PKCS #11 error out */
201 nss_SetError(ckrv);
202 nss_SetError(NSS_ERROR_PKCS11);
204 return status;
207 static nssCryptokiObject *
208 import_object (
209 NSSToken *tok,
210 nssSession *sessionOpt,
211 CK_ATTRIBUTE_PTR objectTemplate,
212 CK_ULONG otsize
215 nssSession *session = NULL;
216 PRBool createdSession = PR_FALSE;
217 nssCryptokiObject *object = NULL;
218 CK_OBJECT_HANDLE handle;
219 CK_RV ckrv;
220 void *epv = nssToken_GetCryptokiEPV(tok);
221 if (nssCKObject_IsTokenObjectTemplate(objectTemplate, otsize)) {
222 if (sessionOpt) {
223 if (!nssSession_IsReadWrite(sessionOpt)) {
224 nss_SetError(NSS_ERROR_INVALID_ARGUMENT);
225 return NULL;
226 } else {
227 session = sessionOpt;
229 } else if (nssSession_IsReadWrite(tok->defaultSession)) {
230 session = tok->defaultSession;
231 } else {
232 session = nssSlot_CreateSession(tok->slot, NULL, PR_TRUE);
233 createdSession = PR_TRUE;
235 } else {
236 session = (sessionOpt) ? sessionOpt : tok->defaultSession;
238 if (session == NULL) {
239 nss_SetError(NSS_ERROR_INVALID_ARGUMENT);
240 return NULL;
242 nssSession_EnterMonitor(session);
243 ckrv = CKAPI(epv)->C_CreateObject(session->handle,
244 objectTemplate, otsize,
245 &handle);
246 nssSession_ExitMonitor(session);
247 if (ckrv == CKR_OK) {
248 object = nssCryptokiObject_Create(tok, session, handle);
249 } else {
250 nss_SetError(ckrv);
251 nss_SetError(NSS_ERROR_PKCS11);
253 if (createdSession) {
254 nssSession_Destroy(session);
256 return object;
259 static nssCryptokiObject **
260 create_objects_from_handles (
261 NSSToken *tok,
262 nssSession *session,
263 CK_OBJECT_HANDLE *handles,
264 PRUint32 numH
267 nssCryptokiObject **objects;
268 objects = nss_ZNEWARRAY(NULL, nssCryptokiObject *, numH + 1);
269 if (objects) {
270 PRInt32 i;
271 for (i=0; i<(PRInt32)numH; i++) {
272 objects[i] = nssCryptokiObject_Create(tok, session, handles[i]);
273 if (!objects[i]) {
274 for (--i; i>0; --i) {
275 nssCryptokiObject_Destroy(objects[i]);
277 nss_ZFreeIf(objects);
278 objects = NULL;
279 break;
283 return objects;
286 static nssCryptokiObject **
287 find_objects (
288 NSSToken *tok,
289 nssSession *sessionOpt,
290 CK_ATTRIBUTE_PTR obj_template,
291 CK_ULONG otsize,
292 PRUint32 maximumOpt,
293 PRStatus *statusOpt
296 CK_RV ckrv = CKR_OK;
297 CK_ULONG count;
298 CK_OBJECT_HANDLE *objectHandles;
299 CK_OBJECT_HANDLE staticObjects[OBJECT_STACK_SIZE];
300 PRUint32 arraySize, numHandles;
301 void *epv = nssToken_GetCryptokiEPV(tok);
302 nssCryptokiObject **objects;
303 nssSession *session = (sessionOpt) ? sessionOpt : tok->defaultSession;
305 /* the arena is only for the array of object handles */
306 if (maximumOpt > 0) {
307 arraySize = maximumOpt;
308 } else {
309 arraySize = OBJECT_STACK_SIZE;
311 numHandles = 0;
312 if (arraySize <= OBJECT_STACK_SIZE) {
313 objectHandles = staticObjects;
314 } else {
315 objectHandles = nss_ZNEWARRAY(NULL, CK_OBJECT_HANDLE, arraySize);
317 if (!objectHandles) {
318 ckrv = CKR_HOST_MEMORY;
319 goto loser;
321 nssSession_EnterMonitor(session); /* ==== session lock === */
322 /* Initialize the find with the template */
323 ckrv = CKAPI(epv)->C_FindObjectsInit(session->handle,
324 obj_template, otsize);
325 if (ckrv != CKR_OK) {
326 nssSession_ExitMonitor(session);
327 goto loser;
329 while (PR_TRUE) {
330 /* Issue the find for up to arraySize - numHandles objects */
331 ckrv = CKAPI(epv)->C_FindObjects(session->handle,
332 objectHandles + numHandles,
333 arraySize - numHandles,
334 &count);
335 if (ckrv != CKR_OK) {
336 nssSession_ExitMonitor(session);
337 goto loser;
339 /* bump the number of found objects */
340 numHandles += count;
341 if (maximumOpt > 0 || numHandles < arraySize) {
342 /* When a maximum is provided, the search is done all at once,
343 * so the search is finished. If the number returned was less
344 * than the number sought, the search is finished.
346 break;
348 /* the array is filled, double it and continue */
349 arraySize *= 2;
350 if (objectHandles == staticObjects) {
351 objectHandles = nss_ZNEWARRAY(NULL,CK_OBJECT_HANDLE, arraySize);
352 if (objectHandles) {
353 PORT_Memcpy(objectHandles, staticObjects,
354 OBJECT_STACK_SIZE * sizeof(objectHandles[1]));
356 } else {
357 objectHandles = nss_ZREALLOCARRAY(objectHandles,
358 CK_OBJECT_HANDLE,
359 arraySize);
361 if (!objectHandles) {
362 nssSession_ExitMonitor(session);
363 ckrv = CKR_HOST_MEMORY;
364 goto loser;
367 ckrv = CKAPI(epv)->C_FindObjectsFinal(session->handle);
368 nssSession_ExitMonitor(session); /* ==== end session lock === */
369 if (ckrv != CKR_OK) {
370 goto loser;
372 if (numHandles > 0) {
373 objects = create_objects_from_handles(tok, session,
374 objectHandles, numHandles);
375 } else {
376 nss_SetError(NSS_ERROR_NOT_FOUND);
377 objects = NULL;
379 if (objectHandles && objectHandles != staticObjects) {
380 nss_ZFreeIf(objectHandles);
382 if (statusOpt) *statusOpt = PR_SUCCESS;
383 return objects;
384 loser:
385 if (objectHandles && objectHandles != staticObjects) {
386 nss_ZFreeIf(objectHandles);
389 * These errors should be treated the same as if the objects just weren't
390 * found..
392 if ((ckrv == CKR_ATTRIBUTE_TYPE_INVALID) ||
393 (ckrv == CKR_ATTRIBUTE_VALUE_INVALID) ||
394 (ckrv == CKR_DATA_INVALID) ||
395 (ckrv == CKR_DATA_LEN_RANGE) ||
396 (ckrv == CKR_FUNCTION_NOT_SUPPORTED) ||
397 (ckrv == CKR_TEMPLATE_INCOMPLETE) ||
398 (ckrv == CKR_TEMPLATE_INCONSISTENT)) {
400 nss_SetError(NSS_ERROR_NOT_FOUND);
401 if (statusOpt) *statusOpt = PR_SUCCESS;
402 } else {
403 nss_SetError(ckrv);
404 nss_SetError(NSS_ERROR_PKCS11);
405 if (statusOpt) *statusOpt = PR_FAILURE;
407 return (nssCryptokiObject **)NULL;
410 static nssCryptokiObject **
411 find_objects_by_template (
412 NSSToken *token,
413 nssSession *sessionOpt,
414 CK_ATTRIBUTE_PTR obj_template,
415 CK_ULONG otsize,
416 PRUint32 maximumOpt,
417 PRStatus *statusOpt
420 CK_OBJECT_CLASS objclass = (CK_OBJECT_CLASS)-1;
421 nssCryptokiObject **objects = NULL;
422 PRUint32 i;
423 for (i=0; i<otsize; i++) {
424 if (obj_template[i].type == CKA_CLASS) {
425 objclass = *(CK_OBJECT_CLASS *)obj_template[i].pValue;
426 break;
429 PR_ASSERT(i < otsize);
430 if (i == otsize) {
431 PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
432 if (statusOpt) *statusOpt = PR_FAILURE;
433 return NULL;
435 /* If these objects are being cached, try looking there first */
436 if (token->cache &&
437 nssTokenObjectCache_HaveObjectClass(token->cache, objclass))
439 PRStatus status;
440 objects = nssTokenObjectCache_FindObjectsByTemplate(token->cache,
441 objclass,
442 obj_template,
443 otsize,
444 maximumOpt,
445 &status);
446 if (status == PR_SUCCESS) {
447 if (statusOpt) *statusOpt = status;
448 return objects;
451 /* Either they are not cached, or cache failed; look on token. */
452 objects = find_objects(token, sessionOpt,
453 obj_template, otsize,
454 maximumOpt, statusOpt);
455 return objects;
458 extern const NSSError NSS_ERROR_INVALID_CERTIFICATE;
460 NSS_IMPLEMENT nssCryptokiObject *
461 nssToken_ImportCertificate (
462 NSSToken *tok,
463 nssSession *sessionOpt,
464 NSSCertificateType certType,
465 NSSItem *id,
466 NSSUTF8 *nickname,
467 NSSDER *encoding,
468 NSSDER *issuer,
469 NSSDER *subject,
470 NSSDER *serial,
471 NSSASCII7 *email,
472 PRBool asTokenObject
475 PRStatus status;
476 CK_CERTIFICATE_TYPE cert_type;
477 CK_ATTRIBUTE_PTR attr;
478 CK_ATTRIBUTE cert_tmpl[10];
479 CK_ULONG ctsize;
480 nssTokenSearchType searchType;
481 nssCryptokiObject *rvObject = NULL;
483 if (certType == NSSCertificateType_PKIX) {
484 cert_type = CKC_X_509;
485 } else {
486 return (nssCryptokiObject *)NULL;
488 NSS_CK_TEMPLATE_START(cert_tmpl, attr, ctsize);
489 if (asTokenObject) {
490 NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_true);
491 searchType = nssTokenSearchType_TokenOnly;
492 } else {
493 NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_false);
494 searchType = nssTokenSearchType_SessionOnly;
496 NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_CLASS, &g_ck_class_cert);
497 NSS_CK_SET_ATTRIBUTE_VAR( attr, CKA_CERTIFICATE_TYPE, cert_type);
498 NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_ID, id);
499 NSS_CK_SET_ATTRIBUTE_UTF8(attr, CKA_LABEL, nickname);
500 NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_VALUE, encoding);
501 NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_ISSUER, issuer);
502 NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_SUBJECT, subject);
503 NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_SERIAL_NUMBER, serial);
504 if (email) {
505 NSS_CK_SET_ATTRIBUTE_UTF8(attr, CKA_NETSCAPE_EMAIL, email);
507 NSS_CK_TEMPLATE_FINISH(cert_tmpl, attr, ctsize);
508 /* see if the cert is already there */
509 rvObject = nssToken_FindCertificateByIssuerAndSerialNumber(tok,
510 sessionOpt,
511 issuer,
512 serial,
513 searchType,
514 NULL);
515 if (rvObject) {
516 NSSItem existingDER;
517 NSSSlot *slot = nssToken_GetSlot(tok);
518 nssSession *session = nssSlot_CreateSession(slot, NULL, PR_TRUE);
519 if (!session) {
520 nssCryptokiObject_Destroy(rvObject);
521 nssSlot_Destroy(slot);
522 return (nssCryptokiObject *)NULL;
524 /* Reject any attempt to import a new cert that has the same
525 * issuer/serial as an existing cert, but does not have the
526 * same encoding
528 NSS_CK_TEMPLATE_START(cert_tmpl, attr, ctsize);
529 NSS_CK_SET_ATTRIBUTE_NULL(attr, CKA_VALUE);
530 NSS_CK_TEMPLATE_FINISH(cert_tmpl, attr, ctsize);
531 status = nssCKObject_GetAttributes(rvObject->handle,
532 cert_tmpl, ctsize, NULL,
533 session, slot);
534 NSS_CK_ATTRIBUTE_TO_ITEM(cert_tmpl, &existingDER);
535 if (status == PR_SUCCESS) {
536 if (!nssItem_Equal(encoding, &existingDER, NULL)) {
537 nss_SetError(NSS_ERROR_INVALID_CERTIFICATE);
538 status = PR_FAILURE;
540 nss_ZFreeIf(existingDER.data);
542 if (status == PR_FAILURE) {
543 nssCryptokiObject_Destroy(rvObject);
544 nssSession_Destroy(session);
545 nssSlot_Destroy(slot);
546 return (nssCryptokiObject *)NULL;
548 /* according to PKCS#11, label, ID, issuer, and serial number
549 * may change after the object has been created. For PKIX, the
550 * last two attributes can't change, so for now we'll only worry
551 * about the first two.
553 NSS_CK_TEMPLATE_START(cert_tmpl, attr, ctsize);
554 NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_ID, id);
555 NSS_CK_SET_ATTRIBUTE_UTF8(attr, CKA_LABEL, nickname);
556 NSS_CK_TEMPLATE_FINISH(cert_tmpl, attr, ctsize);
557 /* reset the mutable attributes on the token */
558 nssCKObject_SetAttributes(rvObject->handle,
559 cert_tmpl, ctsize,
560 session, slot);
561 if (!rvObject->label && nickname) {
562 rvObject->label = nssUTF8_Duplicate(nickname, NULL);
564 nssSession_Destroy(session);
565 nssSlot_Destroy(slot);
566 } else {
567 /* Import the certificate onto the token */
568 rvObject = import_object(tok, sessionOpt, cert_tmpl, ctsize);
570 if (rvObject && tok->cache) {
571 /* The cache will overwrite the attributes if the object already
572 * exists.
574 nssTokenObjectCache_ImportObject(tok->cache, rvObject,
575 CKO_CERTIFICATE,
576 cert_tmpl, ctsize);
578 return rvObject;
581 /* traverse all certificates - this should only happen if the token
582 * has been marked as "traversable"
584 NSS_IMPLEMENT nssCryptokiObject **
585 nssToken_FindCertificates (
586 NSSToken *token,
587 nssSession *sessionOpt,
588 nssTokenSearchType searchType,
589 PRUint32 maximumOpt,
590 PRStatus *statusOpt
593 CK_ATTRIBUTE_PTR attr;
594 CK_ATTRIBUTE cert_template[2];
595 CK_ULONG ctsize;
596 nssCryptokiObject **objects;
597 NSS_CK_TEMPLATE_START(cert_template, attr, ctsize);
598 /* Set the search to token/session only if provided */
599 if (searchType == nssTokenSearchType_SessionOnly) {
600 NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_false);
601 } else if (searchType == nssTokenSearchType_TokenOnly ||
602 searchType == nssTokenSearchType_TokenForced) {
603 NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_true);
605 NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_CLASS, &g_ck_class_cert);
606 NSS_CK_TEMPLATE_FINISH(cert_template, attr, ctsize);
608 if (searchType == nssTokenSearchType_TokenForced) {
609 objects = find_objects(token, sessionOpt,
610 cert_template, ctsize,
611 maximumOpt, statusOpt);
612 } else {
613 objects = find_objects_by_template(token, sessionOpt,
614 cert_template, ctsize,
615 maximumOpt, statusOpt);
617 return objects;
620 NSS_IMPLEMENT nssCryptokiObject **
621 nssToken_FindCertificatesBySubject (
622 NSSToken *token,
623 nssSession *sessionOpt,
624 NSSDER *subject,
625 nssTokenSearchType searchType,
626 PRUint32 maximumOpt,
627 PRStatus *statusOpt
630 CK_ATTRIBUTE_PTR attr;
631 CK_ATTRIBUTE subj_template[3];
632 CK_ULONG stsize;
633 nssCryptokiObject **objects;
634 NSS_CK_TEMPLATE_START(subj_template, attr, stsize);
635 /* Set the search to token/session only if provided */
636 if (searchType == nssTokenSearchType_SessionOnly) {
637 NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_false);
638 } else if (searchType == nssTokenSearchType_TokenOnly) {
639 NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_true);
641 NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_CLASS, &g_ck_class_cert);
642 NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_SUBJECT, subject);
643 NSS_CK_TEMPLATE_FINISH(subj_template, attr, stsize);
644 /* now locate the token certs matching this template */
645 objects = find_objects_by_template(token, sessionOpt,
646 subj_template, stsize,
647 maximumOpt, statusOpt);
648 return objects;
651 NSS_IMPLEMENT nssCryptokiObject **
652 nssToken_FindCertificatesByNickname (
653 NSSToken *token,
654 nssSession *sessionOpt,
655 const NSSUTF8 *name,
656 nssTokenSearchType searchType,
657 PRUint32 maximumOpt,
658 PRStatus *statusOpt
661 CK_ATTRIBUTE_PTR attr;
662 CK_ATTRIBUTE nick_template[3];
663 CK_ULONG ntsize;
664 nssCryptokiObject **objects;
665 NSS_CK_TEMPLATE_START(nick_template, attr, ntsize);
666 NSS_CK_SET_ATTRIBUTE_UTF8(attr, CKA_LABEL, name);
667 /* Set the search to token/session only if provided */
668 if (searchType == nssTokenSearchType_SessionOnly) {
669 NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_false);
670 } else if (searchType == nssTokenSearchType_TokenOnly) {
671 NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_true);
673 NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_CLASS, &g_ck_class_cert);
674 NSS_CK_TEMPLATE_FINISH(nick_template, attr, ntsize);
675 /* now locate the token certs matching this template */
676 objects = find_objects_by_template(token, sessionOpt,
677 nick_template, ntsize,
678 maximumOpt, statusOpt);
679 if (!objects) {
680 /* This is to workaround the fact that PKCS#11 doesn't specify
681 * whether the '\0' should be included. XXX Is that still true?
682 * im - this is not needed by the current softoken. However, I'm
683 * leaving it in until I have surveyed more tokens to see if it needed.
684 * well, its needed by the builtin token...
686 nick_template[0].ulValueLen++;
687 objects = find_objects_by_template(token, sessionOpt,
688 nick_template, ntsize,
689 maximumOpt, statusOpt);
691 return objects;
694 /* XXX
695 * This function *does not* use the token object cache, because not even
696 * the softoken will return a value for CKA_NETSCAPE_EMAIL from a call
697 * to GetAttributes. The softoken does allow searches with that attribute,
698 * it just won't return a value for it.
700 NSS_IMPLEMENT nssCryptokiObject **
701 nssToken_FindCertificatesByEmail (
702 NSSToken *token,
703 nssSession *sessionOpt,
704 NSSASCII7 *email,
705 nssTokenSearchType searchType,
706 PRUint32 maximumOpt,
707 PRStatus *statusOpt
710 CK_ATTRIBUTE_PTR attr;
711 CK_ATTRIBUTE email_template[3];
712 CK_ULONG etsize;
713 nssCryptokiObject **objects;
714 NSS_CK_TEMPLATE_START(email_template, attr, etsize);
715 NSS_CK_SET_ATTRIBUTE_UTF8(attr, CKA_NETSCAPE_EMAIL, email);
716 /* Set the search to token/session only if provided */
717 if (searchType == nssTokenSearchType_SessionOnly) {
718 NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_false);
719 } else if (searchType == nssTokenSearchType_TokenOnly) {
720 NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_true);
722 NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_CLASS, &g_ck_class_cert);
723 NSS_CK_TEMPLATE_FINISH(email_template, attr, etsize);
724 /* now locate the token certs matching this template */
725 objects = find_objects(token, sessionOpt,
726 email_template, etsize,
727 maximumOpt, statusOpt);
728 if (!objects) {
729 /* This is to workaround the fact that PKCS#11 doesn't specify
730 * whether the '\0' should be included. XXX Is that still true?
731 * im - this is not needed by the current softoken. However, I'm
732 * leaving it in until I have surveyed more tokens to see if it needed.
733 * well, its needed by the builtin token...
735 email_template[0].ulValueLen++;
736 objects = find_objects(token, sessionOpt,
737 email_template, etsize,
738 maximumOpt, statusOpt);
740 return objects;
743 NSS_IMPLEMENT nssCryptokiObject **
744 nssToken_FindCertificatesByID (
745 NSSToken *token,
746 nssSession *sessionOpt,
747 NSSItem *id,
748 nssTokenSearchType searchType,
749 PRUint32 maximumOpt,
750 PRStatus *statusOpt
753 CK_ATTRIBUTE_PTR attr;
754 CK_ATTRIBUTE id_template[3];
755 CK_ULONG idtsize;
756 nssCryptokiObject **objects;
757 NSS_CK_TEMPLATE_START(id_template, attr, idtsize);
758 NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_ID, id);
759 /* Set the search to token/session only if provided */
760 if (searchType == nssTokenSearchType_SessionOnly) {
761 NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_false);
762 } else if (searchType == nssTokenSearchType_TokenOnly) {
763 NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_true);
765 NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_CLASS, &g_ck_class_cert);
766 NSS_CK_TEMPLATE_FINISH(id_template, attr, idtsize);
767 /* now locate the token certs matching this template */
768 objects = find_objects_by_template(token, sessionOpt,
769 id_template, idtsize,
770 maximumOpt, statusOpt);
771 return objects;
775 * decode the serial item and return our result.
776 * NOTE serialDecode's data is really stored in serial. Don't free it.
778 static PRStatus
779 nssToken_decodeSerialItem(NSSItem *serial, NSSItem *serialDecode)
781 unsigned char *data = (unsigned char *)serial->data;
782 int data_left, data_len, index;
784 if ((serial->size >= 3) && (data[0] == 0x2)) {
785 /* remove the der encoding of the serial number before generating the
786 * key.. */
787 data_left = serial->size-2;
788 data_len = data[1];
789 index = 2;
791 /* extended length ? (not very likely for a serial number) */
792 if (data_len & 0x80) {
793 int len_count = data_len & 0x7f;
795 data_len = 0;
796 data_left -= len_count;
797 if (data_left > 0) {
798 while (len_count --) {
799 data_len = (data_len << 8) | data[index++];
803 /* XXX leaving any leading zeros on the serial number for backwards
804 * compatibility
806 /* not a valid der, must be just an unlucky serial number value */
807 if (data_len == data_left) {
808 serialDecode->size = data_len;
809 serialDecode->data = &data[index];
810 return PR_SUCCESS;
813 return PR_FAILURE;
816 NSS_IMPLEMENT nssCryptokiObject *
817 nssToken_FindCertificateByIssuerAndSerialNumber (
818 NSSToken *token,
819 nssSession *sessionOpt,
820 NSSDER *issuer,
821 NSSDER *serial,
822 nssTokenSearchType searchType,
823 PRStatus *statusOpt
826 CK_ATTRIBUTE_PTR attr;
827 CK_ATTRIBUTE_PTR serialAttr;
828 CK_ATTRIBUTE cert_template[4];
829 CK_ULONG ctsize;
830 nssCryptokiObject **objects;
831 nssCryptokiObject *rvObject = NULL;
832 NSS_CK_TEMPLATE_START(cert_template, attr, ctsize);
833 /* Set the search to token/session only if provided */
834 if (searchType == nssTokenSearchType_SessionOnly) {
835 NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_false);
836 } else if ((searchType == nssTokenSearchType_TokenOnly) ||
837 (searchType == nssTokenSearchType_TokenForced)) {
838 NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_true);
840 /* Set the unique id */
841 NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_CLASS, &g_ck_class_cert);
842 NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_ISSUER, issuer);
843 serialAttr = attr;
844 NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_SERIAL_NUMBER, serial);
845 NSS_CK_TEMPLATE_FINISH(cert_template, attr, ctsize);
846 /* get the object handle */
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);
856 if (objects) {
857 rvObject = objects[0];
858 nss_ZFreeIf(objects);
862 * NSS used to incorrectly store serial numbers in their decoded form.
863 * because of this old tokens have decoded serial numbers.
865 if (!objects) {
866 NSSItem serialDecode;
867 PRStatus status;
869 status = nssToken_decodeSerialItem(serial, &serialDecode);
870 if (status != PR_SUCCESS) {
871 return NULL;
873 NSS_CK_SET_ATTRIBUTE_ITEM(serialAttr,CKA_SERIAL_NUMBER,&serialDecode);
874 if (searchType == nssTokenSearchType_TokenForced) {
875 objects = find_objects(token, sessionOpt,
876 cert_template, ctsize,
877 1, statusOpt);
878 } else {
879 objects = find_objects_by_template(token, sessionOpt,
880 cert_template, ctsize,
881 1, statusOpt);
883 if (objects) {
884 rvObject = objects[0];
885 nss_ZFreeIf(objects);
888 return rvObject;
891 NSS_IMPLEMENT nssCryptokiObject *
892 nssToken_FindCertificateByEncodedCertificate (
893 NSSToken *token,
894 nssSession *sessionOpt,
895 NSSBER *encodedCertificate,
896 nssTokenSearchType searchType,
897 PRStatus *statusOpt
900 CK_ATTRIBUTE_PTR attr;
901 CK_ATTRIBUTE cert_template[3];
902 CK_ULONG ctsize;
903 nssCryptokiObject **objects;
904 nssCryptokiObject *rvObject = NULL;
905 NSS_CK_TEMPLATE_START(cert_template, attr, ctsize);
906 /* Set the search to token/session only if provided */
907 if (searchType == nssTokenSearchType_SessionOnly) {
908 NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_false);
909 } else if (searchType == nssTokenSearchType_TokenOnly) {
910 NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_true);
912 NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_CLASS, &g_ck_class_cert);
913 NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_VALUE, encodedCertificate);
914 NSS_CK_TEMPLATE_FINISH(cert_template, attr, ctsize);
915 /* get the object handle */
916 objects = find_objects_by_template(token, sessionOpt,
917 cert_template, ctsize,
918 1, statusOpt);
919 if (objects) {
920 rvObject = objects[0];
921 nss_ZFreeIf(objects);
923 return rvObject;
926 NSS_IMPLEMENT nssCryptokiObject **
927 nssToken_FindPrivateKeys (
928 NSSToken *token,
929 nssSession *sessionOpt,
930 nssTokenSearchType searchType,
931 PRUint32 maximumOpt,
932 PRStatus *statusOpt
935 CK_ATTRIBUTE_PTR attr;
936 CK_ATTRIBUTE key_template[2];
937 CK_ULONG ktsize;
938 nssCryptokiObject **objects;
940 NSS_CK_TEMPLATE_START(key_template, attr, ktsize);
941 NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_CLASS, &g_ck_class_privkey);
942 if (searchType == nssTokenSearchType_SessionOnly) {
943 NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_false);
944 } else if (searchType == nssTokenSearchType_TokenOnly) {
945 NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_true);
947 NSS_CK_TEMPLATE_FINISH(key_template, attr, ktsize);
949 objects = find_objects_by_template(token, sessionOpt,
950 key_template, ktsize,
951 maximumOpt, statusOpt);
952 return objects;
955 /* XXX ?there are no session cert objects, so only search token objects */
956 NSS_IMPLEMENT nssCryptokiObject *
957 nssToken_FindPrivateKeyByID (
958 NSSToken *token,
959 nssSession *sessionOpt,
960 NSSItem *keyID
963 CK_ATTRIBUTE_PTR attr;
964 CK_ATTRIBUTE key_template[3];
965 CK_ULONG ktsize;
966 nssCryptokiObject **objects;
967 nssCryptokiObject *rvKey = NULL;
969 NSS_CK_TEMPLATE_START(key_template, attr, ktsize);
970 NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_CLASS, &g_ck_class_privkey);
971 NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_true);
972 NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_ID, keyID);
973 NSS_CK_TEMPLATE_FINISH(key_template, attr, ktsize);
975 objects = find_objects_by_template(token, sessionOpt,
976 key_template, ktsize,
977 1, NULL);
978 if (objects) {
979 rvKey = objects[0];
980 nss_ZFreeIf(objects);
982 return rvKey;
985 /* XXX ?there are no session cert objects, so only search token objects */
986 NSS_IMPLEMENT nssCryptokiObject *
987 nssToken_FindPublicKeyByID (
988 NSSToken *token,
989 nssSession *sessionOpt,
990 NSSItem *keyID
993 CK_ATTRIBUTE_PTR attr;
994 CK_ATTRIBUTE key_template[3];
995 CK_ULONG ktsize;
996 nssCryptokiObject **objects;
997 nssCryptokiObject *rvKey = NULL;
999 NSS_CK_TEMPLATE_START(key_template, attr, ktsize);
1000 NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_CLASS, &g_ck_class_pubkey);
1001 NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_true);
1002 NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_ID, keyID);
1003 NSS_CK_TEMPLATE_FINISH(key_template, attr, ktsize);
1005 objects = find_objects_by_template(token, sessionOpt,
1006 key_template, ktsize,
1007 1, NULL);
1008 if (objects) {
1009 rvKey = objects[0];
1010 nss_ZFreeIf(objects);
1012 return rvKey;
1015 static void
1016 sha1_hash(NSSItem *input, NSSItem *output)
1018 NSSAlgorithmAndParameters *ap;
1019 PK11SlotInfo *internal = PK11_GetInternalSlot();
1020 NSSToken *token = PK11Slot_GetNSSToken(internal);
1021 ap = NSSAlgorithmAndParameters_CreateSHA1Digest(NULL);
1022 (void)nssToken_Digest(token, NULL, ap, input, output, NULL);
1023 PK11_FreeSlot(token->pk11slot);
1024 nss_ZFreeIf(ap);
1027 static void
1028 md5_hash(NSSItem *input, NSSItem *output)
1030 NSSAlgorithmAndParameters *ap;
1031 PK11SlotInfo *internal = PK11_GetInternalSlot();
1032 NSSToken *token = PK11Slot_GetNSSToken(internal);
1033 ap = NSSAlgorithmAndParameters_CreateMD5Digest(NULL);
1034 (void)nssToken_Digest(token, NULL, ap, input, output, NULL);
1035 PK11_FreeSlot(token->pk11slot);
1036 nss_ZFreeIf(ap);
1039 static CK_TRUST
1040 get_ck_trust (
1041 nssTrustLevel nssTrust
1044 CK_TRUST t;
1045 switch (nssTrust) {
1046 case nssTrustLevel_NotTrusted: t = CKT_NETSCAPE_UNTRUSTED; break;
1047 case nssTrustLevel_TrustedDelegator: t = CKT_NETSCAPE_TRUSTED_DELEGATOR;
1048 break;
1049 case nssTrustLevel_ValidDelegator: t = CKT_NETSCAPE_VALID_DELEGATOR; break;
1050 case nssTrustLevel_Trusted: t = CKT_NETSCAPE_TRUSTED; break;
1051 case nssTrustLevel_Valid: t = CKT_NETSCAPE_VALID; break;
1052 case nssTrustLevel_Unknown:
1053 default: t = CKT_NETSCAPE_TRUST_UNKNOWN; break;
1055 return t;
1058 NSS_IMPLEMENT nssCryptokiObject *
1059 nssToken_ImportTrust (
1060 NSSToken *tok,
1061 nssSession *sessionOpt,
1062 NSSDER *certEncoding,
1063 NSSDER *certIssuer,
1064 NSSDER *certSerial,
1065 nssTrustLevel serverAuth,
1066 nssTrustLevel clientAuth,
1067 nssTrustLevel codeSigning,
1068 nssTrustLevel emailProtection,
1069 PRBool stepUpApproved,
1070 PRBool asTokenObject
1073 nssCryptokiObject *object;
1074 CK_OBJECT_CLASS tobjc = CKO_NETSCAPE_TRUST;
1075 CK_TRUST ckSA, ckCA, ckCS, ckEP;
1076 CK_ATTRIBUTE_PTR attr;
1077 CK_ATTRIBUTE trust_tmpl[11];
1078 CK_ULONG tsize;
1079 PRUint8 sha1[20]; /* this is cheating... */
1080 PRUint8 md5[16];
1081 NSSItem sha1_result, md5_result;
1082 sha1_result.data = sha1; sha1_result.size = sizeof sha1;
1083 md5_result.data = md5; md5_result.size = sizeof md5;
1084 sha1_hash(certEncoding, &sha1_result);
1085 md5_hash(certEncoding, &md5_result);
1086 ckSA = get_ck_trust(serverAuth);
1087 ckCA = get_ck_trust(clientAuth);
1088 ckCS = get_ck_trust(codeSigning);
1089 ckEP = get_ck_trust(emailProtection);
1090 NSS_CK_TEMPLATE_START(trust_tmpl, attr, tsize);
1091 if (asTokenObject) {
1092 NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_true);
1093 } else {
1094 NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_false);
1096 NSS_CK_SET_ATTRIBUTE_VAR( attr, CKA_CLASS, tobjc);
1097 NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_ISSUER, certIssuer);
1098 NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_SERIAL_NUMBER, certSerial);
1099 NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_CERT_SHA1_HASH, &sha1_result);
1100 NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_CERT_MD5_HASH, &md5_result);
1101 /* now set the trust values */
1102 NSS_CK_SET_ATTRIBUTE_VAR(attr, CKA_TRUST_SERVER_AUTH, ckSA);
1103 NSS_CK_SET_ATTRIBUTE_VAR(attr, CKA_TRUST_CLIENT_AUTH, ckCA);
1104 NSS_CK_SET_ATTRIBUTE_VAR(attr, CKA_TRUST_CODE_SIGNING, ckCS);
1105 NSS_CK_SET_ATTRIBUTE_VAR(attr, CKA_TRUST_EMAIL_PROTECTION, ckEP);
1106 if (stepUpApproved) {
1107 NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TRUST_STEP_UP_APPROVED,
1108 &g_ck_true);
1109 } else {
1110 NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TRUST_STEP_UP_APPROVED,
1111 &g_ck_false);
1113 NSS_CK_TEMPLATE_FINISH(trust_tmpl, attr, tsize);
1114 /* import the trust object onto the token */
1115 object = import_object(tok, sessionOpt, trust_tmpl, tsize);
1116 if (object && tok->cache) {
1117 nssTokenObjectCache_ImportObject(tok->cache, object, tobjc,
1118 trust_tmpl, tsize);
1120 return object;
1123 NSS_IMPLEMENT nssCryptokiObject **
1124 nssToken_FindTrustObjects (
1125 NSSToken *token,
1126 nssSession *sessionOpt,
1127 nssTokenSearchType searchType,
1128 PRUint32 maximumOpt,
1129 PRStatus *statusOpt
1132 CK_OBJECT_CLASS tobjc = CKO_NETSCAPE_TRUST;
1133 CK_ATTRIBUTE_PTR attr;
1134 CK_ATTRIBUTE tobj_template[2];
1135 CK_ULONG tobj_size;
1136 nssCryptokiObject **objects;
1137 nssSession *session = sessionOpt ? sessionOpt : token->defaultSession;
1139 NSS_CK_TEMPLATE_START(tobj_template, attr, tobj_size);
1140 if (searchType == nssTokenSearchType_SessionOnly) {
1141 NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_false);
1142 } else if (searchType == nssTokenSearchType_TokenOnly ||
1143 searchType == nssTokenSearchType_TokenForced) {
1144 NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_true);
1146 NSS_CK_SET_ATTRIBUTE_VAR( attr, CKA_CLASS, tobjc);
1147 NSS_CK_TEMPLATE_FINISH(tobj_template, attr, tobj_size);
1149 if (searchType == nssTokenSearchType_TokenForced) {
1150 objects = find_objects(token, session,
1151 tobj_template, tobj_size,
1152 maximumOpt, statusOpt);
1153 } else {
1154 objects = find_objects_by_template(token, session,
1155 tobj_template, tobj_size,
1156 maximumOpt, statusOpt);
1158 return objects;
1161 NSS_IMPLEMENT nssCryptokiObject *
1162 nssToken_FindTrustForCertificate (
1163 NSSToken *token,
1164 nssSession *sessionOpt,
1165 NSSDER *certEncoding,
1166 NSSDER *certIssuer,
1167 NSSDER *certSerial,
1168 nssTokenSearchType searchType
1171 CK_OBJECT_CLASS tobjc = CKO_NETSCAPE_TRUST;
1172 CK_ATTRIBUTE_PTR attr;
1173 CK_ATTRIBUTE tobj_template[5];
1174 CK_ULONG tobj_size;
1175 nssSession *session = sessionOpt ? sessionOpt : token->defaultSession;
1176 nssCryptokiObject *object, **objects;
1178 NSS_CK_TEMPLATE_START(tobj_template, attr, tobj_size);
1179 if (searchType == nssTokenSearchType_SessionOnly) {
1180 NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_false);
1181 } else if (searchType == nssTokenSearchType_TokenOnly) {
1182 NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_true);
1184 NSS_CK_SET_ATTRIBUTE_VAR( attr, CKA_CLASS, tobjc);
1185 NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_ISSUER, certIssuer);
1186 NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_SERIAL_NUMBER , certSerial);
1187 NSS_CK_TEMPLATE_FINISH(tobj_template, attr, tobj_size);
1188 object = NULL;
1189 objects = find_objects_by_template(token, session,
1190 tobj_template, tobj_size,
1191 1, NULL);
1192 if (objects) {
1193 object = objects[0];
1194 nss_ZFreeIf(objects);
1196 return object;
1199 NSS_IMPLEMENT nssCryptokiObject *
1200 nssToken_ImportCRL (
1201 NSSToken *token,
1202 nssSession *sessionOpt,
1203 NSSDER *subject,
1204 NSSDER *encoding,
1205 PRBool isKRL,
1206 NSSUTF8 *url,
1207 PRBool asTokenObject
1210 nssCryptokiObject *object;
1211 CK_OBJECT_CLASS crlobjc = CKO_NETSCAPE_CRL;
1212 CK_ATTRIBUTE_PTR attr;
1213 CK_ATTRIBUTE crl_tmpl[6];
1214 CK_ULONG crlsize;
1216 NSS_CK_TEMPLATE_START(crl_tmpl, attr, crlsize);
1217 if (asTokenObject) {
1218 NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_true);
1219 } else {
1220 NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_false);
1222 NSS_CK_SET_ATTRIBUTE_VAR( attr, CKA_CLASS, crlobjc);
1223 NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_SUBJECT, subject);
1224 NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_VALUE, encoding);
1225 NSS_CK_SET_ATTRIBUTE_UTF8(attr, CKA_NETSCAPE_URL, url);
1226 if (isKRL) {
1227 NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_NETSCAPE_KRL, &g_ck_true);
1228 } else {
1229 NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_NETSCAPE_KRL, &g_ck_false);
1231 NSS_CK_TEMPLATE_FINISH(crl_tmpl, attr, crlsize);
1233 /* import the crl object onto the token */
1234 object = import_object(token, sessionOpt, crl_tmpl, crlsize);
1235 if (object && token->cache) {
1236 nssTokenObjectCache_ImportObject(token->cache, object, crlobjc,
1237 crl_tmpl, crlsize);
1239 return object;
1242 NSS_IMPLEMENT nssCryptokiObject **
1243 nssToken_FindCRLs (
1244 NSSToken *token,
1245 nssSession *sessionOpt,
1246 nssTokenSearchType searchType,
1247 PRUint32 maximumOpt,
1248 PRStatus *statusOpt
1251 CK_OBJECT_CLASS crlobjc = CKO_NETSCAPE_CRL;
1252 CK_ATTRIBUTE_PTR attr;
1253 CK_ATTRIBUTE crlobj_template[2];
1254 CK_ULONG crlobj_size;
1255 nssCryptokiObject **objects;
1256 nssSession *session = sessionOpt ? sessionOpt : token->defaultSession;
1258 NSS_CK_TEMPLATE_START(crlobj_template, attr, crlobj_size);
1259 if (searchType == nssTokenSearchType_SessionOnly) {
1260 NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_false);
1261 } else if (searchType == nssTokenSearchType_TokenOnly ||
1262 searchType == nssTokenSearchType_TokenForced) {
1263 NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_true);
1265 NSS_CK_SET_ATTRIBUTE_VAR( attr, CKA_CLASS, crlobjc);
1266 NSS_CK_TEMPLATE_FINISH(crlobj_template, attr, crlobj_size);
1268 if (searchType == nssTokenSearchType_TokenForced) {
1269 objects = find_objects(token, session,
1270 crlobj_template, crlobj_size,
1271 maximumOpt, statusOpt);
1272 } else {
1273 objects = find_objects_by_template(token, session,
1274 crlobj_template, crlobj_size,
1275 maximumOpt, statusOpt);
1277 return objects;
1280 NSS_IMPLEMENT nssCryptokiObject **
1281 nssToken_FindCRLsBySubject (
1282 NSSToken *token,
1283 nssSession *sessionOpt,
1284 NSSDER *subject,
1285 nssTokenSearchType searchType,
1286 PRUint32 maximumOpt,
1287 PRStatus *statusOpt
1290 CK_OBJECT_CLASS crlobjc = CKO_NETSCAPE_CRL;
1291 CK_ATTRIBUTE_PTR attr;
1292 CK_ATTRIBUTE crlobj_template[3];
1293 CK_ULONG crlobj_size;
1294 nssCryptokiObject **objects;
1295 nssSession *session = sessionOpt ? sessionOpt : token->defaultSession;
1297 NSS_CK_TEMPLATE_START(crlobj_template, attr, crlobj_size);
1298 if (searchType == nssTokenSearchType_SessionOnly) {
1299 NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_false);
1300 } else if (searchType == nssTokenSearchType_TokenOnly ||
1301 searchType == nssTokenSearchType_TokenForced) {
1302 NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_true);
1304 NSS_CK_SET_ATTRIBUTE_VAR( attr, CKA_CLASS, crlobjc);
1305 NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_SUBJECT, subject);
1306 NSS_CK_TEMPLATE_FINISH(crlobj_template, attr, crlobj_size);
1308 objects = find_objects_by_template(token, session,
1309 crlobj_template, crlobj_size,
1310 maximumOpt, statusOpt);
1311 return objects;
1314 NSS_IMPLEMENT PRStatus
1315 nssToken_GetCachedObjectAttributes (
1316 NSSToken *token,
1317 NSSArena *arenaOpt,
1318 nssCryptokiObject *object,
1319 CK_OBJECT_CLASS objclass,
1320 CK_ATTRIBUTE_PTR atemplate,
1321 CK_ULONG atlen
1324 if (!token->cache) {
1325 return PR_FAILURE;
1327 return nssTokenObjectCache_GetObjectAttributes(token->cache, arenaOpt,
1328 object, objclass,
1329 atemplate, atlen);
1332 NSS_IMPLEMENT NSSItem *
1333 nssToken_Digest (
1334 NSSToken *tok,
1335 nssSession *sessionOpt,
1336 NSSAlgorithmAndParameters *ap,
1337 NSSItem *data,
1338 NSSItem *rvOpt,
1339 NSSArena *arenaOpt
1342 CK_RV ckrv;
1343 CK_ULONG digestLen;
1344 CK_BYTE_PTR digest;
1345 NSSItem *rvItem = NULL;
1346 void *epv = nssToken_GetCryptokiEPV(tok);
1347 nssSession *session;
1348 session = (sessionOpt) ? sessionOpt : tok->defaultSession;
1349 nssSession_EnterMonitor(session);
1350 ckrv = CKAPI(epv)->C_DigestInit(session->handle, &ap->mechanism);
1351 if (ckrv != CKR_OK) {
1352 nssSession_ExitMonitor(session);
1353 return NULL;
1355 #if 0
1356 /* XXX the standard says this should work, but it doesn't */
1357 ckrv = CKAPI(epv)->C_Digest(session->handle, NULL, 0, NULL, &digestLen);
1358 if (ckrv != CKR_OK) {
1359 nssSession_ExitMonitor(session);
1360 return NULL;
1362 #endif
1363 digestLen = 0; /* XXX for now */
1364 digest = NULL;
1365 if (rvOpt) {
1366 if (rvOpt->size > 0 && rvOpt->size < digestLen) {
1367 nssSession_ExitMonitor(session);
1368 /* the error should be bad args */
1369 return NULL;
1371 if (rvOpt->data) {
1372 digest = rvOpt->data;
1374 digestLen = rvOpt->size;
1376 if (!digest) {
1377 digest = (CK_BYTE_PTR)nss_ZAlloc(arenaOpt, digestLen);
1378 if (!digest) {
1379 nssSession_ExitMonitor(session);
1380 return NULL;
1383 ckrv = CKAPI(epv)->C_Digest(session->handle,
1384 (CK_BYTE_PTR)data->data,
1385 (CK_ULONG)data->size,
1386 (CK_BYTE_PTR)digest,
1387 &digestLen);
1388 nssSession_ExitMonitor(session);
1389 if (ckrv != CKR_OK) {
1390 nss_ZFreeIf(digest);
1391 return NULL;
1393 if (!rvOpt) {
1394 rvItem = nssItem_Create(arenaOpt, NULL, digestLen, (void *)digest);
1396 return rvItem;
1399 NSS_IMPLEMENT PRStatus
1400 nssToken_BeginDigest (
1401 NSSToken *tok,
1402 nssSession *sessionOpt,
1403 NSSAlgorithmAndParameters *ap
1406 CK_RV ckrv;
1407 nssSession *session;
1408 void *epv = nssToken_GetCryptokiEPV(tok);
1409 session = (sessionOpt) ? sessionOpt : tok->defaultSession;
1410 nssSession_EnterMonitor(session);
1411 ckrv = CKAPI(epv)->C_DigestInit(session->handle, &ap->mechanism);
1412 nssSession_ExitMonitor(session);
1413 return (ckrv == CKR_OK) ? PR_SUCCESS : PR_FAILURE;
1416 NSS_IMPLEMENT PRStatus
1417 nssToken_ContinueDigest (
1418 NSSToken *tok,
1419 nssSession *sessionOpt,
1420 NSSItem *item
1423 CK_RV ckrv;
1424 nssSession *session;
1425 void *epv = nssToken_GetCryptokiEPV(tok);
1426 session = (sessionOpt) ? sessionOpt : tok->defaultSession;
1427 nssSession_EnterMonitor(session);
1428 ckrv = CKAPI(epv)->C_DigestUpdate(session->handle,
1429 (CK_BYTE_PTR)item->data,
1430 (CK_ULONG)item->size);
1431 nssSession_ExitMonitor(session);
1432 return (ckrv == CKR_OK) ? PR_SUCCESS : PR_FAILURE;
1435 NSS_IMPLEMENT NSSItem *
1436 nssToken_FinishDigest (
1437 NSSToken *tok,
1438 nssSession *sessionOpt,
1439 NSSItem *rvOpt,
1440 NSSArena *arenaOpt
1443 CK_RV ckrv;
1444 CK_ULONG digestLen;
1445 CK_BYTE_PTR digest;
1446 NSSItem *rvItem = NULL;
1447 void *epv = nssToken_GetCryptokiEPV(tok);
1448 nssSession *session;
1449 session = (sessionOpt) ? sessionOpt : tok->defaultSession;
1450 nssSession_EnterMonitor(session);
1451 ckrv = CKAPI(epv)->C_DigestFinal(session->handle, NULL, &digestLen);
1452 if (ckrv != CKR_OK || digestLen == 0) {
1453 nssSession_ExitMonitor(session);
1454 return NULL;
1456 digest = NULL;
1457 if (rvOpt) {
1458 if (rvOpt->size > 0 && rvOpt->size < digestLen) {
1459 nssSession_ExitMonitor(session);
1460 /* the error should be bad args */
1461 return NULL;
1463 if (rvOpt->data) {
1464 digest = rvOpt->data;
1466 digestLen = rvOpt->size;
1468 if (!digest) {
1469 digest = (CK_BYTE_PTR)nss_ZAlloc(arenaOpt, digestLen);
1470 if (!digest) {
1471 nssSession_ExitMonitor(session);
1472 return NULL;
1475 ckrv = CKAPI(epv)->C_DigestFinal(session->handle, digest, &digestLen);
1476 nssSession_ExitMonitor(session);
1477 if (ckrv != CKR_OK) {
1478 nss_ZFreeIf(digest);
1479 return NULL;
1481 if (!rvOpt) {
1482 rvItem = nssItem_Create(arenaOpt, NULL, digestLen, (void *)digest);
1484 return rvItem;
1487 NSS_IMPLEMENT PRBool
1488 nssToken_IsPresent (
1489 NSSToken *token
1492 return nssSlot_IsTokenPresent(token->slot);
1495 /* Sigh. The methods to find objects declared above cause problems with
1496 * the low-level object cache in the softoken -- the objects are found in
1497 * toto, then one wave of GetAttributes is done, then another. Having a
1498 * large number of objects causes the cache to be thrashed, as the objects
1499 * are gone before there's any chance to ask for their attributes.
1500 * So, for now, bringing back traversal methods for certs. This way all of
1501 * the cert's attributes can be grabbed immediately after finding it,
1502 * increasing the likelihood that the cache takes care of it.
1504 NSS_IMPLEMENT PRStatus
1505 nssToken_TraverseCertificates (
1506 NSSToken *token,
1507 nssSession *sessionOpt,
1508 nssTokenSearchType searchType,
1509 PRStatus (* callback)(nssCryptokiObject *instance, void *arg),
1510 void *arg
1513 CK_RV ckrv;
1514 CK_ULONG count;
1515 CK_OBJECT_HANDLE *objectHandles;
1516 CK_ATTRIBUTE_PTR attr;
1517 CK_ATTRIBUTE cert_template[2];
1518 CK_ULONG ctsize;
1519 NSSArena *arena;
1520 PRStatus status;
1521 PRUint32 arraySize, numHandles;
1522 nssCryptokiObject **objects;
1523 void *epv = nssToken_GetCryptokiEPV(token);
1524 nssSession *session = (sessionOpt) ? sessionOpt : token->defaultSession;
1526 /* template for all certs */
1527 NSS_CK_TEMPLATE_START(cert_template, attr, ctsize);
1528 if (searchType == nssTokenSearchType_SessionOnly) {
1529 NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_false);
1530 } else if (searchType == nssTokenSearchType_TokenOnly ||
1531 searchType == nssTokenSearchType_TokenForced) {
1532 NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_true);
1534 NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_CLASS, &g_ck_class_cert);
1535 NSS_CK_TEMPLATE_FINISH(cert_template, attr, ctsize);
1537 /* the arena is only for the array of object handles */
1538 arena = nssArena_Create();
1539 if (!arena) {
1540 return PR_FAILURE;
1542 arraySize = OBJECT_STACK_SIZE;
1543 numHandles = 0;
1544 objectHandles = nss_ZNEWARRAY(arena, CK_OBJECT_HANDLE, arraySize);
1545 if (!objectHandles) {
1546 goto loser;
1548 nssSession_EnterMonitor(session); /* ==== session lock === */
1549 /* Initialize the find with the template */
1550 ckrv = CKAPI(epv)->C_FindObjectsInit(session->handle,
1551 cert_template, ctsize);
1552 if (ckrv != CKR_OK) {
1553 nssSession_ExitMonitor(session);
1554 goto loser;
1556 while (PR_TRUE) {
1557 /* Issue the find for up to arraySize - numHandles objects */
1558 ckrv = CKAPI(epv)->C_FindObjects(session->handle,
1559 objectHandles + numHandles,
1560 arraySize - numHandles,
1561 &count);
1562 if (ckrv != CKR_OK) {
1563 nssSession_ExitMonitor(session);
1564 goto loser;
1566 /* bump the number of found objects */
1567 numHandles += count;
1568 if (numHandles < arraySize) {
1569 break;
1571 /* the array is filled, double it and continue */
1572 arraySize *= 2;
1573 objectHandles = nss_ZREALLOCARRAY(objectHandles,
1574 CK_OBJECT_HANDLE,
1575 arraySize);
1576 if (!objectHandles) {
1577 nssSession_ExitMonitor(session);
1578 goto loser;
1581 ckrv = CKAPI(epv)->C_FindObjectsFinal(session->handle);
1582 nssSession_ExitMonitor(session); /* ==== end session lock === */
1583 if (ckrv != CKR_OK) {
1584 goto loser;
1586 if (numHandles > 0) {
1587 objects = create_objects_from_handles(token, session,
1588 objectHandles, numHandles);
1589 if (objects) {
1590 nssCryptokiObject **op;
1591 for (op = objects; *op; op++) {
1592 status = (*callback)(*op, arg);
1594 nss_ZFreeIf(objects);
1597 nssArena_Destroy(arena);
1598 return PR_SUCCESS;
1599 loser:
1600 nssArena_Destroy(arena);
1601 return PR_FAILURE;
1604 NSS_IMPLEMENT PRBool
1605 nssToken_IsPrivateKeyAvailable (
1606 NSSToken *token,
1607 NSSCertificate *c,
1608 nssCryptokiObject *instance
1611 CK_OBJECT_CLASS theClass;
1613 if (token == NULL) return PR_FALSE;
1614 if (c == NULL) return PR_FALSE;
1616 theClass = CKO_PRIVATE_KEY;
1617 if (!nssSlot_IsLoggedIn(token->slot)) {
1618 theClass = CKO_PUBLIC_KEY;
1620 if (PK11_MatchItem(token->pk11slot, instance->handle, theClass)
1621 != CK_INVALID_HANDLE) {
1622 return PR_TRUE;
1624 return PR_FALSE;