/* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ /* * token.c * * This file implements the NSSCKFWToken type and methods. */ #ifndef CK_T #include "ck.h" #endif /* CK_T */ /* * NSSCKFWToken * * -- create/destroy -- * nssCKFWToken_Create * nssCKFWToken_Destroy * * -- public accessors -- * NSSCKFWToken_GetMDToken * NSSCKFWToken_GetFWSlot * NSSCKFWToken_GetMDSlot * NSSCKFWToken_GetSessionState * * -- implement public accessors -- * nssCKFWToken_GetMDToken * nssCKFWToken_GetFWSlot * nssCKFWToken_GetMDSlot * nssCKFWToken_GetSessionState * nssCKFWToken_SetSessionState * * -- private accessors -- * nssCKFWToken_SetSessionState * nssCKFWToken_RemoveSession * nssCKFWToken_CloseAllSessions * nssCKFWToken_GetSessionCount * nssCKFWToken_GetRwSessionCount * nssCKFWToken_GetRoSessionCount * nssCKFWToken_GetSessionObjectHash * nssCKFWToken_GetMDObjectHash * nssCKFWToken_GetObjectHandleHash * * -- module fronts -- * nssCKFWToken_InitToken * nssCKFWToken_GetLabel * nssCKFWToken_GetManufacturerID * nssCKFWToken_GetModel * nssCKFWToken_GetSerialNumber * nssCKFWToken_GetHasRNG * nssCKFWToken_GetIsWriteProtected * nssCKFWToken_GetLoginRequired * nssCKFWToken_GetUserPinInitialized * nssCKFWToken_GetRestoreKeyNotNeeded * nssCKFWToken_GetHasClockOnToken * nssCKFWToken_GetHasProtectedAuthenticationPath * nssCKFWToken_GetSupportsDualCryptoOperations * nssCKFWToken_GetMaxSessionCount * nssCKFWToken_GetMaxRwSessionCount * nssCKFWToken_GetMaxPinLen * nssCKFWToken_GetMinPinLen * nssCKFWToken_GetTotalPublicMemory * nssCKFWToken_GetFreePublicMemory * nssCKFWToken_GetTotalPrivateMemory * nssCKFWToken_GetFreePrivateMemory * nssCKFWToken_GetHardwareVersion * nssCKFWToken_GetFirmwareVersion * nssCKFWToken_GetUTCTime * nssCKFWToken_OpenSession * nssCKFWToken_GetMechanismCount * nssCKFWToken_GetMechanismTypes * nssCKFWToken_GetMechanism */ struct NSSCKFWTokenStr { NSSCKFWMutex *mutex; NSSArena *arena; NSSCKMDToken *mdToken; NSSCKFWSlot *fwSlot; NSSCKMDSlot *mdSlot; NSSCKFWInstance *fwInstance; NSSCKMDInstance *mdInstance; /* * Everything above is set at creation time, and then not modified. * The invariants the mutex protects are: * * 1) Each of the cached descriptions (versions, etc.) are in an * internally consistant state. * * 2) The session counts and hashes are consistant. * * 3) The object hashes are consistant. * * Note that the calls accessing the cached descriptions will call * the NSSCKMDToken methods with the mutex locked. Those methods * may then call the public NSSCKFWToken routines. Those public * routines only access the constant data above and the atomic * CK_STATE session state variable below, so there's no problem. * But be careful if you add to this object; mutexes are in * general not reentrant, so don't create deadlock situations. */ NSSUTF8 *label; NSSUTF8 *manufacturerID; NSSUTF8 *model; NSSUTF8 *serialNumber; CK_VERSION hardwareVersion; CK_VERSION firmwareVersion; CK_ULONG sessionCount; CK_ULONG rwSessionCount; nssCKFWHash *sessions; nssCKFWHash *sessionObjectHash; nssCKFWHash *mdObjectHash; nssCKFWHash *mdMechanismHash; CK_STATE state; }; #ifdef DEBUG /* * But first, the pointer-tracking stuff. * * NOTE: the pointer-tracking support in NSS/base currently relies * upon NSPR's CallOnce support. That, however, relies upon NSPR's * locking, which is tied into the runtime. We need a pointer-tracker * implementation that uses the locks supplied through C_Initialize. * That support, however, can be filled in later. So for now, I'll * just do this routines as no-ops. */ static CK_RV token_add_pointer( const NSSCKFWToken *fwToken) { return CKR_OK; } static CK_RV token_remove_pointer( const NSSCKFWToken *fwToken) { return CKR_OK; } NSS_IMPLEMENT CK_RV nssCKFWToken_verifyPointer( const NSSCKFWToken *fwToken) { return CKR_OK; } #endif /* DEBUG */ /* * nssCKFWToken_Create * */ NSS_IMPLEMENT NSSCKFWToken * nssCKFWToken_Create( NSSCKFWSlot *fwSlot, NSSCKMDToken *mdToken, CK_RV *pError) { NSSArena *arena = (NSSArena *)NULL; NSSCKFWToken *fwToken = (NSSCKFWToken *)NULL; CK_BBOOL called_setup = CK_FALSE; /* * We have already verified the arguments in nssCKFWSlot_GetToken. */ arena = NSSArena_Create(); if (!arena) { *pError = CKR_HOST_MEMORY; goto loser; } fwToken = nss_ZNEW(arena, NSSCKFWToken); if (!fwToken) { *pError = CKR_HOST_MEMORY; goto loser; } fwToken->arena = arena; fwToken->mdToken = mdToken; fwToken->fwSlot = fwSlot; fwToken->fwInstance = nssCKFWSlot_GetFWInstance(fwSlot); fwToken->mdInstance = nssCKFWSlot_GetMDInstance(fwSlot); fwToken->state = CKS_RO_PUBLIC_SESSION; /* some default */ fwToken->sessionCount = 0; fwToken->rwSessionCount = 0; fwToken->mutex = nssCKFWInstance_CreateMutex(fwToken->fwInstance, arena, pError); if (!fwToken->mutex) { if (CKR_OK == *pError) { *pError = CKR_GENERAL_ERROR; } goto loser; } fwToken->sessions = nssCKFWHash_Create(fwToken->fwInstance, arena, pError); if (!fwToken->sessions) { if (CKR_OK == *pError) { *pError = CKR_GENERAL_ERROR; } goto loser; } if (CK_TRUE != nssCKFWInstance_GetModuleHandlesSessionObjects( fwToken->fwInstance)) { fwToken->sessionObjectHash = nssCKFWHash_Create(fwToken->fwInstance, arena, pError); if (!fwToken->sessionObjectHash) { if (CKR_OK == *pError) { *pError = CKR_GENERAL_ERROR; } goto loser; } } fwToken->mdObjectHash = nssCKFWHash_Create(fwToken->fwInstance, arena, pError); if (!fwToken->mdObjectHash) { if (CKR_OK == *pError) { *pError = CKR_GENERAL_ERROR; } goto loser; } fwToken->mdMechanismHash = nssCKFWHash_Create(fwToken->fwInstance, arena, pError); if (!fwToken->mdMechanismHash) { if (CKR_OK == *pError) { *pError = CKR_GENERAL_ERROR; } goto loser; } /* More here */ if (mdToken->Setup) { *pError = mdToken->Setup(mdToken, fwToken, fwToken->mdInstance, fwToken->fwInstance); if (CKR_OK != *pError) { goto loser; } } called_setup = CK_TRUE; #ifdef DEBUG *pError = token_add_pointer(fwToken); if (CKR_OK != *pError) { goto loser; } #endif /* DEBUG */ *pError = CKR_OK; return fwToken; loser: if (CK_TRUE == called_setup) { if (mdToken->Invalidate) { mdToken->Invalidate(mdToken, fwToken, fwToken->mdInstance, fwToken->fwInstance); } } if (arena) { (void)NSSArena_Destroy(arena); } return (NSSCKFWToken *)NULL; } static void nss_ckfwtoken_session_iterator( const void *key, void *value, void *closure) { /* * Remember that the fwToken->mutex is locked */ NSSCKFWSession *fwSession = (NSSCKFWSession *)value; (void)nssCKFWSession_Destroy(fwSession, CK_FALSE); return; } static void nss_ckfwtoken_object_iterator( const void *key, void *value, void *closure) { /* * Remember that the fwToken->mutex is locked */ NSSCKFWObject *fwObject = (NSSCKFWObject *)value; (void)nssCKFWObject_Finalize(fwObject, CK_FALSE); return; } /* * nssCKFWToken_Destroy * */ NSS_IMPLEMENT CK_RV nssCKFWToken_Destroy( NSSCKFWToken *fwToken) { CK_RV error = CKR_OK; #ifdef NSSDEBUG error = nssCKFWToken_verifyPointer(fwToken); if (CKR_OK != error) { return error; } #endif /* NSSDEBUG */ (void)nssCKFWMutex_Destroy(fwToken->mutex); if (fwToken->mdToken->Invalidate) { fwToken->mdToken->Invalidate(fwToken->mdToken, fwToken, fwToken->mdInstance, fwToken->fwInstance); } /* we can destroy the list without locking now because no one else is * referencing us (or _Destroy was invalidly called!) */ nssCKFWHash_Iterate(fwToken->sessions, nss_ckfwtoken_session_iterator, (void *)NULL); nssCKFWHash_Destroy(fwToken->sessions); /* session objects go away when their sessions are removed */ if (fwToken->sessionObjectHash) { nssCKFWHash_Destroy(fwToken->sessionObjectHash); } /* free up the token objects */ if (fwToken->mdObjectHash) { nssCKFWHash_Iterate(fwToken->mdObjectHash, nss_ckfwtoken_object_iterator, (void *)NULL); nssCKFWHash_Destroy(fwToken->mdObjectHash); } if (fwToken->mdMechanismHash) { nssCKFWHash_Destroy(fwToken->mdMechanismHash); } nssCKFWSlot_ClearToken(fwToken->fwSlot); #ifdef DEBUG error = token_remove_pointer(fwToken); #endif /* DEBUG */ (void)NSSArena_Destroy(fwToken->arena); return error; } /* * nssCKFWToken_GetMDToken * */ NSS_IMPLEMENT NSSCKMDToken * nssCKFWToken_GetMDToken( NSSCKFWToken *fwToken) { #ifdef NSSDEBUG if (CKR_OK != nssCKFWToken_verifyPointer(fwToken)) { return (NSSCKMDToken *)NULL; } #endif /* NSSDEBUG */ return fwToken->mdToken; } /* * nssCKFWToken_GetArena * */ NSS_IMPLEMENT NSSArena * nssCKFWToken_GetArena( NSSCKFWToken *fwToken, CK_RV *pError) { #ifdef NSSDEBUG if (!pError) { return (NSSArena *)NULL; } *pError = nssCKFWToken_verifyPointer(fwToken); if (CKR_OK != *pError) { return (NSSArena *)NULL; } #endif /* NSSDEBUG */ return fwToken->arena; } /* * nssCKFWToken_GetFWSlot * */ NSS_IMPLEMENT NSSCKFWSlot * nssCKFWToken_GetFWSlot( NSSCKFWToken *fwToken) { #ifdef NSSDEBUG if (CKR_OK != nssCKFWToken_verifyPointer(fwToken)) { return (NSSCKFWSlot *)NULL; } #endif /* NSSDEBUG */ return fwToken->fwSlot; } /* * nssCKFWToken_GetMDSlot * */ NSS_IMPLEMENT NSSCKMDSlot * nssCKFWToken_GetMDSlot( NSSCKFWToken *fwToken) { #ifdef NSSDEBUG if (CKR_OK != nssCKFWToken_verifyPointer(fwToken)) { return (NSSCKMDSlot *)NULL; } #endif /* NSSDEBUG */ return fwToken->mdSlot; } /* * nssCKFWToken_GetSessionState * */ NSS_IMPLEMENT CK_STATE nssCKFWToken_GetSessionState( NSSCKFWToken *fwToken) { #ifdef NSSDEBUG if (CKR_OK != nssCKFWToken_verifyPointer(fwToken)) { return CKS_RO_PUBLIC_SESSION; /* whatever */ } #endif /* NSSDEBUG */ /* * BTW, do not lock the token in this method. */ /* * Theoretically, there is no state if there aren't any * sessions open. But then we'd need to worry about * reporting an error, etc. What the heck-- let's just * revert to CKR_RO_PUBLIC_SESSION as the "default." */ return fwToken->state; } /* * nssCKFWToken_InitToken * */ NSS_IMPLEMENT CK_RV nssCKFWToken_InitToken( NSSCKFWToken *fwToken, NSSItem *pin, NSSUTF8 *label) { CK_RV error; #ifdef NSSDEBUG error = nssCKFWToken_verifyPointer(fwToken); if (CKR_OK != error) { return CKR_ARGUMENTS_BAD; } #endif /* NSSDEBUG */ error = nssCKFWMutex_Lock(fwToken->mutex); if (CKR_OK != error) { return error; } if (fwToken->sessionCount > 0) { error = CKR_SESSION_EXISTS; goto done; } if (!fwToken->mdToken->InitToken) { error = CKR_DEVICE_ERROR; goto done; } if (!pin) { if (nssCKFWToken_GetHasProtectedAuthenticationPath(fwToken)) { ; /* okay */ } else { error = CKR_PIN_INCORRECT; goto done; } } if (!label) { label = (NSSUTF8 *)""; } error = fwToken->mdToken->InitToken(fwToken->mdToken, fwToken, fwToken->mdInstance, fwToken->fwInstance, pin, label); done: (void)nssCKFWMutex_Unlock(fwToken->mutex); return error; } /* * nssCKFWToken_GetLabel * */ NSS_IMPLEMENT CK_RV nssCKFWToken_GetLabel( NSSCKFWToken *fwToken, CK_CHAR label[32]) { CK_RV error = CKR_OK; #ifdef NSSDEBUG if ((CK_CHAR_PTR)NULL == label) { return CKR_ARGUMENTS_BAD; } error = nssCKFWToken_verifyPointer(fwToken); if (CKR_OK != error) { return error; } #endif /* NSSDEBUG */ error = nssCKFWMutex_Lock(fwToken->mutex); if (CKR_OK != error) { return error; } if (!fwToken->label) { if (fwToken->mdToken->GetLabel) { fwToken->label = fwToken->mdToken->GetLabel(fwToken->mdToken, fwToken, fwToken->mdInstance, fwToken->fwInstance, &error); if ((!fwToken->label) && (CKR_OK != error)) { goto done; } } else { fwToken->label = (NSSUTF8 *)""; } } (void)nssUTF8_CopyIntoFixedBuffer(fwToken->label, (char *)label, 32, ' '); error = CKR_OK; done: (void)nssCKFWMutex_Unlock(fwToken->mutex); return error; } /* * nssCKFWToken_GetManufacturerID * */ NSS_IMPLEMENT CK_RV nssCKFWToken_GetManufacturerID( NSSCKFWToken *fwToken, CK_CHAR manufacturerID[32]) { CK_RV error = CKR_OK; #ifdef NSSDEBUG if ((CK_CHAR_PTR)NULL == manufacturerID) { return CKR_ARGUMENTS_BAD; } error = nssCKFWToken_verifyPointer(fwToken); if (CKR_OK != error) { return error; } #endif /* NSSDEBUG */ error = nssCKFWMutex_Lock(fwToken->mutex); if (CKR_OK != error) { return error; } if (!fwToken->manufacturerID) { if (fwToken->mdToken->GetManufacturerID) { fwToken->manufacturerID = fwToken->mdToken->GetManufacturerID(fwToken->mdToken, fwToken, fwToken->mdInstance, fwToken->fwInstance, &error); if ((!fwToken->manufacturerID) && (CKR_OK != error)) { goto done; } } else { fwToken->manufacturerID = (NSSUTF8 *)""; } } (void)nssUTF8_CopyIntoFixedBuffer(fwToken->manufacturerID, (char *)manufacturerID, 32, ' '); error = CKR_OK; done: (void)nssCKFWMutex_Unlock(fwToken->mutex); return error; } /* * nssCKFWToken_GetModel * */ NSS_IMPLEMENT CK_RV nssCKFWToken_GetModel( NSSCKFWToken *fwToken, CK_CHAR model[16]) { CK_RV error = CKR_OK; #ifdef NSSDEBUG if ((CK_CHAR_PTR)NULL == model) { return CKR_ARGUMENTS_BAD; } error = nssCKFWToken_verifyPointer(fwToken); if (CKR_OK != error) { return error; } #endif /* NSSDEBUG */ error = nssCKFWMutex_Lock(fwToken->mutex); if (CKR_OK != error) { return error; } if (!fwToken->model) { if (fwToken->mdToken->GetModel) { fwToken->model = fwToken->mdToken->GetModel(fwToken->mdToken, fwToken, fwToken->mdInstance, fwToken->fwInstance, &error); if ((!fwToken->model) && (CKR_OK != error)) { goto done; } } else { fwToken->model = (NSSUTF8 *)""; } } (void)nssUTF8_CopyIntoFixedBuffer(fwToken->model, (char *)model, 16, ' '); error = CKR_OK; done: (void)nssCKFWMutex_Unlock(fwToken->mutex); return error; } /* * nssCKFWToken_GetSerialNumber * */ NSS_IMPLEMENT CK_RV nssCKFWToken_GetSerialNumber( NSSCKFWToken *fwToken, CK_CHAR serialNumber[16]) { CK_RV error = CKR_OK; #ifdef NSSDEBUG if ((CK_CHAR_PTR)NULL == serialNumber) { return CKR_ARGUMENTS_BAD; } error = nssCKFWToken_verifyPointer(fwToken); if (CKR_OK != error) { return error; } #endif /* NSSDEBUG */ error = nssCKFWMutex_Lock(fwToken->mutex); if (CKR_OK != error) { return error; } if (!fwToken->serialNumber) { if (fwToken->mdToken->GetSerialNumber) { fwToken->serialNumber = fwToken->mdToken->GetSerialNumber(fwToken->mdToken, fwToken, fwToken->mdInstance, fwToken->fwInstance, &error); if ((!fwToken->serialNumber) && (CKR_OK != error)) { goto done; } } else { fwToken->serialNumber = (NSSUTF8 *)""; } } (void)nssUTF8_CopyIntoFixedBuffer(fwToken->serialNumber, (char *)serialNumber, 16, ' '); error = CKR_OK; done: (void)nssCKFWMutex_Unlock(fwToken->mutex); return error; } /* * nssCKFWToken_GetHasRNG * */ NSS_IMPLEMENT CK_BBOOL nssCKFWToken_GetHasRNG( NSSCKFWToken *fwToken) { #ifdef NSSDEBUG if (CKR_OK != nssCKFWToken_verifyPointer(fwToken)) { return CK_FALSE; } #endif /* NSSDEBUG */ if (!fwToken->mdToken->GetHasRNG) { return CK_FALSE; } return fwToken->mdToken->GetHasRNG(fwToken->mdToken, fwToken, fwToken->mdInstance, fwToken->fwInstance); } /* * nssCKFWToken_GetIsWriteProtected * */ NSS_IMPLEMENT CK_BBOOL nssCKFWToken_GetIsWriteProtected( NSSCKFWToken *fwToken) { #ifdef NSSDEBUG if (CKR_OK != nssCKFWToken_verifyPointer(fwToken)) { return CK_FALSE; } #endif /* NSSDEBUG */ if (!fwToken->mdToken->GetIsWriteProtected) { return CK_FALSE; } return fwToken->mdToken->GetIsWriteProtected(fwToken->mdToken, fwToken, fwToken->mdInstance, fwToken->fwInstance); } /* * nssCKFWToken_GetLoginRequired * */ NSS_IMPLEMENT CK_BBOOL nssCKFWToken_GetLoginRequired( NSSCKFWToken *fwToken) { #ifdef NSSDEBUG if (CKR_OK != nssCKFWToken_verifyPointer(fwToken)) { return CK_FALSE; } #endif /* NSSDEBUG */ if (!fwToken->mdToken->GetLoginRequired) { return CK_FALSE; } return fwToken->mdToken->GetLoginRequired(fwToken->mdToken, fwToken, fwToken->mdInstance, fwToken->fwInstance); } /* * nssCKFWToken_GetUserPinInitialized * */ NSS_IMPLEMENT CK_BBOOL nssCKFWToken_GetUserPinInitialized( NSSCKFWToken *fwToken) { #ifdef NSSDEBUG if (CKR_OK != nssCKFWToken_verifyPointer(fwToken)) { return CK_FALSE; } #endif /* NSSDEBUG */ if (!fwToken->mdToken->GetUserPinInitialized) { return CK_FALSE; } return fwToken->mdToken->GetUserPinInitialized(fwToken->mdToken, fwToken, fwToken->mdInstance, fwToken->fwInstance); } /* * nssCKFWToken_GetRestoreKeyNotNeeded * */ NSS_IMPLEMENT CK_BBOOL nssCKFWToken_GetRestoreKeyNotNeeded( NSSCKFWToken *fwToken) { #ifdef NSSDEBUG if (CKR_OK != nssCKFWToken_verifyPointer(fwToken)) { return CK_FALSE; } #endif /* NSSDEBUG */ if (!fwToken->mdToken->GetRestoreKeyNotNeeded) { return CK_FALSE; } return fwToken->mdToken->GetRestoreKeyNotNeeded(fwToken->mdToken, fwToken, fwToken->mdInstance, fwToken->fwInstance); } /* * nssCKFWToken_GetHasClockOnToken * */ NSS_IMPLEMENT CK_BBOOL nssCKFWToken_GetHasClockOnToken( NSSCKFWToken *fwToken) { #ifdef NSSDEBUG if (CKR_OK != nssCKFWToken_verifyPointer(fwToken)) { return CK_FALSE; } #endif /* NSSDEBUG */ if (!fwToken->mdToken->GetHasClockOnToken) { return CK_FALSE; } return fwToken->mdToken->GetHasClockOnToken(fwToken->mdToken, fwToken, fwToken->mdInstance, fwToken->fwInstance); } /* * nssCKFWToken_GetHasProtectedAuthenticationPath * */ NSS_IMPLEMENT CK_BBOOL nssCKFWToken_GetHasProtectedAuthenticationPath( NSSCKFWToken *fwToken) { #ifdef NSSDEBUG if (CKR_OK != nssCKFWToken_verifyPointer(fwToken)) { return CK_FALSE; } #endif /* NSSDEBUG */ if (!fwToken->mdToken->GetHasProtectedAuthenticationPath) { return CK_FALSE; } return fwToken->mdToken->GetHasProtectedAuthenticationPath(fwToken->mdToken, fwToken, fwToken->mdInstance, fwToken->fwInstance); } /* * nssCKFWToken_GetSupportsDualCryptoOperations * */ NSS_IMPLEMENT CK_BBOOL nssCKFWToken_GetSupportsDualCryptoOperations( NSSCKFWToken *fwToken) { #ifdef NSSDEBUG if (CKR_OK != nssCKFWToken_verifyPointer(fwToken)) { return CK_FALSE; } #endif /* NSSDEBUG */ if (!fwToken->mdToken->GetSupportsDualCryptoOperations) { return CK_FALSE; } return fwToken->mdToken->GetSupportsDualCryptoOperations(fwToken->mdToken, fwToken, fwToken->mdInstance, fwToken->fwInstance); } /* * nssCKFWToken_GetMaxSessionCount * */ NSS_IMPLEMENT CK_ULONG nssCKFWToken_GetMaxSessionCount( NSSCKFWToken *fwToken) { #ifdef NSSDEBUG if (CKR_OK != nssCKFWToken_verifyPointer(fwToken)) { return CK_UNAVAILABLE_INFORMATION; } #endif /* NSSDEBUG */ if (!fwToken->mdToken->GetMaxSessionCount) { return CK_UNAVAILABLE_INFORMATION; } return fwToken->mdToken->GetMaxSessionCount(fwToken->mdToken, fwToken, fwToken->mdInstance, fwToken->fwInstance); } /* * nssCKFWToken_GetMaxRwSessionCount * */ NSS_IMPLEMENT CK_ULONG nssCKFWToken_GetMaxRwSessionCount( NSSCKFWToken *fwToken) { #ifdef NSSDEBUG if (CKR_OK != nssCKFWToken_verifyPointer(fwToken)) { return CK_UNAVAILABLE_INFORMATION; } #endif /* NSSDEBUG */ if (!fwToken->mdToken->GetMaxRwSessionCount) { return CK_UNAVAILABLE_INFORMATION; } return fwToken->mdToken->GetMaxRwSessionCount(fwToken->mdToken, fwToken, fwToken->mdInstance, fwToken->fwInstance); } /* * nssCKFWToken_GetMaxPinLen * */ NSS_IMPLEMENT CK_ULONG nssCKFWToken_GetMaxPinLen( NSSCKFWToken *fwToken) { #ifdef NSSDEBUG if (CKR_OK != nssCKFWToken_verifyPointer(fwToken)) { return CK_UNAVAILABLE_INFORMATION; } #endif /* NSSDEBUG */ if (!fwToken->mdToken->GetMaxPinLen) { return CK_UNAVAILABLE_INFORMATION; } return fwToken->mdToken->GetMaxPinLen(fwToken->mdToken, fwToken, fwToken->mdInstance, fwToken->fwInstance); } /* * nssCKFWToken_GetMinPinLen * */ NSS_IMPLEMENT CK_ULONG nssCKFWToken_GetMinPinLen( NSSCKFWToken *fwToken) { #ifdef NSSDEBUG if (CKR_OK != nssCKFWToken_verifyPointer(fwToken)) { return CK_UNAVAILABLE_INFORMATION; } #endif /* NSSDEBUG */ if (!fwToken->mdToken->GetMinPinLen) { return CK_UNAVAILABLE_INFORMATION; } return fwToken->mdToken->GetMinPinLen(fwToken->mdToken, fwToken, fwToken->mdInstance, fwToken->fwInstance); } /* * nssCKFWToken_GetTotalPublicMemory * */ NSS_IMPLEMENT CK_ULONG nssCKFWToken_GetTotalPublicMemory( NSSCKFWToken *fwToken) { #ifdef NSSDEBUG if (CKR_OK != nssCKFWToken_verifyPointer(fwToken)) { return CK_UNAVAILABLE_INFORMATION; } #endif /* NSSDEBUG */ if (!fwToken->mdToken->GetTotalPublicMemory) { return CK_UNAVAILABLE_INFORMATION; } return fwToken->mdToken->GetTotalPublicMemory(fwToken->mdToken, fwToken, fwToken->mdInstance, fwToken->fwInstance); } /* * nssCKFWToken_GetFreePublicMemory * */ NSS_IMPLEMENT CK_ULONG nssCKFWToken_GetFreePublicMemory( NSSCKFWToken *fwToken) { #ifdef NSSDEBUG if (CKR_OK != nssCKFWToken_verifyPointer(fwToken)) { return CK_UNAVAILABLE_INFORMATION; } #endif /* NSSDEBUG */ if (!fwToken->mdToken->GetFreePublicMemory) { return CK_UNAVAILABLE_INFORMATION; } return fwToken->mdToken->GetFreePublicMemory(fwToken->mdToken, fwToken, fwToken->mdInstance, fwToken->fwInstance); } /* * nssCKFWToken_GetTotalPrivateMemory * */ NSS_IMPLEMENT CK_ULONG nssCKFWToken_GetTotalPrivateMemory( NSSCKFWToken *fwToken) { #ifdef NSSDEBUG if (CKR_OK != nssCKFWToken_verifyPointer(fwToken)) { return CK_UNAVAILABLE_INFORMATION; } #endif /* NSSDEBUG */ if (!fwToken->mdToken->GetTotalPrivateMemory) { return CK_UNAVAILABLE_INFORMATION; } return fwToken->mdToken->GetTotalPrivateMemory(fwToken->mdToken, fwToken, fwToken->mdInstance, fwToken->fwInstance); } /* * nssCKFWToken_GetFreePrivateMemory * */ NSS_IMPLEMENT CK_ULONG nssCKFWToken_GetFreePrivateMemory( NSSCKFWToken *fwToken) { #ifdef NSSDEBUG if (CKR_OK != nssCKFWToken_verifyPointer(fwToken)) { return CK_UNAVAILABLE_INFORMATION; } #endif /* NSSDEBUG */ if (!fwToken->mdToken->GetFreePrivateMemory) { return CK_UNAVAILABLE_INFORMATION; } return fwToken->mdToken->GetFreePrivateMemory(fwToken->mdToken, fwToken, fwToken->mdInstance, fwToken->fwInstance); } /* * nssCKFWToken_GetHardwareVersion * */ NSS_IMPLEMENT CK_VERSION nssCKFWToken_GetHardwareVersion( NSSCKFWToken *fwToken) { CK_VERSION rv; #ifdef NSSDEBUG if (CKR_OK != nssCKFWToken_verifyPointer(fwToken)) { rv.major = rv.minor = 0; return rv; } #endif /* NSSDEBUG */ if (CKR_OK != nssCKFWMutex_Lock(fwToken->mutex)) { rv.major = rv.minor = 0; return rv; } if ((0 != fwToken->hardwareVersion.major) || (0 != fwToken->hardwareVersion.minor)) { rv = fwToken->hardwareVersion; goto done; } if (fwToken->mdToken->GetHardwareVersion) { fwToken->hardwareVersion = fwToken->mdToken->GetHardwareVersion( fwToken->mdToken, fwToken, fwToken->mdInstance, fwToken->fwInstance); } else { fwToken->hardwareVersion.major = 0; fwToken->hardwareVersion.minor = 1; } rv = fwToken->hardwareVersion; done: (void)nssCKFWMutex_Unlock(fwToken->mutex); return rv; } /* * nssCKFWToken_GetFirmwareVersion * */ NSS_IMPLEMENT CK_VERSION nssCKFWToken_GetFirmwareVersion( NSSCKFWToken *fwToken) { CK_VERSION rv; #ifdef NSSDEBUG if (CKR_OK != nssCKFWToken_verifyPointer(fwToken)) { rv.major = rv.minor = 0; return rv; } #endif /* NSSDEBUG */ if (CKR_OK != nssCKFWMutex_Lock(fwToken->mutex)) { rv.major = rv.minor = 0; return rv; } if ((0 != fwToken->firmwareVersion.major) || (0 != fwToken->firmwareVersion.minor)) { rv = fwToken->firmwareVersion; goto done; } if (fwToken->mdToken->GetFirmwareVersion) { fwToken->firmwareVersion = fwToken->mdToken->GetFirmwareVersion( fwToken->mdToken, fwToken, fwToken->mdInstance, fwToken->fwInstance); } else { fwToken->firmwareVersion.major = 0; fwToken->firmwareVersion.minor = 1; } rv = fwToken->firmwareVersion; done: (void)nssCKFWMutex_Unlock(fwToken->mutex); return rv; } /* * nssCKFWToken_GetUTCTime * */ NSS_IMPLEMENT CK_RV nssCKFWToken_GetUTCTime( NSSCKFWToken *fwToken, CK_CHAR utcTime[16]) { CK_RV error = CKR_OK; #ifdef NSSDEBUG error = nssCKFWToken_verifyPointer(fwToken); if (CKR_OK != error) { return error; } if ((CK_CHAR_PTR)NULL == utcTime) { return CKR_ARGUMENTS_BAD; } #endif /* DEBUG */ if (CK_TRUE != nssCKFWToken_GetHasClockOnToken(fwToken)) { /* return CKR_DEVICE_ERROR; */ (void)nssUTF8_CopyIntoFixedBuffer((NSSUTF8 *)NULL, (char *)utcTime, 16, ' '); return CKR_OK; } if (!fwToken->mdToken->GetUTCTime) { /* It said it had one! */ return CKR_GENERAL_ERROR; } error = fwToken->mdToken->GetUTCTime(fwToken->mdToken, fwToken, fwToken->mdInstance, fwToken->fwInstance, utcTime); if (CKR_OK != error) { return error; } /* Sanity-check the data */ { /* Format is YYYYMMDDhhmmss00 */ int i; int Y, M, D, h, m, s; static int dims[] = { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; for (i = 0; i < 16; i++) { if ((utcTime[i] < '0') || (utcTime[i] > '9')) { goto badtime; } } Y = ((utcTime[0] - '0') * 1000) + ((utcTime[1] - '0') * 100) + ((utcTime[2] - '0') * 10) + (utcTime[3] - '0'); M = ((utcTime[4] - '0') * 10) + (utcTime[5] - '0'); D = ((utcTime[6] - '0') * 10) + (utcTime[7] - '0'); h = ((utcTime[8] - '0') * 10) + (utcTime[9] - '0'); m = ((utcTime[10] - '0') * 10) + (utcTime[11] - '0'); s = ((utcTime[12] - '0') * 10) + (utcTime[13] - '0'); if ((Y < 1990) || (Y > 3000)) goto badtime; /* Y3K problem. heh heh heh */ if ((M < 1) || (M > 12)) goto badtime; if ((D < 1) || (D > 31)) goto badtime; if (D > dims[M - 1]) goto badtime; /* per-month check */ if ((2 == M) && (((Y % 4) || !(Y % 100)) && (Y % 400)) && (D > 28)) goto badtime; /* leap years */ if ((h < 0) || (h > 23)) goto badtime; if ((m < 0) || (m > 60)) goto badtime; if ((s < 0) || (s > 61)) goto badtime; /* 60m and 60 or 61s is only allowed for leap seconds. */ if ((60 == m) || (s >= 60)) { if ((23 != h) || (60 != m) || (s < 60)) goto badtime; /* leap seconds can only happen on June 30 or Dec 31.. I think */ /* if( ((6 != M) || (30 != D)) && ((12 != M) || (31 != D)) ) goto badtime; */ } } return CKR_OK; badtime: return CKR_GENERAL_ERROR; } /* * nssCKFWToken_OpenSession * */ NSS_IMPLEMENT NSSCKFWSession * nssCKFWToken_OpenSession( NSSCKFWToken *fwToken, CK_BBOOL rw, CK_VOID_PTR pApplication, CK_NOTIFY Notify, CK_RV *pError) { NSSCKFWSession *fwSession = (NSSCKFWSession *)NULL; NSSCKMDSession *mdSession; #ifdef NSSDEBUG if (!pError) { return (NSSCKFWSession *)NULL; } *pError = nssCKFWToken_verifyPointer(fwToken); if (CKR_OK != *pError) { return (NSSCKFWSession *)NULL; } switch (rw) { case CK_TRUE: case CK_FALSE: break; default: *pError = CKR_ARGUMENTS_BAD; return (NSSCKFWSession *)NULL; } #endif /* NSSDEBUG */ *pError = nssCKFWMutex_Lock(fwToken->mutex); if (CKR_OK != *pError) { return (NSSCKFWSession *)NULL; } if (CK_TRUE == rw) { /* Read-write session desired */ if (CK_TRUE == nssCKFWToken_GetIsWriteProtected(fwToken)) { *pError = CKR_TOKEN_WRITE_PROTECTED; goto done; } } else { /* Read-only session desired */ if (CKS_RW_SO_FUNCTIONS == nssCKFWToken_GetSessionState(fwToken)) { *pError = CKR_SESSION_READ_WRITE_SO_EXISTS; goto done; } } /* We could compare sesion counts to any limits we know of, I guess.. */ if (!fwToken->mdToken->OpenSession) { /* * I'm not sure that the Module actually needs to implement * mdSessions -- the Framework can keep track of everything * needed, really. But I'll sort out that detail later.. */ *pError = CKR_GENERAL_ERROR; goto done; } fwSession = nssCKFWSession_Create(fwToken, rw, pApplication, Notify, pError); if (!fwSession) { if (CKR_OK == *pError) { *pError = CKR_GENERAL_ERROR; } goto done; } mdSession = fwToken->mdToken->OpenSession(fwToken->mdToken, fwToken, fwToken->mdInstance, fwToken->fwInstance, fwSession, rw, pError); if (!mdSession) { (void)nssCKFWSession_Destroy(fwSession, CK_FALSE); if (CKR_OK == *pError) { *pError = CKR_GENERAL_ERROR; } goto done; } *pError = nssCKFWSession_SetMDSession(fwSession, mdSession); if (CKR_OK != *pError) { if (mdSession->Close) { mdSession->Close(mdSession, fwSession, fwToken->mdToken, fwToken, fwToken->mdInstance, fwToken->fwInstance); } (void)nssCKFWSession_Destroy(fwSession, CK_FALSE); goto done; } *pError = nssCKFWHash_Add(fwToken->sessions, fwSession, fwSession); if (CKR_OK != *pError) { (void)nssCKFWSession_Destroy(fwSession, CK_FALSE); fwSession = (NSSCKFWSession *)NULL; goto done; } done: (void)nssCKFWMutex_Unlock(fwToken->mutex); return fwSession; } /* * nssCKFWToken_GetMechanismCount * */ NSS_IMPLEMENT CK_ULONG nssCKFWToken_GetMechanismCount( NSSCKFWToken *fwToken) { #ifdef NSSDEBUG if (CKR_OK != nssCKFWToken_verifyPointer(fwToken)) { return 0; } #endif /* NSSDEBUG */ if (!fwToken->mdToken->GetMechanismCount) { return 0; } return fwToken->mdToken->GetMechanismCount(fwToken->mdToken, fwToken, fwToken->mdInstance, fwToken->fwInstance); } /* * nssCKFWToken_GetMechanismTypes * */ NSS_IMPLEMENT CK_RV nssCKFWToken_GetMechanismTypes( NSSCKFWToken *fwToken, CK_MECHANISM_TYPE types[]) { #ifdef NSSDEBUG if (CKR_OK != nssCKFWToken_verifyPointer(fwToken)) { return CKR_ARGUMENTS_BAD; } if (!types) { return CKR_ARGUMENTS_BAD; } #endif /* NSSDEBUG */ if (!fwToken->mdToken->GetMechanismTypes) { /* * This should only be called with a sufficiently-large * "types" array, which can only be done if GetMechanismCount * is implemented. If that's implemented (and returns nonzero), * then this should be too. So return an error. */ return CKR_GENERAL_ERROR; } return fwToken->mdToken->GetMechanismTypes(fwToken->mdToken, fwToken, fwToken->mdInstance, fwToken->fwInstance, types); } /* * nssCKFWToken_GetMechanism * */ NSS_IMPLEMENT NSSCKFWMechanism * nssCKFWToken_GetMechanism( NSSCKFWToken *fwToken, CK_MECHANISM_TYPE which, CK_RV *pError) { NSSCKMDMechanism *mdMechanism; if (!fwToken->mdMechanismHash) { *pError = CKR_GENERAL_ERROR; return (NSSCKFWMechanism *)NULL; } if (!fwToken->mdToken->GetMechanism) { /* * If we don't implement any GetMechanism function, then we must * not support any. */ *pError = CKR_MECHANISM_INVALID; return (NSSCKFWMechanism *)NULL; } /* lookup in hash table */ mdMechanism = fwToken->mdToken->GetMechanism(fwToken->mdToken, fwToken, fwToken->mdInstance, fwToken->fwInstance, which, pError); if (!mdMechanism) { return (NSSCKFWMechanism *)NULL; } /* store in hash table */ return nssCKFWMechanism_Create(mdMechanism, fwToken->mdToken, fwToken, fwToken->mdInstance, fwToken->fwInstance); } NSS_IMPLEMENT CK_RV nssCKFWToken_SetSessionState( NSSCKFWToken *fwToken, CK_STATE newState) { CK_RV error = CKR_OK; #ifdef NSSDEBUG error = nssCKFWToken_verifyPointer(fwToken); if (CKR_OK != error) { return error; } switch (newState) { case CKS_RO_PUBLIC_SESSION: case CKS_RO_USER_FUNCTIONS: case CKS_RW_PUBLIC_SESSION: case CKS_RW_USER_FUNCTIONS: case CKS_RW_SO_FUNCTIONS: break; default: return CKR_ARGUMENTS_BAD; } #endif /* NSSDEBUG */ error = nssCKFWMutex_Lock(fwToken->mutex); if (CKR_OK != error) { return error; } fwToken->state = newState; (void)nssCKFWMutex_Unlock(fwToken->mutex); return CKR_OK; } /* * nssCKFWToken_RemoveSession * */ NSS_IMPLEMENT CK_RV nssCKFWToken_RemoveSession( NSSCKFWToken *fwToken, NSSCKFWSession *fwSession) { CK_RV error = CKR_OK; #ifdef NSSDEBUG error = nssCKFWToken_verifyPointer(fwToken); if (CKR_OK != error) { return error; } error = nssCKFWSession_verifyPointer(fwSession); if (CKR_OK != error) { return error; } #endif /* NSSDEBUG */ error = nssCKFWMutex_Lock(fwToken->mutex); if (CKR_OK != error) { return error; } if (CK_TRUE != nssCKFWHash_Exists(fwToken->sessions, fwSession)) { error = CKR_SESSION_HANDLE_INVALID; goto done; } nssCKFWHash_Remove(fwToken->sessions, fwSession); fwToken->sessionCount--; if (nssCKFWSession_IsRWSession(fwSession)) { fwToken->rwSessionCount--; } if (0 == fwToken->sessionCount) { fwToken->rwSessionCount = 0; /* sanity */ fwToken->state = CKS_RO_PUBLIC_SESSION; /* some default */ } error = CKR_OK; done: (void)nssCKFWMutex_Unlock(fwToken->mutex); return error; } /* * nssCKFWToken_CloseAllSessions * */ NSS_IMPLEMENT CK_RV nssCKFWToken_CloseAllSessions( NSSCKFWToken *fwToken) { CK_RV error = CKR_OK; #ifdef NSSDEBUG error = nssCKFWToken_verifyPointer(fwToken); if (CKR_OK != error) { return error; } #endif /* NSSDEBUG */ error = nssCKFWMutex_Lock(fwToken->mutex); if (CKR_OK != error) { return error; } nssCKFWHash_Iterate(fwToken->sessions, nss_ckfwtoken_session_iterator, (void *)NULL); nssCKFWHash_Destroy(fwToken->sessions); fwToken->sessions = nssCKFWHash_Create(fwToken->fwInstance, fwToken->arena, &error); if (!fwToken->sessions) { if (CKR_OK == error) { error = CKR_GENERAL_ERROR; } goto done; } fwToken->state = CKS_RO_PUBLIC_SESSION; /* some default */ fwToken->sessionCount = 0; fwToken->rwSessionCount = 0; error = CKR_OK; done: (void)nssCKFWMutex_Unlock(fwToken->mutex); return error; } /* * nssCKFWToken_GetSessionCount * */ NSS_IMPLEMENT CK_ULONG nssCKFWToken_GetSessionCount( NSSCKFWToken *fwToken) { CK_ULONG rv; #ifdef NSSDEBUG if (CKR_OK != nssCKFWToken_verifyPointer(fwToken)) { return (CK_ULONG)0; } #endif /* NSSDEBUG */ if (CKR_OK != nssCKFWMutex_Lock(fwToken->mutex)) { return (CK_ULONG)0; } rv = fwToken->sessionCount; (void)nssCKFWMutex_Unlock(fwToken->mutex); return rv; } /* * nssCKFWToken_GetRwSessionCount * */ NSS_IMPLEMENT CK_ULONG nssCKFWToken_GetRwSessionCount( NSSCKFWToken *fwToken) { CK_ULONG rv; #ifdef NSSDEBUG if (CKR_OK != nssCKFWToken_verifyPointer(fwToken)) { return (CK_ULONG)0; } #endif /* NSSDEBUG */ if (CKR_OK != nssCKFWMutex_Lock(fwToken->mutex)) { return (CK_ULONG)0; } rv = fwToken->rwSessionCount; (void)nssCKFWMutex_Unlock(fwToken->mutex); return rv; } /* * nssCKFWToken_GetRoSessionCount * */ NSS_IMPLEMENT CK_ULONG nssCKFWToken_GetRoSessionCount( NSSCKFWToken *fwToken) { CK_ULONG rv; #ifdef NSSDEBUG if (CKR_OK != nssCKFWToken_verifyPointer(fwToken)) { return (CK_ULONG)0; } #endif /* NSSDEBUG */ if (CKR_OK != nssCKFWMutex_Lock(fwToken->mutex)) { return (CK_ULONG)0; } rv = fwToken->sessionCount - fwToken->rwSessionCount; (void)nssCKFWMutex_Unlock(fwToken->mutex); return rv; } /* * nssCKFWToken_GetSessionObjectHash * */ NSS_IMPLEMENT nssCKFWHash * nssCKFWToken_GetSessionObjectHash( NSSCKFWToken *fwToken) { #ifdef NSSDEBUG if (CKR_OK != nssCKFWToken_verifyPointer(fwToken)) { return (nssCKFWHash *)NULL; } #endif /* NSSDEBUG */ return fwToken->sessionObjectHash; } /* * nssCKFWToken_GetMDObjectHash * */ NSS_IMPLEMENT nssCKFWHash * nssCKFWToken_GetMDObjectHash( NSSCKFWToken *fwToken) { #ifdef NSSDEBUG if (CKR_OK != nssCKFWToken_verifyPointer(fwToken)) { return (nssCKFWHash *)NULL; } #endif /* NSSDEBUG */ return fwToken->mdObjectHash; } /* * nssCKFWToken_GetObjectHandleHash * */ NSS_IMPLEMENT nssCKFWHash * nssCKFWToken_GetObjectHandleHash( NSSCKFWToken *fwToken) { #ifdef NSSDEBUG if (CKR_OK != nssCKFWToken_verifyPointer(fwToken)) { return (nssCKFWHash *)NULL; } #endif /* NSSDEBUG */ return fwToken->mdObjectHash; } /* * NSSCKFWToken_GetMDToken * */ NSS_IMPLEMENT NSSCKMDToken * NSSCKFWToken_GetMDToken( NSSCKFWToken *fwToken) { #ifdef DEBUG if (CKR_OK != nssCKFWToken_verifyPointer(fwToken)) { return (NSSCKMDToken *)NULL; } #endif /* DEBUG */ return nssCKFWToken_GetMDToken(fwToken); } /* * NSSCKFWToken_GetArena * */ NSS_IMPLEMENT NSSArena * NSSCKFWToken_GetArena( NSSCKFWToken *fwToken, CK_RV *pError) { #ifdef DEBUG if (!pError) { return (NSSArena *)NULL; } if (CKR_OK != nssCKFWToken_verifyPointer(fwToken)) { *pError = CKR_ARGUMENTS_BAD; return (NSSArena *)NULL; } #endif /* DEBUG */ return nssCKFWToken_GetArena(fwToken, pError); } /* * NSSCKFWToken_GetFWSlot * */ NSS_IMPLEMENT NSSCKFWSlot * NSSCKFWToken_GetFWSlot( NSSCKFWToken *fwToken) { #ifdef DEBUG if (CKR_OK != nssCKFWToken_verifyPointer(fwToken)) { return (NSSCKFWSlot *)NULL; } #endif /* DEBUG */ return nssCKFWToken_GetFWSlot(fwToken); } /* * NSSCKFWToken_GetMDSlot * */ NSS_IMPLEMENT NSSCKMDSlot * NSSCKFWToken_GetMDSlot( NSSCKFWToken *fwToken) { #ifdef DEBUG if (CKR_OK != nssCKFWToken_verifyPointer(fwToken)) { return (NSSCKMDSlot *)NULL; } #endif /* DEBUG */ return nssCKFWToken_GetMDSlot(fwToken); } /* * NSSCKFWToken_GetSessionState * */ NSS_IMPLEMENT CK_STATE NSSCKFWSession_GetSessionState( NSSCKFWToken *fwToken) { #ifdef DEBUG if (CKR_OK != nssCKFWToken_verifyPointer(fwToken)) { return CKS_RO_PUBLIC_SESSION; } #endif /* DEBUG */ return nssCKFWToken_GetSessionState(fwToken); }