/* * The contents of this file are subject to the Mozilla Public * License Version 1.1 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of * the License at http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or * implied. See the License for the specific language governing * rights and limitations under the License. * * The Original Code is the Netscape security libraries. * * The Initial Developer of the Original Code is Netscape * Communications Corporation. Portions created by Netscape are * Copyright (C) 1994-2000 Netscape Communications Corporation. All * Rights Reserved. * * Contributor(s): * * Alternatively, the contents of this file may be used under the * terms of the GNU General Public License Version 2 or later (the * "GPL"), in which case the provisions of the GPL are applicable * instead of those above. If you wish to allow use of your * version of this file only under the terms of the GPL and not to * allow others to use your version of this file under the MPL, * indicate your decision by deleting the provisions above and * replace them with the notice and other provisions required by * the GPL. If you do not delete the provisions above, a recipient * may use your version of this file under either the MPL or the * GPL. */ #ifdef DEBUG static const char CVS_ID[] = "@(#) $RCSfile: devtoken.c,v $ $Revision: 1.2 $ $Date: 2001-11-09 00:36:12 $ $Name: not supported by cvs2svn $"; #endif /* DEBUG */ #ifndef DEV_H #include "dev.h" #endif /* DEV_H */ #ifndef DEVM_H #include "devm.h" #endif /* DEVM_H */ /* for the cache... */ #ifndef PKI_H #include "pki.h" #endif /* PKI_H */ #ifndef NSSCKEPV_H #include "nssckepv.h" #endif /* NSSCKEPV_H */ #ifndef NSSPKI_H #include "nsspki.h" #endif /* NSSPKI_H */ #ifndef PKI_H #include "pki.h" #endif /* PKI_H */ #ifndef CKHELPER_H #include "ckhelper.h" #endif /* CKHELPER_H */ #ifndef BASE_H #include "base.h" #endif /* BASE_H */ /* maybe this should really inherit completely from the module... I dunno, * any uses of slots where independence is needed? */ NSS_IMPLEMENT NSSToken * nssToken_Create ( NSSArena *arenaOpt, CK_SLOT_ID slotID, NSSSlot *parent ) { NSSArena *arena; nssArenaMark *mark; NSSToken *rvToken; nssSession *session; NSSUTF8 *tokenName = NULL; PRUint32 length; PRBool newArena; PRBool readWrite; PRStatus nssrv; CK_TOKEN_INFO tokenInfo; CK_RV ckrv; if (arenaOpt) { arena = arenaOpt; mark = nssArena_Mark(arena); if (!mark) { return (NSSToken *)NULL; } newArena = PR_FALSE; } else { arena = NSSArena_Create(); if(!arena) { return (NSSToken *)NULL; } newArena = PR_TRUE; } rvToken = nss_ZNEW(arena, NSSToken); if (!rvToken) { goto loser; } /* Get token information */ ckrv = CKAPI(parent)->C_GetTokenInfo(slotID, &tokenInfo); if (ckrv != CKR_OK) { /* set an error here, eh? */ goto loser; } /* Grab the slot description from the PKCS#11 fixed-length buffer */ length = nssPKCS11StringLength(tokenInfo.label, sizeof(tokenInfo.label)); if (length > 0) { tokenName = nssUTF8_Create(arena, nssStringType_UTF8String, (void *)tokenInfo.label, length); if (!tokenName) { goto loser; } } /* Open a default session handle for the token. */ if (tokenInfo.ulMaxSessionCount == 1) { /* if the token can only handle one session, it must be RW. */ readWrite = PR_TRUE; } else { readWrite = PR_FALSE; } session = nssSlot_CreateSession(parent, arena, readWrite); if (session == NULL) { goto loser; } /* TODO: seed the RNG here */ if (!arenaOpt) { /* Avoid confusion now - only set the token's arena to a non-NULL value * if a new arena is created. Otherwise, depend on the caller (having * passed arenaOpt) to free the arena. */ rvToken->arena = arena; } rvToken->refCount = 1; rvToken->slot = parent; rvToken->name = tokenName; rvToken->ckFlags = tokenInfo.flags; rvToken->defaultSession = session; nssrv = nssArena_Unmark(arena, mark); if (nssrv != PR_SUCCESS) { goto loser; } return rvToken; loser: if (session) { nssSession_Destroy(session); } if (newArena) { nssArena_Destroy(arena); } else { if (mark) { nssArena_Release(arena, mark); } } return (NSSToken *)NULL; } NSS_IMPLEMENT PRStatus nssToken_Destroy ( NSSToken *tok ) { if (--tok->refCount == 0) { #ifndef NSS_3_4_CODE /* don't do this in 3.4 -- let PK11SlotInfo handle it */ if (tok->defaultSession) { nssSession_Destroy(tok->defaultSession); } #endif if (tok->arena) { return NSSArena_Destroy(tok->arena); } else { nss_ZFreeIf(tok); } } return PR_SUCCESS; } NSS_IMPLEMENT NSSToken * nssToken_AddRef ( NSSToken *tok ) { ++tok->refCount; return tok; } NSS_IMPLEMENT NSSUTF8 * nssToken_GetName ( NSSToken *tok ) { return tok->name; } NSS_IMPLEMENT PRStatus nssToken_DeleteStoredObject ( NSSToken *tok, nssSession *sessionOpt, CK_OBJECT_HANDLE object ) { nssSession *session = NULL; CK_RV ckrv; PRStatus nssrv; PRBool createdSession; if (nssCKObject_IsAttributeTrue(object, CKA_TOKEN, tok->defaultSession, tok->slot, &nssrv)) { if (sessionOpt) { if (!nssSession_IsReadWrite(sessionOpt)) { return PR_FAILURE;; } else { session = sessionOpt; } } else if (nssSession_IsReadWrite(tok->defaultSession)) { session = tok->defaultSession; } else { session = nssSlot_CreateSession(tok->slot, NULL, PR_TRUE); createdSession = PR_TRUE; } } if (session == NULL) { return PR_FAILURE; } nssSession_EnterMonitor(session); ckrv = CKAPI(tok->slot)->C_DestroyObject(session->handle, object); nssSession_ExitMonitor(session); if (createdSession) { nssSession_Destroy(session); } if (ckrv != CKR_OK) { return PR_FAILURE; } return PR_SUCCESS; } NSS_IMPLEMENT CK_OBJECT_HANDLE nssToken_ImportObject ( NSSToken *tok, nssSession *sessionOpt, CK_ATTRIBUTE_PTR objectTemplate, CK_ULONG otsize ) { nssSession *session = NULL; PRBool createdSession = PR_FALSE; CK_OBJECT_HANDLE object; CK_RV ckrv; if (nssCKObject_IsTokenObjectTemplate(objectTemplate, otsize)) { if (sessionOpt) { if (!nssSession_IsReadWrite(sessionOpt)) { return CK_INVALID_HANDLE; } else { session = sessionOpt; } } else if (nssSession_IsReadWrite(tok->defaultSession)) { session = tok->defaultSession; } else { session = nssSlot_CreateSession(tok->slot, NULL, PR_TRUE); createdSession = PR_TRUE; } } if (session == NULL) { return PR_FAILURE; } nssSession_EnterMonitor(session); ckrv = CKAPI(tok->slot)->C_CreateObject(session->handle, objectTemplate, otsize, &object); nssSession_ExitMonitor(session); if (createdSession) { nssSession_Destroy(session); } if (ckrv != CKR_OK) { return CK_INVALID_HANDLE; } return object; } NSS_IMPLEMENT CK_OBJECT_HANDLE nssToken_FindObjectByTemplate ( NSSToken *tok, nssSession *sessionOpt, CK_ATTRIBUTE_PTR cktemplate, CK_ULONG ctsize ) { CK_SESSION_HANDLE hSession; CK_OBJECT_HANDLE rvObject; CK_ULONG count; CK_RV ckrv; nssSession *session; session = (sessionOpt) ? sessionOpt : tok->defaultSession; hSession = session->handle; nssSession_EnterMonitor(session); ckrv = CKAPI(tok)->C_FindObjectsInit(hSession, cktemplate, ctsize); if (ckrv != CKR_OK) { nssSession_ExitMonitor(session); return CK_INVALID_HANDLE; } ckrv = CKAPI(tok)->C_FindObjects(hSession, &rvObject, 1, &count); if (ckrv != CKR_OK) { nssSession_ExitMonitor(session); return CK_INVALID_HANDLE; } ckrv = CKAPI(tok)->C_FindObjectsFinal(hSession); nssSession_ExitMonitor(session); if (ckrv != CKR_OK) { return CK_INVALID_HANDLE; } return rvObject; } extern const NSSError NSS_ERROR_MAXIMUM_FOUND; struct collect_arg_str { NSSArena *arena; nssList *list; PRUint32 maximum; }; static PRStatus collect_certs_callback(NSSToken *t, nssSession *session, CK_OBJECT_HANDLE h, void *arg) { NSSCertificate *cert; struct collect_arg_str *ca = (struct collect_arg_str *)arg; cert = nssCertificate_CreateFromHandle(ca->arena, h, session, t->slot); if (!cert) { goto loser; } /* addref */ nssList_Add(ca->list, (void *)cert); if (ca->maximum > 0 && nssList_Count(ca->list) >= ca->maximum) { /* signal the end of collection) */ nss_SetError(NSS_ERROR_MAXIMUM_FOUND); return PR_FAILURE; } return PR_SUCCESS; loser: return PR_FAILURE; } struct cert_callback_str { nssListIterator *cachedCerts; PRStatus (*callback)(NSSCertificate *c, void *arg); void *arg; }; static PRStatus retrieve_cert(NSSToken *t, nssSession *session, CK_OBJECT_HANDLE h, void *arg) { NSSCertificate *cert = NULL; NSSCertificate *c; struct cert_callback_str *ccb = (struct cert_callback_str *)arg; if (ccb->cachedCerts) { for (c = (NSSCertificate *)nssListIterator_Start(ccb->cachedCerts); c != (NSSCertificate *)NULL; c = (NSSCertificate *)nssListIterator_Next(ccb->cachedCerts)) { if (c->handle == h && c->token == t) { /* this is enough, right? */ cert = c; break; } } nssListIterator_Finish(ccb->cachedCerts); } if (!cert) { /* Could not find cert, so create it */ cert = nssCertificate_CreateFromHandle(NULL, h, session, t->slot); if (!cert) { goto loser; } } /* Got the cert, feed it to the callback */ return (*ccb->callback)(cert, ccb->arg); loser: return PR_FAILURE; } #define OBJECT_STACK_SIZE 16 static PRStatus nsstoken_TraverseObjects ( NSSToken *tok, nssSession *session, CK_ATTRIBUTE_PTR obj_template, CK_ULONG otsize, PRStatus (*callback)(NSSToken *t, nssSession *session, CK_OBJECT_HANDLE h, void *arg), void *arg ) { NSSSlot *slot; PRStatus cbrv; PRUint32 i; CK_RV ckrv; CK_ULONG count; CK_OBJECT_HANDLE *objectStack; CK_OBJECT_HANDLE startOS[OBJECT_STACK_SIZE]; CK_SESSION_HANDLE hSession; NSSArena *objectArena = NULL; nssList *objectList = NULL; slot = tok->slot; hSession = session->handle; objectStack = startOS; nssSession_EnterMonitor(session); ckrv = CKAPI(slot)->C_FindObjectsInit(hSession, obj_template, otsize); if (ckrv != CKR_OK) { nssSession_ExitMonitor(session); goto loser; } while (PR_TRUE) { ckrv = CKAPI(slot)->C_FindObjects(hSession, objectStack, OBJECT_STACK_SIZE, &count); if (ckrv != CKR_OK) { nssSession_ExitMonitor(session); goto loser; } if (count == OBJECT_STACK_SIZE) { if (!objectList) { objectArena = NSSArena_Create(); objectList = nssList_Create(objectArena, PR_FALSE); } objectStack = nss_ZNEWARRAY(objectArena, CK_OBJECT_HANDLE, OBJECT_STACK_SIZE); nssList_Add(objectList, objectStack); } else { break; } } ckrv = CKAPI(slot)->C_FindObjectsFinal(hSession); nssSession_ExitMonitor(session); if (ckrv != CKR_OK) { goto loser; } if (objectList) { nssListIterator *objects; objects = nssList_CreateIterator(objectList); for (objectStack = (CK_OBJECT_HANDLE *)nssListIterator_Start(objects); objectStack != NULL; objectStack = (CK_OBJECT_HANDLE *)nssListIterator_Next(objects)) { for (i=0; idefaultSession; /* this isn't really traversal, it's find by template ... */ if (cachedList) { ccb.cachedCerts = nssList_CreateIterator(cachedList); } else { ccb.cachedCerts = NULL; } ccb.callback = callback; ccb.arg = arg; rv = nsstoken_TraverseObjects(tok, session, cktemplate, ctsize, retrieve_cert, (void *)&ccb); return rv; }