/* * 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. * * This file implements PKCS 11 for FORTEZZA using MACI * drivers. Except for the Mac. They only have CI libraries, so * that's what we use there. * * For more information about PKCS 11 See PKCS 11 Token Inteface Standard. * * This implementations queries the MACI to figure out how * many slots exist on a given system. There is an artificial boundary * of 32 slots, because allocating slots dynamically caused memory * problems in the client when first this module was first developed. * Some how the heap was being corrupted and we couldn't find out where. * Subsequent attempts to allocate dynamic memory caused no problem. * * In this implementation, session objects are only visible to the session * that created or generated them. */ #include "fpkmem.h" #include "seccomon.h" #include "fpkcs11.h" #include "fpkcs11i.h" #include "cryptint.h" #include "pk11func.h" #include "fortsock.h" #include "fmutex.h" #ifdef notdef #include #include #endif #ifdef XP_MAC #ifndef __POWERPC__ #include #endif /* This is not a 4.0 project, so I can't depend on * 4.0 defines, so instead I depend on CodeWarrior * defines. I define XP_MAC in fpkmem.h */ #if __POWERPC__ #elif __CFM68K__ #else /* These include are taken fromn npmac.cpp which are used * by the plugin group to properly set-up a plug-in for * dynamic loading on 68K. */ #include /* ** The Mixed Mode procInfos defined in npupp.h assume Think C- ** style calling conventions. These conventions are used by ** Metrowerks with the exception of pointer return types, which ** in Metrowerks 68K are returned in A0, instead of the standard ** D0. Thus, since NPN_MemAlloc and NPN_UserAgent return pointers, ** Mixed Mode will return the values to a 68K plugin in D0, but ** a 68K plugin compiled by Metrowerks will expect the result in ** A0. The following pragma forces Metrowerks to use D0 instead. */ #ifdef __MWERKS__ #ifndef powerc #pragma pointers_in_D0 #endif #endif #ifdef __MWERKS__ #ifndef powerc #pragma pointers_in_A0 #endif #endif /* The following fix for static initializers fixes a previous ** incompatibility with some parts of PowerPlant. */ #ifdef __MWERKS__ #ifdef __cplusplus extern "C" { #endif #ifndef powerc extern void __InitCode__(void); #else extern void __sinit(void); #endif extern void __destroy_global_chain(void); #ifdef __cplusplus } #endif /* __cplusplus */ #endif /* __MWERKS__ */ #endif #endif typedef struct { unsigned char *data; int len; } CertItem; /* * ******************** Static data ******************************* */ /* The next three strings must be exactly 32 characters long */ static char *manufacturerID = "Netscape Communications Corp "; static char *libraryDescription = "Communicator Fortezza Crypto Svc"; typedef enum {DSA_KEY, KEA_KEY, V1_KEY, INVALID_KEY } PrivKeyType; static PK11Slot fort11_slot[NUM_SLOTS]; static FortezzaSocket fortezzaSockets[NUM_SLOTS]; static PRBool init = PR_FALSE; static CK_ULONG kNumSockets = 0; #define __PASTE(x,y) x##y #undef CK_FUNC #undef CK_EXTERN #undef CK_NEED_ARG_LIST #undef _CK_RV #define fort11_attr_expand(ap) (ap)->type,(ap)->pValue,(ap)->ulValueLen #define fort11_SlotFromSession pk11_SlotFromSession #define fort11_isToken pk11_isToken static CK_FUNCTION_LIST fort11_funcList = { { 2, 1 }, #undef CK_FUNC #undef CK_EXTERN #undef CK_NEED_ARG_LIST #undef _CK_RV #define CK_EXTERN #define CK_FUNC(name) name, #define _CK_RV #include "fpkcs11f.h" }; #undef CK_FUNC #undef CK_EXTERN #undef _CK_RV #undef __PASTE #undef pk11_SlotFromSessionHandle #undef pk11_SlotFromID #define MAJOR_VERSION_MASK 0xFF00 #define MINOR_VERSION_MASK 0x00FF /* Mechanisms */ struct mechanismList { CK_MECHANISM_TYPE type; CK_MECHANISM_INFO domestic; PRBool privkey; }; static struct mechanismList mechanisms[] = { {CKM_DSA, {512,1024,CKF_SIGN}, PR_TRUE}, {CKM_SKIPJACK_KEY_GEN, {92, 92, CKF_GENERATE}, PR_TRUE}, {CKM_SKIPJACK_CBC64, {92, 92, CKF_ENCRYPT | CKF_DECRYPT}, PR_TRUE}, {CKM_SKIPJACK_WRAP, {92, 92, CKF_WRAP}, PR_TRUE}, {CKM_KEA_KEY_DERIVE, {128, 128, CKF_DERIVE}, PR_TRUE}, }; static CK_ULONG mechanismCount = sizeof(mechanisms)/sizeof(mechanisms[0]); /*************Static function prototypes********************************/ static PRBool fort11_isTrue(PK11Object *object,CK_ATTRIBUTE_TYPE type); static void fort11_FreeAttribute(PK11Attribute *attribute); static void fort11_DestroyAttribute(PK11Attribute *attribute); static PK11Object* fort11_NewObject(PK11Slot *slot); static PK11FreeStatus fort11_FreeObject(PK11Object *object); static CK_RV fort11_AddAttributeType(PK11Object *object, CK_ATTRIBUTE_TYPE type, void *valPtr, CK_ULONG length); static void fort11_AddSlotObject(PK11Slot *slot, PK11Object *object); static PK11Attribute* fort11_FindAttribute(PK11Object *object, CK_ATTRIBUTE_TYPE type); static PK11Attribute* fort11_NewAttribute(CK_ATTRIBUTE_TYPE type, CK_VOID_PTR value, CK_ULONG len); static void fort11_DeleteAttributeType(PK11Object *object, CK_ATTRIBUTE_TYPE type); static void fort11_AddAttribute(PK11Object *object, PK11Attribute *attribute); static void fort11_AddObject(PK11Session *session, PK11Object *object); static PK11Object * fort11_ObjectFromHandle(CK_OBJECT_HANDLE handle, PK11Session *session); static void fort11_DeleteObject(PK11Session *session,PK11Object *object); static CK_RV fort11_DestroyObject(PK11Object *object); void fort11_FreeSession(PK11Session *session); #define FIRST_SLOT_SESS_ID 0x00000100L #define ADD_NEXT_SESS_ID 0x00000100L #define SLOT_MASK 0x000000FFL #define FAILED CKR_FUNCTION_FAILED static void fort11_FreeFortezzaKey (void *inFortezzaKey) { RemoveKey ((FortezzaKey*) inFortezzaKey); } static void fort11_DestroySlotObjects (PK11Slot *slot, PK11Session *session) { PK11Object *currObject, *nextObject, *oldObject; int i; for (i=0; itokObjects[i]; slot->tokObjects[i] = NULL; do { FMUTEX_Lock(slot->sessionLock); if (currObject) { nextObject = currObject->next; FMUTEX_Lock(currObject->refLock); currObject->refCount++; FMUTEX_Unlock(currObject->refLock); fort11_DeleteObject(session, currObject); } FMUTEX_Unlock(slot->sessionLock); if (currObject) { oldObject = currObject; currObject = nextObject; fort11_FreeObject(oldObject); } } while (currObject != NULL); } } static void fort11_TokenRemoved(PK11Slot *slot, PK11Session *session) { FortezzaSocket *socket = &fortezzaSockets[slot->slotID-1]; LogoutFromSocket (socket); slot->isLoggedIn = PR_FALSE; if (session && session->notify) { /*If no session pointer exists, lots of leaked memory*/ session->notify (session->handle, CKN_SURRENDER, session->appData); fort11_FreeSession(session); /* Release the reference held * by the slot with the session */ } fort11_DestroySlotObjects(slot, session); fort11_FreeSession(session); /* Release the reference held * by the slot with the session */ /* All keys will have been freed at this point so we can * NULL out this pointer */ socket->keys = NULL; } PRBool fort11_FortezzaIsUserCert(unsigned char * label) { if ( (!PORT_Memcmp(label, "KEAK", 4)) || /* v3 user certs */ (!PORT_Memcmp(label, "DSA1", 4)) || (!PORT_Memcmp(label, "DSAI", 4)) || (!PORT_Memcmp(label, "DSAO", 4)) || (!PORT_Memcmp(label, "INKS", 4)) || /* v1 user certs */ (!PORT_Memcmp(label, "INKX", 4)) || (!PORT_Memcmp(label, "ONKS", 4)) || (!PORT_Memcmp(label, "ONKX", 4)) || (!PORT_Memcmp(label, "3IXS", 4)) || /* old v3 user certs */ (!PORT_Memcmp(label, "3OXS", 4)) || (!PORT_Memcmp(label, "3IKX", 4)) ) { return PR_TRUE; } else { return PR_FALSE; } } static PRBool fort11_FortezzaIsACert(unsigned char * label) { if (label == NULL) return PR_FALSE; if ( (!PORT_Memcmp(label, "DSA1", 4)) || /* v3 certs */ (!PORT_Memcmp(label, "DSAI", 4)) || (!PORT_Memcmp(label, "DSAO", 4)) || (!PORT_Memcmp(label, "DSAX", 4)) || (!PORT_Memcmp(label, "KEAK", 4)) || (!PORT_Memcmp(label, "KEAX", 4)) || (!PORT_Memcmp(label, "CAX1", 4)) || (!PORT_Memcmp(label, "PCA1", 4)) || (!PORT_Memcmp(label, "PAA1", 4)) || (!PORT_Memcmp(label, "ICA1", 4)) || (!PORT_Memcmp(label, "3IXS", 4)) || /* old v3 certs */ (!PORT_Memcmp(label, "3OXS", 4)) || (!PORT_Memcmp(label, "3CAX", 4)) || (!PORT_Memcmp(label, "3IKX", 4)) || (!PORT_Memcmp(label, "3PCA", 4)) || (!PORT_Memcmp(label, "3PAA", 4)) || (!PORT_Memcmp(label, "3ICA", 4)) || (!PORT_Memcmp(label, "INKS", 4)) || /* v1 certs */ (!PORT_Memcmp(label, "INKX", 4)) || (!PORT_Memcmp(label, "ONKS", 4)) || (!PORT_Memcmp(label, "ONKX", 4)) || (!PORT_Memcmp(label, "RRXX", 4)) || (!PORT_Memcmp(label, "RTXX", 4)) || (!PORT_Memcmp(label, "LAXX", 4)) ) { return PR_TRUE; } return PR_FALSE; } static int fort11_cert_length(unsigned char *buf, int length) { unsigned char tag; int used_length= 0; int data_length; tag = buf[used_length++]; /* blow out when we come to the end */ if (tag == 0) { return 0; } data_length = buf[used_length++]; if (data_length&0x80) { int len_count = data_length & 0x7f; data_length = 0; while (len_count-- > 0) { data_length = (data_length << 8) | buf[used_length++]; } } if (data_length > (length-used_length) ) { return length; } return (data_length + used_length); } unsigned char *fort11_data_start(unsigned char *buf, int length, int *data_length, PRBool includeTag) { unsigned char tag; int used_length= 0; tag = buf[used_length++]; /* blow out when we come to the end */ if (tag == 0) { return NULL; } *data_length = buf[used_length++]; if (*data_length&0x80) { int len_count = *data_length & 0x7f; *data_length = 0; while (len_count-- > 0) { *data_length = (*data_length << 8) | buf[used_length++]; } } if (*data_length > (length-used_length) ) { *data_length = length-used_length; return NULL; } if (includeTag) *data_length += used_length; return (buf + (includeTag ? 0 : used_length)); } int fort11_GetCertFields(unsigned char *cert,int cert_length,CertItem *issuer, CertItem *serial,CertItem *subject) { unsigned char *buf; int buf_length; unsigned char *date; int datelen; /* get past the signature wrap */ buf = fort11_data_start(cert,cert_length,&buf_length,PR_FALSE); if (buf == NULL) return FAILED; /* get into the raw cert data */ buf = fort11_data_start(buf,buf_length,&buf_length,PR_FALSE); if (buf == NULL) return FAILED; /* skip past any optional version number */ if ((buf[0] & 0xa0) == 0xa0) { date = fort11_data_start(buf,buf_length,&datelen,PR_FALSE); if (date == NULL) return FAILED; buf_length -= (date-buf) + datelen; buf = date + datelen; } /* serial number */ serial->data = fort11_data_start(buf,buf_length,&serial->len,PR_FALSE); if (serial->data == NULL) return FAILED; buf_length -= (serial->data-buf) + serial->len; buf = serial->data + serial->len; /* skip the OID */ date = fort11_data_start(buf,buf_length,&datelen,PR_FALSE); if (date == NULL) return FAILED; buf_length -= (date-buf) + datelen; buf = date + datelen; /* issuer */ issuer->data = fort11_data_start(buf,buf_length,&issuer->len,PR_TRUE); if (issuer->data == NULL) return FAILED; buf_length -= (issuer->data-buf) + issuer->len; buf = issuer->data + issuer->len; /* skip the date */ date = fort11_data_start(buf,buf_length,&datelen,PR_FALSE); if (date == NULL) return FAILED; buf_length -= (date-buf) + datelen; buf = date + datelen; /*subject */ subject->data=fort11_data_start(buf,buf_length,&subject->len,PR_TRUE); if (subject->data == NULL) return FAILED; buf_length -= (subject->data-buf) + subject->len; buf = subject->data +subject->len; /*subject */ return CKR_OK; } /* quick tohex function to get rid of scanf */ static int fort11_tohex(char *s) { int val = 0; for(;*s;s++) { if ((*s >= '0') && (*s <= '9')) { val = (val << 4) + (*s - '0'); continue; } else if ((*s >= 'a') && (*s <= 'f')) { val = (val << 4) + (*s - 'a') + 10; continue; } else if ((*s >= 'A') && (*s <= 'F')) { val = (val << 4) + (*s - 'A') + 10; continue; } break; } return val; } /* only should be called for V3 KEA cert labels. */ static int fort11_GetSibling(CI_CERT_STR label) { int value = 0; char s[3]; label +=4; strcpy(s,"00"); memcpy(s, label, 2); value = fort11_tohex(s); /* sibling of 255 means no sibling */ if (value == 255) { value = -1; } return value; } static PrivKeyType fort11_GetKeyType(CI_CERT_STR label) { if (label == NULL) return INVALID_KEY; if ( (!PORT_Memcmp(label, "DSA1", 4)) || /* v3 certs */ (!PORT_Memcmp(label, "DSAI", 4)) || (!PORT_Memcmp(label, "DSAO", 4)) || (!PORT_Memcmp(label, "3IXS", 4)) || /* old v3 certs */ (!PORT_Memcmp(label, "3OXS", 4)) ) { return DSA_KEY; } if ( (!PORT_Memcmp(label, "KEAK", 4)) || (!PORT_Memcmp(label, "3IKX", 4)) ) { return KEA_KEY; } if ( (!PORT_Memcmp(label, "INKS", 4)) || /* V1 Certs*/ (!PORT_Memcmp(label, "INKX", 4)) || (!PORT_Memcmp(label, "ONKS", 4)) || (!PORT_Memcmp(label, "ONKX", 4)) || (!PORT_Memcmp(label, "RRXX", 4)) || (!PORT_Memcmp(label, "RTXX", 4)) || (!PORT_Memcmp(label, "LAXX", 4)) ) { return V1_KEY; } return INVALID_KEY; } static CK_RV fort11_ConvertToDSAKey(PK11Object *privateKey, PK11Slot *slot) { CK_KEY_TYPE key_type = CKK_DSA; CK_BBOOL cktrue = TRUE; CK_BBOOL ckfalse = FALSE; CK_OBJECT_CLASS privClass = CKO_PRIVATE_KEY; CK_CHAR label[] = "A DSA Private Key"; /* Fill in the common Default values */ if (fort11_AddAttributeType(privateKey,CKA_START_DATE, NULL, 0) != CKR_OK) { return CKR_GENERAL_ERROR; } if (fort11_AddAttributeType(privateKey,CKA_END_DATE, NULL, 0) != CKR_OK) { return CKR_GENERAL_ERROR; } if (fort11_AddAttributeType(privateKey,CKA_SUBJECT, NULL, 0) != CKR_OK) { return CKR_GENERAL_ERROR; } if (fort11_AddAttributeType(privateKey, CKA_CLASS, &privClass, sizeof (CK_OBJECT_CLASS)) != CKR_OK) { return CKR_GENERAL_ERROR; } if (fort11_AddAttributeType(privateKey, CKA_KEY_TYPE, &key_type, sizeof(CK_KEY_TYPE)) != CKR_OK) { return CKR_GENERAL_ERROR; } if (fort11_AddAttributeType (privateKey, CKA_TOKEN, &cktrue, sizeof (CK_BBOOL)) != CKR_OK) { return CKR_GENERAL_ERROR; } if (fort11_AddAttributeType (privateKey, CKA_LABEL, label, PORT_Strlen((char*)label)) != CKR_OK) { return CKR_GENERAL_ERROR; } if (fort11_AddAttributeType(privateKey, CKA_SENSITIVE, &cktrue, sizeof (CK_BBOOL)) != CKR_OK) { return CKR_GENERAL_ERROR; } if (fort11_AddAttributeType(privateKey, CKA_SIGN, &cktrue, sizeof (CK_BBOOL)) != CKR_OK) { return CKR_GENERAL_ERROR; } if (fort11_AddAttributeType(privateKey, CKA_DERIVE, &cktrue, sizeof(cktrue)) != CKR_OK) { return CKR_GENERAL_ERROR; } if (fort11_AddAttributeType(privateKey, CKA_LOCAL, &ckfalse, sizeof(ckfalse)) != CKR_OK) { return CKR_GENERAL_ERROR; } if (fort11_AddAttributeType(privateKey, CKA_DECRYPT, &ckfalse, sizeof(ckfalse)) != CKR_OK) { return CKR_GENERAL_ERROR; } if (fort11_AddAttributeType(privateKey, CKA_SIGN_RECOVER, &ckfalse, sizeof(ckfalse)) != CKR_OK) { return CKR_GENERAL_ERROR; } if (fort11_AddAttributeType(privateKey, CKA_UNWRAP, &ckfalse, sizeof(ckfalse)) != CKR_OK) { return CKR_GENERAL_ERROR; } if (fort11_AddAttributeType(privateKey, CKA_EXTRACTABLE, &ckfalse, sizeof(ckfalse)) != CKR_OK) { return CKR_GENERAL_ERROR; } if (fort11_AddAttributeType(privateKey, CKA_ALWAYS_SENSITIVE, &cktrue, sizeof(cktrue)) != CKR_OK) { return CKR_GENERAL_ERROR; } if (fort11_AddAttributeType(privateKey, CKA_NEVER_EXTRACTABLE, &cktrue, sizeof(ckfalse)) != CKR_OK) { return CKR_GENERAL_ERROR; } if (fort11_AddAttributeType(privateKey, CKA_PRIME, NULL, 0) != CKR_OK){ return CKR_GENERAL_ERROR; } if (fort11_AddAttributeType(privateKey, CKA_SUBPRIME, NULL, 0) != CKR_OK){ return CKR_GENERAL_ERROR; } if (fort11_AddAttributeType(privateKey, CKA_BASE, NULL, 0) != CKR_OK) { return CKR_GENERAL_ERROR; } if (fort11_AddAttributeType(privateKey, CKA_VALUE, NULL, 0) != CKR_OK) { return CKR_GENERAL_ERROR; } if (fort11_AddAttributeType(privateKey, CKA_PRIVATE, &cktrue, sizeof(cktrue)) != CKR_OK) { return CKR_GENERAL_ERROR; } if (fort11_AddAttributeType(privateKey, CKA_MODIFIABLE,&ckfalse, sizeof(ckfalse)) != CKR_OK) { return CKR_GENERAL_ERROR; } FMUTEX_Lock(slot->objectLock); privateKey->handle = slot->tokenIDCount++; privateKey->handle |= (PK11_TOKEN_MAGIC | PK11_TOKEN_TYPE_PRIV); FMUTEX_Unlock(slot->objectLock); privateKey->objclass = privClass; privateKey->slot = slot; privateKey->inDB = PR_TRUE; return CKR_OK; } static int fort11_LoadRootPAAKey(PK11Slot *slot, PK11Session *session) { CK_OBJECT_CLASS theClass = CKO_SECRET_KEY; int id = 0; CK_BBOOL True = TRUE; CK_BBOOL False = FALSE; CK_CHAR label[] = "Trusted Root PAA Key"; PK11Object *rootKey; FortezzaKey *newKey; FortezzaSocket *socket = &fortezzaSockets[slot->slotID-1]; /*Don't know the key type. Does is matter?*/ rootKey = fort11_NewObject(slot); if (rootKey == NULL) { return CKR_HOST_MEMORY; } if (fort11_AddAttributeType(rootKey, CKA_CLASS, &theClass, sizeof(theClass)) != CKR_OK) { return CKR_GENERAL_ERROR; } if (fort11_AddAttributeType(rootKey, CKA_TOKEN, &True, sizeof(True)) != CKR_OK) { return CKR_GENERAL_ERROR; } if (fort11_AddAttributeType(rootKey, CKA_LABEL, label, sizeof(label)) != CKR_OK) { return CKR_GENERAL_ERROR; } if (fort11_AddAttributeType(rootKey, CKA_PRIVATE, &True, sizeof (True)) != CKR_OK) { return CKR_GENERAL_ERROR; } if (fort11_AddAttributeType(rootKey,CKA_MODIFIABLE, &False, sizeof(False)) != CKR_OK) { return CKR_GENERAL_ERROR; } if (fort11_AddAttributeType(rootKey, CKA_ID, &id, sizeof(int)) != CKR_OK) { return CKR_GENERAL_ERROR; } if (fort11_AddAttributeType(rootKey, CKA_DERIVE, &True, sizeof(True)) != CKR_OK) { return CKR_GENERAL_ERROR; } if (fort11_AddAttributeType(rootKey, CKA_SENSITIVE, &True, sizeof(True)) != CKR_OK) { return CKR_GENERAL_ERROR; } FMUTEX_Lock(slot->objectLock); rootKey->handle = slot->tokenIDCount++; rootKey->handle |= (PK11_TOKEN_MAGIC | PK11_TOKEN_TYPE_PRIV); FMUTEX_Unlock(slot->objectLock); rootKey->objclass = theClass; rootKey->slot = slot; rootKey->inDB = PR_TRUE; newKey = NewFortezzaKey(socket, Ks, NULL, 0); if (newKey == NULL) { fort11_FreeObject(rootKey); return CKR_HOST_MEMORY; } rootKey->objectInfo = (void*)newKey; rootKey->infoFree = fort11_FreeFortezzaKey; fort11_AddObject(session, rootKey); return CKR_OK; } static CK_RV fort11_ConvertToKEAKey (PK11Object *privateKey, PK11Slot *slot) { CK_OBJECT_CLASS theClass = CKO_PRIVATE_KEY; CK_KEY_TYPE keyType = CKK_KEA; CK_CHAR label[] = "A KEA private key Object"; CK_BBOOL True = TRUE; CK_BBOOL False = FALSE; if (fort11_AddAttributeType(privateKey, CKA_CLASS, &theClass, sizeof (CK_OBJECT_CLASS)) != CKR_OK) { return CKR_GENERAL_ERROR; } if (fort11_AddAttributeType(privateKey, CKA_KEY_TYPE, &keyType, sizeof (CK_KEY_TYPE)) != CKR_OK) { return CKR_GENERAL_ERROR; } if (fort11_AddAttributeType(privateKey, CKA_TOKEN, &True, sizeof(CK_BBOOL)) != CKR_OK) { return CKR_GENERAL_ERROR; } if (fort11_AddAttributeType (privateKey, CKA_LABEL, label, PORT_Strlen((char*)label)) != CKR_OK) { return CKR_GENERAL_ERROR; } if (fort11_AddAttributeType (privateKey, CKA_SENSITIVE, &True, sizeof(CK_BBOOL)) != CKR_OK) { return CKR_GENERAL_ERROR; } if (fort11_AddAttributeType (privateKey, CKA_DERIVE, &True, sizeof(CK_BBOOL)) != CKR_OK) { return CKR_GENERAL_ERROR; } if (fort11_AddAttributeType(privateKey, CKA_PRIVATE, &True, sizeof(True)) != CKR_OK) { return CKR_GENERAL_ERROR; } if (fort11_AddAttributeType(privateKey, CKA_START_DATE, NULL, 0) != CKR_OK) { return CKR_GENERAL_ERROR; } if (fort11_AddAttributeType(privateKey, CKA_END_DATE, NULL, 0) != CKR_OK) { return CKR_GENERAL_ERROR; } if (fort11_AddAttributeType(privateKey, CKA_LOCAL, &False, sizeof(False)) != CKR_OK) { return CKR_GENERAL_ERROR; } FMUTEX_Lock(slot->objectLock); privateKey->handle = slot->tokenIDCount++; privateKey->handle |= (PK11_TOKEN_MAGIC | PK11_TOKEN_TYPE_PRIV); FMUTEX_Unlock(slot->objectLock); privateKey->objclass = theClass; privateKey->slot = slot; privateKey->inDB = PR_TRUE; return CKR_OK; } static CK_RV fort11_ConvertToV1Key (PK11Object* privateKey, PK11Slot *slot) { CK_RV rv; CK_BBOOL True = TRUE; rv = fort11_ConvertToDSAKey(privateKey, slot); if (rv != CKR_OK) { return rv; } if (fort11_AddAttributeType(privateKey, CKA_DERIVE, &True, sizeof (CK_BBOOL)) != CKR_OK) { return CKR_GENERAL_ERROR; } return CKR_OK; } static CK_RV fort11_NewPrivateKey(PK11Object *privKeyObject, PK11Slot *slot,CI_PERSON currPerson) { PrivKeyType keyType = fort11_GetKeyType(currPerson.CertLabel); CK_RV rv; switch (keyType) { case DSA_KEY: rv = fort11_ConvertToDSAKey(privKeyObject, slot); break; case KEA_KEY: rv = fort11_ConvertToKEAKey(privKeyObject, slot); break; case V1_KEY: rv = fort11_ConvertToV1Key(privKeyObject, slot); break; default: rv = CKR_GENERAL_ERROR; break; } return rv; } PRBool fort11_LoadCertObjectForSearch(CI_PERSON currPerson, PK11Slot *slot, PK11Session *session, CI_PERSON *pers_array) { PK11Object *certObject, *privKeyObject; PK11Attribute *attribute, *newAttribute; int ci_rv; CI_CERTIFICATE cert; CK_OBJECT_CLASS certClass = CKO_CERTIFICATE; CK_CERTIFICATE_TYPE certType = CKC_X_509; CK_BBOOL cktrue = TRUE; CK_BBOOL ckfalse = FALSE; CertItem issuer, serial, subject; int certSize; char nickname[50]; char *cursor; PrivKeyType priv_key; int sibling; certObject = fort11_NewObject(slot); if (certObject == NULL) return PR_FALSE; ci_rv = MACI_GetCertificate (fortezzaSockets[slot->slotID-1].maciSession, currPerson.CertificateIndex, cert); if (ci_rv != CI_OK){ fort11_FreeObject(certObject); return PR_FALSE; } ci_rv = fort11_GetCertFields(cert,CI_CERT_SIZE,&issuer,&serial,&subject); if (ci_rv != CKR_OK) { fort11_FreeObject(certObject); return PR_FALSE; } if (fort11_AddAttributeType(certObject, CKA_CLASS, &certClass, sizeof (CK_OBJECT_CLASS)) != CKR_OK) { fort11_FreeObject (certObject); return PR_FALSE; } if (fort11_AddAttributeType(certObject, CKA_TOKEN, &cktrue, sizeof (CK_BBOOL)) != CKR_OK) { fort11_FreeObject(certObject); return PR_FALSE; } if (fort11_AddAttributeType(certObject, CKA_PRIVATE, &ckfalse, sizeof (CK_BBOOL)) != CKR_OK) { fort11_FreeObject(certObject); return PR_FALSE; } /* check if the label represents a KEA key. if so, the nickname should be made the same as the corresponding DSA sibling cert. */ priv_key = fort11_GetKeyType(currPerson.CertLabel); if (priv_key == KEA_KEY) { sibling = fort11_GetSibling(currPerson.CertLabel); /* check for failure of fort11_GetSibling. also check that the sibling is not zero. */ if (sibling > 0) { /* assign the KEA cert label to be the same as the sibling DSA label */ sprintf (nickname, "%s", &pers_array[sibling-1].CertLabel[8] ); } else { sprintf (nickname, "%s", &currPerson.CertLabel[8]); } } else { sprintf (nickname, "%s", &currPerson.CertLabel[8]); } cursor = nickname+PORT_Strlen(nickname)-1; while ((*cursor) == ' ') { cursor--; } cursor[1] = '\0'; if (fort11_AddAttributeType(certObject, CKA_LABEL, nickname, PORT_Strlen(nickname)) != CKR_OK) { fort11_FreeObject(certObject); return PR_FALSE; } if (fort11_AddAttributeType(certObject, CKA_CERTIFICATE_TYPE, &certType, sizeof(CK_CERTIFICATE_TYPE)) != CKR_OK) { fort11_FreeObject(certObject); return PR_FALSE; } certSize = fort11_cert_length(cert,CI_CERT_SIZE); if (fort11_AddAttributeType (certObject, CKA_VALUE, cert, certSize) != CI_OK) { fort11_FreeObject(certObject); return PR_FALSE; } if (fort11_AddAttributeType(certObject, CKA_ISSUER, issuer.data, issuer.len) != CKR_OK) { fort11_FreeObject (certObject); return PR_FALSE; } if (fort11_AddAttributeType(certObject, CKA_SUBJECT, subject.data, subject.len) != CKR_OK) { fort11_FreeObject (certObject); return PR_FALSE; } if (fort11_AddAttributeType(certObject, CKA_SERIAL_NUMBER, serial.data, serial.len) != CKR_OK) { fort11_FreeObject(certObject); return PR_FALSE; } /*Change this to a byte array later*/ if (fort11_AddAttributeType(certObject, CKA_ID, &currPerson.CertificateIndex, sizeof(int)) != CKR_OK) { fort11_FreeObject(certObject); return PR_FALSE; } certObject->objectInfo = NULL; certObject->infoFree = NULL; certObject->objclass = certClass; certObject->slot = slot; certObject->inDB = PR_TRUE; FMUTEX_Lock(slot->objectLock); certObject->handle = slot->tokenIDCount++; certObject->handle |= (PK11_TOKEN_MAGIC | PK11_TOKEN_TYPE_CERT); FMUTEX_Unlock(slot->objectLock); if (fort11_FortezzaIsUserCert (currPerson.CertLabel)) { privKeyObject = fort11_NewObject(slot); if (fort11_NewPrivateKey(privKeyObject, slot, currPerson) != CKR_OK) { fort11_FreeObject(privKeyObject); fort11_FreeObject(certObject); return PR_FALSE; } if(fort11_AddAttributeType(privKeyObject,CKA_ID, &currPerson.CertificateIndex, sizeof(int)) != CKR_OK) { fort11_FreeObject(privKeyObject); fort11_FreeObject(certObject); return PR_FALSE; } attribute = fort11_FindAttribute(certObject,CKA_SUBJECT); newAttribute= fort11_NewAttribute(pk11_attr_expand(&attribute->attrib)); fort11_FreeAttribute(attribute); if (newAttribute != NULL) { fort11_DeleteAttributeType(privKeyObject, CKA_SUBJECT); fort11_AddAttribute(privKeyObject, newAttribute); } fort11_AddObject (session, privKeyObject); } fort11_AddObject (session, certObject); return PR_TRUE; } #define TRUSTED_PAA "00000000Trusted Root PAA" static int fort11_BuildCertObjects(FortezzaSocket *currSocket, PK11Slot *slot, PK11Session *session) { int i; CI_PERSON rootPAA; PORT_Memcpy (rootPAA.CertLabel, TRUSTED_PAA, 1+PORT_Strlen (TRUSTED_PAA)); rootPAA.CertificateIndex = 0; if (!fort11_LoadCertObjectForSearch(rootPAA, slot, session, currSocket->personalityList)) { return CKR_GENERAL_ERROR; } if (fort11_LoadRootPAAKey(slot, session) != CKR_OK) { return CKR_GENERAL_ERROR; } for (i=0 ; i < currSocket->numPersonalities; i++) { if (fort11_FortezzaIsACert (currSocket->personalityList[i].CertLabel)){ if (!fort11_LoadCertObjectForSearch(currSocket->personalityList[i], slot, session, currSocket->personalityList)){ return CKR_GENERAL_ERROR; } } } return CKR_OK; } PK11Slot* fort11_SlotFromSessionHandle(CK_SESSION_HANDLE inHandle) { CK_SESSION_HANDLE whichSlot = inHandle & SLOT_MASK; if (whichSlot >= kNumSockets) return NULL_PTR; return &fort11_slot[whichSlot]; } PK11Slot* fort11_SlotFromID (CK_SLOT_ID inSlotID) { if (inSlotID == 0 || inSlotID > kNumSockets) return NULL; return &fort11_slot[inSlotID-1]; } CK_ULONG fort11_firstSessionID (int inSlotNum) { return (CK_ULONG)(inSlotNum); } /* * Utility to convert passed in PIN to a CI_PIN */ void fort11_convertToCIPin (CI_PIN ciPin,CK_CHAR_PTR pPin, CK_ULONG ulLen) { unsigned long i; for (i=0; iattributeLock); pk11queue_find(attribute,type,object->head,HASH_SIZE); FMUTEX_Unlock(object->attributeLock); return (PRBool)(attribute != NULL); } /* * create a new attribute with type, value, and length. Space is allocated * to hold value. */ static PK11Attribute * fort11_NewAttribute(CK_ATTRIBUTE_TYPE type, CK_VOID_PTR value, CK_ULONG len) { PK11Attribute *attribute; CK_RV mrv; attribute = (PK11Attribute*)PORT_Alloc(sizeof(PK11Attribute)); if (attribute == NULL) return NULL; attribute->attrib.type = type; if (value) { attribute->attrib.pValue = (CK_VOID_PTR)PORT_Alloc(len); if (attribute->attrib.pValue == NULL) { PORT_Free(attribute); return NULL; } PORT_Memcpy(attribute->attrib.pValue,value,len); attribute->attrib.ulValueLen = len; } else { attribute->attrib.pValue = NULL; attribute->attrib.ulValueLen = 0; } attribute->handle = type; attribute->next = attribute->prev = NULL; attribute->refCount = 1; if (FMUTEX_MutexEnabled()) { mrv = FMUTEX_Create (&attribute->refLock); if (mrv != CKR_OK) { if (attribute->attrib.pValue) PORT_Free(attribute->attrib.pValue); PORT_Free(attribute); return NULL; } } else { attribute->refLock = NULL; } return attribute; } /* * add an attribute to an object */ static void fort11_AddAttribute(PK11Object *object,PK11Attribute *attribute) { FMUTEX_Lock (object->attributeLock); pk11queue_add(attribute,attribute->handle,object->head,HASH_SIZE); FMUTEX_Unlock(object->attributeLock); } static CK_RV fort11_AddAttributeType(PK11Object *object,CK_ATTRIBUTE_TYPE type,void *valPtr, CK_ULONG length) { PK11Attribute *attribute; attribute = fort11_NewAttribute(type,valPtr,length); if (attribute == NULL) { return CKR_HOST_MEMORY; } fort11_AddAttribute(object,attribute); return CKR_OK; } /* Make sure a given attribute exists. If it doesn't, initialize it to * value and len */ static CK_RV fort11_forceAttribute(PK11Object *object,CK_ATTRIBUTE_TYPE type,void *value, unsigned int len) { if ( !fort11_hasAttribute(object, type)) { return fort11_AddAttributeType(object,type,value,len); } return CKR_OK; } /* * look up and attribute structure from a type and Object structure. * The returned attribute is referenced and needs to be freed when * it is no longer needed. */ static PK11Attribute * fort11_FindAttribute(PK11Object *object,CK_ATTRIBUTE_TYPE type) { PK11Attribute *attribute; FMUTEX_Lock(object->attributeLock); pk11queue_find(attribute,type,object->head,HASH_SIZE); if (attribute) { /* atomic increment would be nice here */ FMUTEX_Lock(attribute->refLock); attribute->refCount++; FMUTEX_Unlock(attribute->refLock); } FMUTEX_Unlock(object->attributeLock); return(attribute); } /* * this is only valid for CK_BBOOL type attributes. Return the state * of that attribute. */ static PRBool fort11_isTrue(PK11Object *object,CK_ATTRIBUTE_TYPE type) { PK11Attribute *attribute; PRBool tok = PR_FALSE; attribute=fort11_FindAttribute(object,type); if (attribute == NULL) { return PR_FALSE; } tok = (PRBool)(*(CK_BBOOL *)attribute->attrib.pValue); fort11_FreeAttribute(attribute); return tok; } /* * add an object to a slot and session queue */ static void fort11_AddSlotObject(PK11Slot *slot, PK11Object *object) { FMUTEX_Lock(slot->objectLock); pk11queue_add(object,object->handle,slot->tokObjects,HASH_SIZE); FMUTEX_Unlock(slot->objectLock); } static void fort11_AddObject(PK11Session *session, PK11Object *object) { PK11Slot *slot = fort11_SlotFromSession(session); if (!fort11_isToken(object->handle)) { FMUTEX_Lock(session->objectLock); pk11queue_add(&object->sessionList,0,session->objects,0); FMUTEX_Unlock(session->objectLock); } fort11_AddSlotObject(slot,object); } /* * free all the data associated with an object. Object reference count must * be 'zero'. */ static CK_RV fort11_DestroyObject(PK11Object *object) { int i; CK_RV crv = CKR_OK; /* PORT_Assert(object->refCount == 0);*/ if (object->label) PORT_Free(object->label); /* clean out the attributes */ /* since no one is referencing us, it's safe to walk the chain * without a lock */ for (i=0; i < HASH_SIZE; i++) { PK11Attribute *ap,*next; for (ap = object->head[i]; ap != NULL; ap = next) { next = ap->next; /* paranoia */ ap->next = ap->prev = NULL; fort11_FreeAttribute(ap); } object->head[i] = NULL; } FMUTEX_Destroy(object->attributeLock); FMUTEX_Destroy(object->refLock); if (object->objectInfo) { (*object->infoFree)(object->objectInfo); } PORT_Free(object); return crv; } /* * release a reference to an attribute structure */ static void fort11_FreeAttribute(PK11Attribute *attribute) { PRBool destroy = PR_FALSE; FMUTEX_Lock(attribute->refLock); if (attribute->refCount == 1) destroy = PR_TRUE; attribute->refCount--; FMUTEX_Unlock(attribute->refLock); if (destroy) fort11_DestroyAttribute(attribute); } /* * release a reference to an object handle */ static PK11FreeStatus fort11_FreeObject(PK11Object *object) { PRBool destroy = PR_FALSE; CK_RV crv; FMUTEX_Lock(object->refLock); if (object->refCount == 1) destroy = PR_TRUE; object->refCount--; FMUTEX_Unlock(object->refLock); if (destroy) { crv = fort11_DestroyObject(object); if (crv != CKR_OK) { return PK11_DestroyFailure; } return PK11_Destroyed; } return PK11_Busy; } static void fort11_update_state(PK11Slot *slot,PK11Session *session) { if (slot->isLoggedIn) { if (slot->ssoLoggedIn) { session->info.state = CKS_RW_SO_FUNCTIONS; } else if (session->info.flags & CKF_RW_SESSION) { session->info.state = CKS_RW_USER_FUNCTIONS; } else { session->info.state = CKS_RO_USER_FUNCTIONS; } } else { if (session->info.flags & CKF_RW_SESSION) { session->info.state = CKS_RW_PUBLIC_SESSION; } else { session->info.state = CKS_RO_PUBLIC_SESSION; } } } /* update the state of all the sessions on a slot */ static void fort11_update_all_states(PK11Slot *slot) { int i; PK11Session *session; for (i=0; i < SESSION_HASH_SIZE; i++) { FMUTEX_Lock(slot->sessionLock); for (session = slot->head[i]; session; session = session->next) { fort11_update_state(slot,session); } FMUTEX_Unlock(slot->sessionLock); } } /* * Create a new object */ static PK11Object * fort11_NewObject(PK11Slot *slot) { PK11Object *object; CK_RV mrv; int i; object = (PK11Object*)PORT_Alloc(sizeof(PK11Object)); if (object == NULL) return NULL; object->handle = 0; object->next = object->prev = NULL; object->sessionList.next = NULL; object->sessionList.prev = NULL; object->sessionList.parent = object; object->inDB = PR_FALSE; object->label = NULL; object->refCount = 1; object->session = NULL; object->slot = slot; object->objclass = 0xffff; if (FMUTEX_MutexEnabled()) { mrv = FMUTEX_Create(&object->refLock); if (mrv != CKR_OK) { PORT_Free(object); return NULL; } mrv = FMUTEX_Create(&object->attributeLock); if (mrv != CKR_OK) { FMUTEX_Destroy(object->refLock); PORT_Free(object); return NULL; } } else { object->attributeLock = NULL; object->refLock = NULL; } for (i=0; i < HASH_SIZE; i++) { object->head[i] = NULL; } object->objectInfo = NULL; object->infoFree = NULL; return object; } /* * look up and object structure from a handle. OBJECT_Handles only make * sense in terms of a given session. make a reference to that object * structure returned. */ static PK11Object * fort11_ObjectFromHandle(CK_OBJECT_HANDLE handle, PK11Session *session) { PK11Object **head; void *lock; PK11Slot *slot = fort11_SlotFromSession(session); PK11Object *object; /* * Token objects are stored in the slot. Session objects are stored * with the session. */ head = slot->tokObjects; lock = slot->objectLock; FMUTEX_Lock(lock); pk11queue_find(object,handle,head,HASH_SIZE); if (object) { FMUTEX_Lock(object->refLock); object->refCount++; FMUTEX_Unlock(object->refLock); } FMUTEX_Unlock(lock); return(object); } /* * add an object to a slot andsession queue */ static void fort11_DeleteObject(PK11Session *session, PK11Object *object) { PK11Slot *slot; if (session == NULL) return; slot = fort11_SlotFromSession(session); if (!fort11_isToken(object->handle)) { FMUTEX_Lock(session->objectLock); pk11queue_delete(&object->sessionList,0,session->objects,0); FMUTEX_Unlock(session->objectLock); } FMUTEX_Lock(slot->objectLock); pk11queue_delete(object,object->handle,slot->tokObjects,HASH_SIZE); FMUTEX_Unlock(slot->objectLock); fort11_FreeObject(object); } /* * ******************** Search Utilities ******************************* */ /* add an object to a search list */ CK_RV fort11_AddToList(PK11ObjectListElement **list,PK11Object *object) { PK11ObjectListElement *newelem = (PK11ObjectListElement *)PORT_Alloc(sizeof(PK11ObjectListElement)); if (newelem == NULL) return CKR_HOST_MEMORY; newelem->next = *list; newelem->object = object; FMUTEX_Lock(object->refLock); object->refCount++; FMUTEX_Unlock(object->refLock); *list = newelem; return CKR_OK; } /* * free a single list element. Return the Next object in the list. */ PK11ObjectListElement * fort11_FreeObjectListElement(PK11ObjectListElement *objectList) { PK11ObjectListElement *ol = objectList->next; fort11_FreeObject(objectList->object); PORT_Free(objectList); return ol; } /* free an entire object list */ void fort11_FreeObjectList(PK11ObjectListElement *objectList) { PK11ObjectListElement *ol; for (ol= objectList; ol != NULL; ol = fort11_FreeObjectListElement(ol)) {} } /* * free a search structure */ void fort11_FreeSearch(PK11SearchResults *search) { if (search->handles) { PORT_Free(search->handles); } PORT_Free(search); } /* * Free up all the memory associated with an attribute. Reference count * must be zero to call this. */ static void fort11_DestroyAttribute(PK11Attribute *attribute) { /*PORT_Assert(attribute->refCount == 0);*/ FMUTEX_Destroy(attribute->refLock); if (attribute->attrib.pValue) { /* clear out the data in the attribute value... it may have been * sensitive data */ PORT_Memset(attribute->attrib.pValue,0,attribute->attrib.ulValueLen); PORT_Free(attribute->attrib.pValue); } PORT_Free(attribute); } /* * delete an attribute from an object */ static void fort11_DeleteAttribute(PK11Object *object, PK11Attribute *attribute) { FMUTEX_Lock(object->attributeLock); if (attribute->next || attribute->prev) { pk11queue_delete(attribute,attribute->handle, object->head,HASH_SIZE); } FMUTEX_Unlock(object->attributeLock); fort11_FreeAttribute(attribute); } /* * decode when a particular attribute may be modified * PK11_NEVER: This attribute must be set at object creation time and * can never be modified. * PK11_ONCOPY: This attribute may be modified only when you copy the * object. * PK11_SENSITIVE: The CKA_SENSITIVE attribute can only be changed from * FALSE to TRUE. * PK11_ALWAYS: This attribute can always be modified. * Some attributes vary their modification type based on the class of the * object. */ PK11ModifyType fort11_modifyType(CK_ATTRIBUTE_TYPE type, CK_OBJECT_CLASS inClass) { /* if we don't know about it, user user defined, always allow modify */ PK11ModifyType mtype = PK11_ALWAYS; switch(type) { /* NEVER */ case CKA_CLASS: case CKA_CERTIFICATE_TYPE: case CKA_KEY_TYPE: case CKA_MODULUS: case CKA_MODULUS_BITS: case CKA_PUBLIC_EXPONENT: case CKA_PRIVATE_EXPONENT: case CKA_PRIME: case CKA_SUBPRIME: case CKA_BASE: case CKA_PRIME_1: case CKA_PRIME_2: case CKA_EXPONENT_1: case CKA_EXPONENT_2: case CKA_COEFFICIENT: case CKA_VALUE_LEN: mtype = PK11_NEVER; break; /* ONCOPY */ case CKA_TOKEN: case CKA_PRIVATE: mtype = PK11_ONCOPY; break; /* SENSITIVE */ case CKA_SENSITIVE: mtype = PK11_SENSITIVE; break; /* ALWAYS */ case CKA_LABEL: case CKA_APPLICATION: case CKA_ID: case CKA_SERIAL_NUMBER: case CKA_START_DATE: case CKA_END_DATE: case CKA_DERIVE: case CKA_ENCRYPT: case CKA_DECRYPT: case CKA_SIGN: case CKA_VERIFY: case CKA_SIGN_RECOVER: case CKA_VERIFY_RECOVER: case CKA_WRAP: case CKA_UNWRAP: mtype = PK11_ALWAYS; break; /* DEPENDS ON CLASS */ case CKA_VALUE: mtype = (inClass == CKO_DATA) ? PK11_ALWAYS : PK11_NEVER; break; case CKA_SUBJECT: mtype = (inClass == CKO_CERTIFICATE) ? PK11_NEVER : PK11_ALWAYS; break; default: break; } return mtype; } /* decode if a particular attribute is sensitive (cannot be read * back to the user of if the object is set to SENSITIVE) */ PRBool fort11_isSensitive(CK_ATTRIBUTE_TYPE type, CK_OBJECT_CLASS inClass) { switch(type) { /* ALWAYS */ case CKA_PRIVATE_EXPONENT: case CKA_PRIME_1: case CKA_PRIME_2: case CKA_EXPONENT_1: case CKA_EXPONENT_2: case CKA_COEFFICIENT: return PR_TRUE; /* DEPENDS ON CLASS */ case CKA_VALUE: /* PRIVATE and SECRET KEYS have SENSITIVE values */ return (PRBool)((inClass == CKO_PRIVATE_KEY) || (inClass == CKO_SECRET_KEY)); default: break; } return PR_FALSE; } static void fort11_DeleteAttributeType(PK11Object *object,CK_ATTRIBUTE_TYPE type) { PK11Attribute *attribute; attribute = fort11_FindAttribute(object, type); if (attribute == NULL) return ; fort11_DeleteAttribute(object,attribute); } /* * create a new nession. NOTE: The session handle is not set, and the * session is not added to the slot's session queue. */ static PK11Session * fort11_NewSession(CK_SLOT_ID slotID, CK_NOTIFY notify, CK_VOID_PTR pApplication, CK_FLAGS flags) { PK11Session *session; PK11Slot *slot = &fort11_slot[slotID-1]; CK_RV mrv; if (slot == NULL) return NULL; session = (PK11Session*)PORT_Alloc(sizeof(PK11Session)); if (session == NULL) return NULL; session->next = session->prev = NULL; session->refCount = 1; session->context = NULL; session->search = NULL; session->objectIDCount = 1; session->fortezzaContext.fortezzaKey = NULL; session->fortezzaContext.fortezzaSocket = NULL; if (FMUTEX_MutexEnabled()) { mrv = FMUTEX_Create(&session->refLock); if (mrv != CKR_OK) { PORT_Free(session); return NULL; } mrv = FMUTEX_Create(&session->objectLock); if (mrv != CKR_OK) { FMUTEX_Destroy(session->refLock); PORT_Free(session); return NULL; } } else { session->refLock = NULL; session->objectLock = NULL; } session->objects[0] = NULL; session->slot = slot; session->notify = notify; session->appData = pApplication; session->info.flags = flags; session->info.slotID = slotID; fort11_update_state(slot,session); return session; } /* * look up a session structure from a session handle * generate a reference to it. */ PK11Session * fort11_SessionFromHandle(CK_SESSION_HANDLE handle, PRBool isCloseSession) { PK11Slot *slot = fort11_SlotFromSessionHandle(handle); PK11Session *session; if (!isCloseSession && !SocketStateUnchanged(&fortezzaSockets[slot->slotID-1])) return NULL; FMUTEX_Lock(slot->sessionLock); pk11queue_find(session,handle,slot->head,SESSION_HASH_SIZE); if (session) session->refCount++; FMUTEX_Unlock(slot->sessionLock); return (session); } /* free all the data associated with a session. */ static void fort11_DestroySession(PK11Session *session) { PK11ObjectList *op,*next; /* PORT_Assert(session->refCount == 0);*/ /* clean out the attributes */ FMUTEX_Lock(session->objectLock); for (op = session->objects[0]; op != NULL; op = next) { next = op->next; /* paranoia */ op->next = op->prev = NULL; fort11_DeleteObject(session,op->parent); } FMUTEX_Unlock(session->objectLock); FMUTEX_Destroy(session->objectLock); FMUTEX_Destroy(session->refLock); if (session->search) { fort11_FreeSearch(session->search); } pk11queue_delete(session, session->handle, session->slot->head, SESSION_HASH_SIZE); PORT_Free(session); } /* * release a reference to a session handle */ void fort11_FreeSession(PK11Session *session) { PRBool destroy = PR_FALSE; PK11Slot *slot = NULL; if (!session) return; /*Quick fix to elminate crash*/ /*Fix in later version */ if (FMUTEX_MutexEnabled()) { slot = fort11_SlotFromSession(session); FMUTEX_Lock(slot->sessionLock); } if (session->refCount == 1) destroy = PR_TRUE; session->refCount--; if (FMUTEX_MutexEnabled()) { FMUTEX_Unlock(slot->sessionLock); } if (destroy) { fort11_DestroySession(session); } } /* return true if the object matches the template */ PRBool fort11_objectMatch(PK11Object *object,CK_ATTRIBUTE_PTR theTemplate,int count) { int i; for (i=0; i < count; i++) { PK11Attribute *attribute = fort11_FindAttribute(object,theTemplate[i].type); if (attribute == NULL) { return PR_FALSE; } if (attribute->attrib.ulValueLen == theTemplate[i].ulValueLen) { if (PORT_Memcmp(attribute->attrib.pValue,theTemplate[i].pValue, theTemplate[i].ulValueLen) == 0) { fort11_FreeAttribute(attribute); continue; } } fort11_FreeAttribute(attribute); return PR_FALSE; } return PR_TRUE; } /* search through all the objects in the queue and return the template matches * in the object list. */ CK_RV fort11_searchObjectList(PK11ObjectListElement **objectList,PK11Object **head, void *lock, CK_ATTRIBUTE_PTR theTemplate, int count) { int i; PK11Object *object; CK_RV rv; for(i=0; i < HASH_SIZE; i++) { /* We need to hold the lock to copy a consistant version of * the linked list. */ FMUTEX_Lock(lock); for (object = head[i]; object != NULL; object= object->next) { if (fort11_objectMatch(object,theTemplate,count)) { rv = fort11_AddToList(objectList,object); if (rv != CKR_OK) { return rv; } } } FMUTEX_Unlock(lock); } return CKR_OK; } static PRBool fort11_NotAllFuncsNULL (CK_C_INITIALIZE_ARGS_PTR pArgs) { return (PRBool)(pArgs && pArgs->CreateMutex && pArgs->DestroyMutex && pArgs->LockMutex && pArgs->UnlockMutex); } static PRBool fort11_InArgCheck(CK_C_INITIALIZE_ARGS_PTR pArgs) { PRBool rv; /* The only check for now, is to make sure that all of the * function pointers are either all NULL or all Non-NULL. * We also need to make sure the pReserved field in pArgs is * set to NULL. */ if (pArgs == NULL) { return PR_TRUE; /* If the argument is NULL, no * inconsistencies can exist. */ } if (pArgs->pReserved != NULL) { return PR_FALSE; } if (pArgs->CreateMutex != NULL) { rv = (PRBool) (pArgs->DestroyMutex != NULL && pArgs->LockMutex != NULL && pArgs->UnlockMutex != NULL); } else { /*pArgs->CreateMutex == NULL*/ rv = (PRBool) (pArgs->DestroyMutex == NULL && pArgs->LockMutex == NULL && pArgs->UnlockMutex == NULL); } return rv; } /********************************************************************** * * Start of PKCS 11 functions * **********************************************************************/ /********************************************************************** * * In order to get this to work on 68K, we have to do some special tricks, * First trick is that we need to make the module a Code Resource, and * all Code Resources on 68K have to have a main function. So we * define main to be a wrapper for C_GetFunctionList which will be the * first funnction called by any software that uses the PKCS11 module. * * The second trick is that whenever you access a global variable from * the Code Resource, it does funny things to the stack on 68K, so we * need to call some macros that handle the stack for us. First thing * you do is call EnterCodeResource() first thing in a function that * accesses a global, right before you leave that function, you call * ExitCodeResource. This will take care of stack management. * * Third trick is to call __InitCode__() when we first enter the module * so that all of the global variables get initialized properly. * **********************************************************************/ #if defined(XP_MAC) && !defined(__POWERPC__) #define FORT11_RETURN(exp) {ExitCodeResource(); return (exp);} #define FORT11_ENTER() EnterCodeResource(); #else /*XP_MAC*/ #define FORT11_RETURN(exp) return (exp); #define FORT11_ENTER() #endif /*XP_MAC*/ #define CARD_OK(rv) if ((rv) != CI_OK) FORT11_RETURN (CKR_DEVICE_ERROR); #define SLOT_OK(slot) if ((slot) > kNumSockets) FORT11_RETURN (CKR_SLOT_ID_INVALID); #ifdef XP_MAC /* This is not a 4.0 project, so I can't depend on * 4.0 defines, so instead I depend on CodeWarrior * defines. */ #if __POWERPC__ #elif __CFM68K__ #else /* To get this to work on 68K, we need to have * the symbol main. So we just make it a wrapper for C_GetFunctionList. */ PR_PUBLIC_API(CK_RV) main(CK_FUNCTION_LIST_PTR *pFunctionList) { FORT11_ENTER() CK_RV rv; __InitCode__(); rv = C_GetFunctionList(pFunctionList); FORT11_RETURN (rv); } #endif #endif /*XP_MAC*/ /* Return the function list */ PR_PUBLIC_API(CK_RV) C_GetFunctionList(CK_FUNCTION_LIST_PTR *pFunctionList) { /* No need to do a FORT11_RETURN as this function will never be directly * called in the case where we need to do stack management. * The main function will call this after taking care of stack stuff. */ *pFunctionList = &fort11_funcList; return CKR_OK; } /* C_Initialize initializes the Cryptoki library. */ PR_PUBLIC_API(CK_RV) C_Initialize(CK_VOID_PTR pReserved) { FORT11_ENTER() int i,j, tempNumSockets; int rv = 1; CK_C_INITIALIZE_ARGS_PTR pArgs = (CK_C_INITIALIZE_ARGS_PTR)pReserved; CK_RV mrv; /* intialize all the slots */ if (!init) { init = PR_TRUE; /* need to initialize locks before MACI_Initialize is called in * software fortezza. */ if (pArgs) { if (!fort11_InArgCheck(pArgs)) { FORT11_RETURN (CKR_ARGUMENTS_BAD); } if (pArgs->flags & CKF_OS_LOCKING_OK){ if (!fort11_NotAllFuncsNULL(pArgs)) { FORT11_RETURN (CKR_CANT_LOCK); } } if (fort11_NotAllFuncsNULL(pArgs)) { mrv = FMUTEX_Init(pArgs); if (mrv != CKR_OK) { return CKR_GENERAL_ERROR; } } } rv = MACI_Initialize (&tempNumSockets); kNumSockets = (CK_ULONG)tempNumSockets; CARD_OK (rv); for (i=0; i < (int) kNumSockets; i++) { if (FMUTEX_MutexEnabled()) { mrv = FMUTEX_Create(&fort11_slot[i].sessionLock); if (mrv != CKR_OK) { FORT11_RETURN (CKR_GENERAL_ERROR); } mrv = FMUTEX_Create(&fort11_slot[i].objectLock); if (mrv != CKR_OK) { FMUTEX_Destroy(fort11_slot[i].sessionLock); FORT11_RETURN (CKR_GENERAL_ERROR); } } else { fort11_slot[i].sessionLock = NULL; fort11_slot[i].objectLock = NULL; } for(j=0; j < SESSION_HASH_SIZE; j++) { fort11_slot[i].head[j] = NULL; } for(j=0; j < HASH_SIZE; j++) { fort11_slot[i].tokObjects[j] = NULL; } fort11_slot[i].password = NULL; fort11_slot[i].hasTokens = PR_FALSE; fort11_slot[i].sessionIDCount = fort11_firstSessionID (i); fort11_slot[i].sessionCount = 0; fort11_slot[i].rwSessionCount = 0; fort11_slot[i].tokenIDCount = 1; fort11_slot[i].needLogin = PR_TRUE; fort11_slot[i].isLoggedIn = PR_FALSE; fort11_slot[i].ssoLoggedIn = PR_FALSE; fort11_slot[i].DB_loaded = PR_FALSE; fort11_slot[i].slotID= i+1; InitSocket(&fortezzaSockets[i], i+1); } } FORT11_RETURN (CKR_OK); } /*C_Finalize indicates that an application is done with the Cryptoki library.*/ PR_PUBLIC_API(CK_RV) C_Finalize (CK_VOID_PTR pReserved) { FORT11_ENTER() int i; for (i=0; i< (int) kNumSockets; i++) { FreeSocket(&fortezzaSockets[i]); } MACI_Terminate(fortezzaSockets[0].maciSession); init = PR_FALSE; FORT11_RETURN (CKR_OK); } /* C_GetInfo returns general information about Cryptoki. */ PR_PUBLIC_API(CK_RV) C_GetInfo(CK_INFO_PTR pInfo) { FORT11_ENTER() pInfo->cryptokiVersion = fort11_funcList.version; PORT_Memcpy(pInfo->manufacturerID,manufacturerID,32); pInfo->libraryVersion.major = 1; pInfo->libraryVersion.minor = 7; PORT_Memcpy(pInfo->libraryDescription,libraryDescription,32); pInfo->flags = 0; FORT11_RETURN (CKR_OK); } /* C_GetSlotList obtains a list of slots in the system. */ PR_PUBLIC_API(CK_RV) C_GetSlotList(CK_BBOOL tokenPresent, CK_SLOT_ID_PTR pSlotList, CK_ULONG_PTR pulCount) { FORT11_ENTER() int i; if (pSlotList != NULL) { if (*pulCount >= kNumSockets) { for (i=0; i < (int) kNumSockets; i++) { pSlotList[i] = i+1; } } else { FORT11_RETURN (CKR_BUFFER_TOO_SMALL); } } else { *pulCount = kNumSockets; } FORT11_RETURN (CKR_OK); } /* C_GetSlotInfo obtains information about a particular slot in the system. */ PR_PUBLIC_API(CK_RV) C_GetSlotInfo(CK_SLOT_ID slotID, CK_SLOT_INFO_PTR pInfo) { FORT11_ENTER() int rv; CI_CONFIG ciConfig; CI_STATE ciState; HSESSION maciSession; char slotDescription[65]; FortezzaSocket *socket; SLOT_OK(slotID); socket = &fortezzaSockets[slotID-1]; if (!socket->isOpen) { InitSocket(socket, slotID); } maciSession = socket->maciSession; rv = MACI_Select(maciSession, slotID); CARD_OK (rv) rv = MACI_GetConfiguration (maciSession, &ciConfig); pInfo->firmwareVersion.major = 0; pInfo->firmwareVersion.minor = 0; #ifdef SWFORT PORT_Memcpy (pInfo->manufacturerID,"Netscape Communications Corp ",32); PORT_Memcpy (slotDescription,"Netscape Software Slot # ",32); #define _local_BASE 24 #else PORT_Memcpy (pInfo->manufacturerID,"LITRONIC ",32); PORT_Memcpy (slotDescription,"Litronic MACI Slot # ",32); #define _local_BASE 20 #endif slotDescription[_local_BASE] = (char )((slotID < 10) ? slotID : slotID/10) + '0'; if (slotID >= 10) slotDescription[_local_BASE+1] = (char)(slotID % 10) + '0'; PORT_Memcpy (&slotDescription[32]," ",32); PORT_Memcpy (pInfo->slotDescription, slotDescription , 64); if (rv == CI_OK) { pInfo->hardwareVersion.major = (ciConfig.ManufacturerVersion & MAJOR_VERSION_MASK) >> 8; pInfo->hardwareVersion.minor = ciConfig.ManufacturerVersion & MINOR_VERSION_MASK; pInfo->flags = CKF_TOKEN_PRESENT; } else { pInfo->hardwareVersion.major = 0; pInfo->hardwareVersion.minor = 0; pInfo->flags = 0; } #ifdef SWFORT /* do we need to make it a removable device as well?? */ pInfo->flags |= CKF_REMOVABLE_DEVICE; #else pInfo->flags |= (CKF_REMOVABLE_DEVICE | CKF_HW_SLOT); #endif rv = MACI_GetState(maciSession, &ciState); if (rv == CI_OK) { switch (ciState) { case CI_ZEROIZE: case CI_INTERNAL_FAILURE: pInfo->flags &= (~CKF_TOKEN_PRESENT); default: break; } } else { pInfo->flags &= (~CKF_TOKEN_PRESENT); } FORT11_RETURN (CKR_OK); } #define CKF_THREAD_SAFE 0x8000 /* C_GetTokenInfo obtains information about a particular token in the system. */ PR_PUBLIC_API(CK_RV) C_GetTokenInfo(CK_SLOT_ID slotID, CK_TOKEN_INFO_PTR pInfo) { FORT11_ENTER() CI_STATUS cardStatus; CI_CONFIG ciConfig; PK11Slot *slot; int rv, i; char tmp[33]; FortezzaSocket *socket; SLOT_OK (slotID); slot = &fort11_slot[slotID-1]; socket = &fortezzaSockets[slotID-1]; if (!socket->isOpen) { InitSocket(socket, slotID); } rv = MACI_Select (socket->maciSession, slotID); rv = MACI_GetStatus (socket->maciSession, &cardStatus); if (rv != CI_OK) { FORT11_RETURN (CKR_DEVICE_ERROR); } #ifdef SWFORT sprintf (tmp, "Software FORTEZZA Slot #%d", slotID); #else sprintf (tmp, "FORTEZZA Slot #%d", slotID); #endif PORT_Memcpy (pInfo->label, tmp, PORT_Strlen(tmp)+1); for (i=0; i<8; i++) { int serNum; serNum = (int)cardStatus.SerialNumber[i]; sprintf ((char*)&pInfo->serialNumber[2*i], "%.2x", serNum); } rv = MACI_GetTime (fortezzaSockets[slotID-1].maciSession, pInfo->utcTime); if (rv == CI_OK) { pInfo->flags = CKF_CLOCK_ON_TOKEN; } else { switch (rv) { case CI_LIB_NOT_INIT: case CI_INV_POINTER: case CI_NO_CARD: case CI_NO_SOCKET: FORT11_RETURN (CKR_DEVICE_ERROR); default: pInfo->flags = 0; break; } } rv = MACI_GetConfiguration (fortezzaSockets[slotID-1].maciSession, &ciConfig); if (rv == CI_OK) { PORT_Memcpy(pInfo->manufacturerID,ciConfig.ManufacturerName, PORT_Strlen(ciConfig.ManufacturerName)); for (i=PORT_Strlen(ciConfig.ManufacturerName); i<32; i++) { pInfo->manufacturerID[i] = ' '; } PORT_Memcpy(pInfo->model,ciConfig.ProcessorType,16); } pInfo->ulMaxPinLen = CI_PIN_SIZE; pInfo->ulMinPinLen = 0; pInfo->ulTotalPublicMemory = 0; pInfo->ulFreePublicMemory = 0; pInfo->flags |= CKF_RNG | CKF_LOGIN_REQUIRED| CKF_USER_PIN_INITIALIZED | CKF_THREAD_SAFE | CKF_WRITE_PROTECTED; pInfo->ulMaxSessionCount = 0; pInfo->ulSessionCount = slot->sessionCount; pInfo->ulMaxRwSessionCount = 0; pInfo->ulRwSessionCount = slot->rwSessionCount; if (rv == CI_OK) { pInfo->firmwareVersion.major = (ciConfig.ManufacturerSWVer & MAJOR_VERSION_MASK) >> 8; pInfo->firmwareVersion.minor = ciConfig.ManufacturerSWVer & MINOR_VERSION_MASK; pInfo->hardwareVersion.major = (ciConfig.ManufacturerVersion & MAJOR_VERSION_MASK) >> 8; pInfo->hardwareVersion.minor = ciConfig.ManufacturerVersion & MINOR_VERSION_MASK; } FORT11_RETURN (CKR_OK); } /* C_GetMechanismList obtains a list of mechanism types supported by a token. */ PR_PUBLIC_API(CK_RV) C_GetMechanismList(CK_SLOT_ID slotID, CK_MECHANISM_TYPE_PTR pMechanismList, CK_ULONG_PTR pulCount) { FORT11_ENTER() CK_RV rv = CKR_OK; int i; SLOT_OK (slotID); if (pMechanismList == NULL) { *pulCount = mechanismCount; } else { if (*pulCount >= mechanismCount) { *pulCount = mechanismCount; for (i=0; i< (int)mechanismCount; i++) { pMechanismList[i] = mechanisms[i].type; } } else { rv = CKR_BUFFER_TOO_SMALL; } } FORT11_RETURN (rv); } /* C_GetMechanismInfo obtains information about a particular mechanism * possibly supported by a token. */ PR_PUBLIC_API(CK_RV) C_GetMechanismInfo(CK_SLOT_ID slotID, CK_MECHANISM_TYPE type, CK_MECHANISM_INFO_PTR pInfo) { int i; FORT11_ENTER() SLOT_OK (slotID); for (i=0; i< (int)mechanismCount; i++) { if (type == mechanisms[i].type) { PORT_Memcpy (pInfo, &mechanisms[i].domestic, sizeof (CK_MECHANISM_INFO)); FORT11_RETURN (CKR_OK); } } FORT11_RETURN (CKR_MECHANISM_INVALID); } /* C_InitToken initializes a token. */ PR_PUBLIC_API(CK_RV) C_InitToken(CK_SLOT_ID slotID, CK_CHAR_PTR pPin, CK_ULONG ulPinLen, CK_CHAR_PTR pLabel) { /* For functions that don't access globals, we don't have to worry about the * stack. */ return CKR_FUNCTION_NOT_SUPPORTED; } /* C_InitPIN initializes the normal user's PIN. */ PR_PUBLIC_API(CK_RV) C_InitPIN(CK_SESSION_HANDLE hSession, CK_CHAR_PTR pPin, CK_ULONG ulPinLen) { /* For functions that don't access globals, we don't have to worry about the * stack. */ return CKR_FUNCTION_NOT_SUPPORTED; } /* C_SetPIN modifies the PIN of user that is currently logged in. */ /* NOTE: This is only valid for the PRIVATE_KEY_SLOT */ PR_PUBLIC_API(CK_RV) C_SetPIN(CK_SESSION_HANDLE hSession, CK_CHAR_PTR pOldPin, CK_ULONG ulOldLen, CK_CHAR_PTR pNewPin, CK_ULONG ulNewLen) { FORT11_ENTER() #ifndef SWFORT CI_PIN ciOldPin, ciNewPin; #endif PK11Session *session; PK11Slot *slot; int rv; session = fort11_SessionFromHandle (hSession, PR_FALSE); slot = fort11_SlotFromSession (session); SLOT_OK(slot->slotID) if (session == NULL) { session = fort11_SessionFromHandle (hSession, PR_TRUE); fort11_TokenRemoved(slot, session); FORT11_RETURN (CKR_SESSION_HANDLE_INVALID); } rv = MACI_Select (fortezzaSockets[slot->slotID-1].maciSession, slot->slotID); CARD_OK (rv) if (slot->needLogin && session->info.state != CKS_RW_USER_FUNCTIONS) { fort11_FreeSession (session); FORT11_RETURN (CKR_USER_NOT_LOGGED_IN); } fort11_FreeSession (session); if (ulNewLen > CI_PIN_SIZE || ulOldLen > CI_PIN_SIZE) FORT11_RETURN (CKR_PIN_LEN_RANGE); #ifndef SWFORT fort11_convertToCIPin (ciOldPin,pOldPin, ulOldLen); fort11_convertToCIPin (ciNewPin,pNewPin, ulNewLen); rv = MACI_ChangePIN (fortezzaSockets[slot->slotID-1].maciSession, CI_USER_PIN, ciOldPin, ciNewPin); #else rv = MACI_ChangePIN (fortezzaSockets[slot->slotID-1].maciSession, CI_USER_PIN, pOldPin, pNewPin); #endif if (rv != CI_OK) { switch (rv) { case CI_FAIL: FORT11_RETURN (CKR_PIN_INCORRECT); default: FORT11_RETURN (CKR_DEVICE_ERROR); } } FORT11_RETURN (CKR_OK); } /* C_OpenSession opens a session between an application and a token. */ PR_PUBLIC_API(CK_RV) C_OpenSession(CK_SLOT_ID slotID, CK_FLAGS flags, CK_VOID_PTR pApplication, CK_NOTIFY Notify, CK_SESSION_HANDLE_PTR phSession) { FORT11_ENTER() PK11Slot *slot; CK_SESSION_HANDLE sessionID; PK11Session *session; FortezzaSocket *socket; SLOT_OK (slotID) slot = &fort11_slot[slotID-1]; socket = &fortezzaSockets[slotID-1]; if (!socket->isOpen) { if (InitSocket(socket, slotID) != SOCKET_SUCCESS) { FORT11_RETURN (CKR_TOKEN_NOT_PRESENT); } } session = fort11_NewSession (slotID, Notify, pApplication, flags | CKF_SERIAL_SESSION); if (session == NULL) FORT11_RETURN (CKR_HOST_MEMORY); FMUTEX_Lock(slot->sessionLock); slot->sessionIDCount += ADD_NEXT_SESS_ID; sessionID = slot->sessionIDCount; fort11_update_state (slot, session); pk11queue_add (session, sessionID, slot->head, SESSION_HASH_SIZE); slot->sessionCount++; if (session->info.flags & CKF_RW_SESSION) { slot->rwSessionCount++; } session->handle = sessionID; session->info.ulDeviceError = 0; FMUTEX_Unlock(slot->sessionLock); *phSession = sessionID; FORT11_RETURN (CKR_OK); } /* C_CloseSession closes a session between an application and a token. */ PR_PUBLIC_API(CK_RV) C_CloseSession(CK_SESSION_HANDLE hSession) { FORT11_ENTER() PK11Slot *slot; PK11Session *session; session = fort11_SessionFromHandle (hSession, PR_TRUE); slot = fort11_SlotFromSessionHandle (hSession); if (session == NULL) { FORT11_RETURN (CKR_SESSION_HANDLE_INVALID); } FMUTEX_Lock(slot->sessionLock); if (session->next || session->prev) { session->refCount--; if (session->info.flags & CKF_RW_SESSION) { slot->rwSessionCount--; } if (slot->sessionCount == 0) { slot->isLoggedIn = PR_FALSE; slot->password = NULL; } } FMUTEX_Unlock(slot->sessionLock); fort11_FreeSession (session); FORT11_RETURN (CKR_OK); } /* C_CloseAllSessions closes all sessions with a token. */ PR_PUBLIC_API(CK_RV) C_CloseAllSessions (CK_SLOT_ID slotID) { FORT11_ENTER() PK11Slot *slot; PK11Session *session; int i; slot = fort11_SlotFromID(slotID); if (slot == NULL) FORT11_RETURN (CKR_SLOT_ID_INVALID); /* first log out the card */ FMUTEX_Lock(slot->sessionLock); slot->isLoggedIn = PR_FALSE; slot->password = NULL; FMUTEX_Unlock(slot->sessionLock); /* now close all the current sessions */ /* NOTE: If you try to open new sessions before C_CloseAllSessions * completes, some of those new sessions may or may not be closed by * C_CloseAllSessions... but any session running when this code starts * will guarrenteed be close, and no session will be partially closed */ for (i=0; i < SESSION_HASH_SIZE; i++) { do { FMUTEX_Lock(slot->sessionLock); session = slot->head[i]; /* hand deque */ /* this duplicates much of C_close session functionality, but because * we know that we are freeing all the sessions, we and do some * more efficient processing */ if (session) { slot->head[i] = session->next; if (session->next) session->next->prev = NULL; session->next = session->prev = NULL; slot->sessionCount--; if (session->info.flags & CKF_RW_SESSION) { slot->rwSessionCount--; } } FMUTEX_Unlock(slot->sessionLock); if (session) fort11_FreeSession(session); } while (session != NULL); } FORT11_RETURN (CKR_OK); } /* C_GetSessionInfo obtains information about the session. */ PR_PUBLIC_API(CK_RV) C_GetSessionInfo(CK_SESSION_HANDLE hSession, CK_SESSION_INFO_PTR pInfo) { FORT11_ENTER() PK11Session *session; PK11Slot *slot; CI_STATE cardState; FortezzaSocket *socket; int ciRV; session = fort11_SessionFromHandle (hSession, PR_FALSE); slot = fort11_SlotFromSessionHandle(hSession); socket = &fortezzaSockets[slot->slotID-1]; if (session == NULL) { session = fort11_SessionFromHandle (hSession, PR_TRUE); fort11_TokenRemoved(slot, session); fort11_FreeSession(session); FORT11_RETURN (CKR_SESSION_HANDLE_INVALID); } PORT_Memcpy (pInfo, &session->info, sizeof (CK_SESSION_INFO)); fort11_FreeSession(session); ciRV = MACI_Select(socket->maciSession, slot->slotID); CARD_OK(ciRV) ciRV = MACI_GetState(socket->maciSession, &cardState); CARD_OK(ciRV) if (socket->isLoggedIn) { switch (cardState) { case CI_POWER_UP: case CI_UNINITIALIZED: case CI_INITIALIZED: case CI_SSO_INITIALIZED: case CI_LAW_INITIALIZED: case CI_USER_INITIALIZED: pInfo->state = CKS_RO_PUBLIC_SESSION; break; case CI_STANDBY: case CI_READY: pInfo->state = CKS_RO_USER_FUNCTIONS; break; default: pInfo->state = CKS_RO_PUBLIC_SESSION; break; } } else { pInfo->state = CKS_RO_PUBLIC_SESSION; } FORT11_RETURN (CKR_OK); } /* C_Login logs a user into a token. */ PR_PUBLIC_API(CK_RV) C_Login(CK_SESSION_HANDLE hSession, CK_USER_TYPE userType, CK_CHAR_PTR pPin, CK_ULONG ulPinLen) { FORT11_ENTER() PK11Slot *slot; PK11Session *session; #ifndef SWFORT CI_PIN ciPin; #endif int rv, ciUserType; slot = fort11_SlotFromSessionHandle (hSession); session = fort11_SessionFromHandle(hSession, PR_FALSE); if (session == NULL) { session = fort11_SessionFromHandle (hSession, PR_TRUE); fort11_TokenRemoved(slot, session); FORT11_RETURN (CKR_SESSION_HANDLE_INVALID); } fort11_FreeSession(session); if (slot->isLoggedIn) FORT11_RETURN (CKR_USER_ALREADY_LOGGED_IN); slot->ssoLoggedIn = PR_FALSE; #ifndef SWFORT if (ulPinLen > CI_PIN_SIZE) FORT11_RETURN (CKR_PIN_LEN_RANGE); fort11_convertToCIPin (ciPin, pPin, ulPinLen); #endif switch (userType) { case CKU_SO: ciUserType = CI_SSO_PIN; break; case CKU_USER: ciUserType = CI_USER_PIN; break; default: FORT11_RETURN (CKR_USER_TYPE_INVALID); } #ifndef SWFORT rv = LoginToSocket(&fortezzaSockets[slot->slotID-1], ciUserType, ciPin); #else rv = LoginToSocket(&fortezzaSockets[slot->slotID-1], ciUserType, pPin); #endif switch (rv) { case SOCKET_SUCCESS: break; case CI_FAIL: FORT11_RETURN (CKR_PIN_INCORRECT); default: FORT11_RETURN (CKR_DEVICE_ERROR); } FMUTEX_Lock(slot->sessionLock); slot->isLoggedIn = PR_TRUE; if (userType == CKU_SO) { slot->ssoLoggedIn = PR_TRUE; } FMUTEX_Unlock(slot->sessionLock); fort11_update_all_states(slot); FORT11_RETURN (CKR_OK); } /* C_Logout logs a user out from a token. */ PR_PUBLIC_API(CK_RV) C_Logout(CK_SESSION_HANDLE hSession) { FORT11_ENTER() PK11Slot *slot = fort11_SlotFromSessionHandle(hSession); PK11Session *session = fort11_SessionFromHandle(hSession, PR_FALSE); if (session == NULL) { session = fort11_SessionFromHandle (hSession, PR_TRUE); fort11_TokenRemoved(slot, session); fort11_FreeSession(session); FORT11_RETURN (CKR_SESSION_HANDLE_INVALID); } if (!slot->isLoggedIn) FORT11_RETURN (CKR_USER_NOT_LOGGED_IN); FMUTEX_Lock(slot->sessionLock); slot->isLoggedIn = PR_FALSE; slot->ssoLoggedIn = PR_FALSE; slot->password = NULL; LogoutFromSocket (&fortezzaSockets[slot->slotID-1]); FMUTEX_Unlock(slot->sessionLock); fort11_update_all_states(slot); FORT11_RETURN (CKR_OK); } /* C_CreateObject creates a new object. */ PR_PUBLIC_API(CK_RV) C_CreateObject(CK_SESSION_HANDLE hSession, CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount, CK_OBJECT_HANDLE_PTR phObject) { /* For functions that don't access globals, we don't have to worry about the * stack. */ return CKR_FUNCTION_NOT_SUPPORTED; } /* C_CopyObject copies an object, creating a new object for the copy. */ PR_PUBLIC_API(CK_RV) C_CopyObject(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hObject, CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount, CK_OBJECT_HANDLE_PTR phNewObject) { /* For functions that don't access globals, we don't have to worry about the * stack. */ return CKR_FUNCTION_NOT_SUPPORTED; } /* C_DestroyObject destroys an object. */ PR_PUBLIC_API(CK_RV) C_DestroyObject(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hObject) { FORT11_ENTER() PK11Slot *slot = fort11_SlotFromSessionHandle(hSession); PK11Session *session; PK11Object *object; PK11FreeStatus status; /* * This whole block just makes sure we really can destroy the * requested object. */ session = fort11_SessionFromHandle(hSession, PR_FALSE); if (session == NULL) { session = fort11_SessionFromHandle(hSession, PR_TRUE); fort11_TokenRemoved(slot, session); fort11_FreeSession(session); FORT11_RETURN (CKR_SESSION_HANDLE_INVALID); } object = fort11_ObjectFromHandle(hObject,session); if (object == NULL) { fort11_FreeSession(session); FORT11_RETURN (CKR_OBJECT_HANDLE_INVALID); } /* don't destroy a private object if we aren't logged in */ if ((!slot->isLoggedIn) && (slot->needLogin) && (fort11_isTrue(object,CKA_PRIVATE))) { fort11_FreeSession(session); fort11_FreeObject(object); FORT11_RETURN (CKR_USER_NOT_LOGGED_IN); } /* don't destroy a token object if we aren't in a rw session */ if (((session->info.flags & CKF_RW_SESSION) == 0) && (fort11_isTrue(object,CKA_TOKEN))) { fort11_FreeSession(session); fort11_FreeObject(object); FORT11_RETURN (CKR_SESSION_READ_ONLY); } /* ACTUALLY WE NEED TO DEAL WITH TOKEN OBJECTS AS WELL */ FMUTEX_Lock(session->objectLock); fort11_DeleteObject(session,object); FMUTEX_Unlock(session->objectLock); fort11_FreeSession(session); /* * get some indication if the object is destroyed. Note: this is not * 100%. Someone may have an object reference outstanding (though that * should not be the case by here. Also now that the object is "half" * destroyed. Our internal representation is destroyed, but it is still * in the data base. */ status = fort11_FreeObject(object); FORT11_RETURN ((status != PK11_DestroyFailure) ? CKR_OK : CKR_DEVICE_ERROR); } /* C_GetObjectSize gets the size of an object in bytes. */ PR_PUBLIC_API(CK_RV) C_GetObjectSize(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hObject, CK_ULONG_PTR pulSize) { /* For functions that don't access globals, we don't have to worry about the * stack. */ *pulSize = 0; return CKR_OK; } /* C_GetAttributeValue obtains the value of one or more object attributes. */ PR_PUBLIC_API(CK_RV) C_GetAttributeValue(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hObject, CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount) { FORT11_ENTER() PK11Slot *slot = fort11_SlotFromSessionHandle(hSession); PK11Session *session; PK11Object *object; PK11Attribute *attribute; PRBool sensitive; int i; /* * make sure we're allowed */ session = fort11_SessionFromHandle(hSession, PR_FALSE); if (session == NULL) { session = fort11_SessionFromHandle (hSession, PR_TRUE); fort11_TokenRemoved(slot, session); fort11_FreeSession(session); FORT11_RETURN (CKR_SESSION_HANDLE_INVALID); } object = fort11_ObjectFromHandle(hObject,session); fort11_FreeSession(session); if (object == NULL) { FORT11_RETURN (CKR_OBJECT_HANDLE_INVALID); } /* don't read a private object if we aren't logged in */ if ((!slot->isLoggedIn) && (slot->needLogin) && (fort11_isTrue(object,CKA_PRIVATE))) { fort11_FreeObject(object); FORT11_RETURN (CKR_USER_NOT_LOGGED_IN); } sensitive = fort11_isTrue(object,CKA_SENSITIVE); for (i=0; i < (int)ulCount; i++) { /* Make sure that this attribute is retrievable */ if (sensitive && fort11_isSensitive(pTemplate[i].type,object->objclass)) { fort11_FreeObject(object); FORT11_RETURN (CKR_ATTRIBUTE_SENSITIVE); } attribute = fort11_FindAttribute(object,pTemplate[i].type); if (attribute == NULL) { fort11_FreeObject(object); FORT11_RETURN (CKR_ATTRIBUTE_TYPE_INVALID); } if (pTemplate[i].pValue != NULL) { PORT_Memcpy(pTemplate[i].pValue,attribute->attrib.pValue, attribute->attrib.ulValueLen); } pTemplate[i].ulValueLen = attribute->attrib.ulValueLen; fort11_FreeAttribute(attribute); } fort11_FreeObject(object); FORT11_RETURN (CKR_OK); } /* C_SetAttributeValue modifies the value of one or more object attributes */ PR_PUBLIC_API(CK_RV) C_SetAttributeValue (CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hObject, CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount) { /* For functions that don't access globals, we don't have to worry about the * stack. */ return CKR_FUNCTION_NOT_SUPPORTED; } /* C_FindObjectsInit initializes a search for token and session objects * that match a template. */ PR_PUBLIC_API(CK_RV) C_FindObjectsInit(CK_SESSION_HANDLE hSession, CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount) { FORT11_ENTER() PK11Slot *slot = fort11_SlotFromSessionHandle(hSession); PK11Session *session; PK11ObjectListElement *objectList = NULL; PK11ObjectListElement *olp; PK11SearchResults *search, *freeSearch; FortezzaSocket *currSocket; int rv, count, i; if (slot == NULL) { FORT11_RETURN (CKR_SESSION_HANDLE_INVALID); } if ((!slot->isLoggedIn) && (slot->needLogin)) FORT11_RETURN (CKR_USER_NOT_LOGGED_IN); session = fort11_SessionFromHandle(hSession, PR_FALSE); if (session == NULL) { session = fort11_SessionFromHandle (hSession, PR_TRUE); fort11_TokenRemoved(slot, session); fort11_FreeSession(session); FORT11_RETURN (CKR_SESSION_HANDLE_INVALID); } currSocket = &fortezzaSockets[slot->slotID-1]; if (currSocket->personalityList == NULL) { rv = FetchPersonalityList(currSocket); if (rv != SOCKET_SUCCESS) { fort11_FreeSession(session); FORT11_RETURN (CKR_DEVICE_ERROR); } rv = fort11_BuildCertObjects(currSocket, slot, session); if (rv != CKR_OK) { fort11_FreeSession(session); FORT11_RETURN (rv); } } rv = fort11_searchObjectList(&objectList, slot->tokObjects, slot->objectLock, pTemplate, ulCount); if (rv != CKR_OK) { fort11_FreeObjectList(objectList); fort11_FreeSession(session); FORT11_RETURN (rv); } /*copy list to session*/ count = 0; for(olp = objectList; olp != NULL; olp = olp->next) { count++; } search = (PK11SearchResults *)PORT_Alloc(sizeof(PK11SearchResults)); if (search != NULL) { search->handles = (CK_OBJECT_HANDLE *) PORT_Alloc(sizeof(CK_OBJECT_HANDLE) * count); if (search->handles != NULL) { for (i=0; i < count; i++) { search->handles[i] = objectList->object->handle; objectList = fort11_FreeObjectListElement(objectList); } } else { PORT_Free(search); search = NULL; } } if (search == NULL) { fort11_FreeObjectList(objectList); fort11_FreeSession(session); FORT11_RETURN (CKR_OK); } /* store the search info */ search->index = 0; search->size = count; if ((freeSearch = session->search) != NULL) { session->search = NULL; fort11_FreeSearch(freeSearch); } session->search = search; fort11_FreeSession(session); FORT11_RETURN (CKR_OK); } /* C_FindObjects continues a search for token and session objects * that match a template, obtaining additional object handles. */ PR_PUBLIC_API(CK_RV) C_FindObjects(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE_PTR phObject, CK_ULONG ulMaxObjectCount, CK_ULONG_PTR pulObjectCount) { FORT11_ENTER() PK11Session *session; PK11SearchResults *search; PK11Slot *slot; int transfer; unsigned long left; *pulObjectCount = 0; session = fort11_SessionFromHandle(hSession,PR_FALSE); slot = fort11_SlotFromSessionHandle(hSession); if (session == NULL) { session = fort11_SessionFromHandle (hSession, PR_TRUE); fort11_TokenRemoved(slot, session); fort11_FreeSession(session); FORT11_RETURN (CKR_SESSION_HANDLE_INVALID); } if (session->search == NULL) { fort11_FreeSession(session); FORT11_RETURN (CKR_OK); } search = session->search; left = session->search->size - session->search->index; transfer = (ulMaxObjectCount > left) ? left : ulMaxObjectCount; PORT_Memcpy(phObject,&search->handles[search->index], transfer*sizeof(CK_OBJECT_HANDLE_PTR)); search->index += transfer; if (search->index == search->size) { session->search = NULL; fort11_FreeSearch(search); } fort11_FreeSession(session); *pulObjectCount = transfer; FORT11_RETURN (CKR_OK); } /* C_FindObjectsFinal finishes a search for token and session objects. */ PR_PUBLIC_API(CK_RV) C_FindObjectsFinal(CK_SESSION_HANDLE hSession) { FORT11_ENTER() PK11Session *session; PK11SearchResults *search; PK11Slot *slot; session = fort11_SessionFromHandle(hSession, PR_FALSE); slot = fort11_SlotFromSessionHandle(hSession); if (session == NULL) { session = fort11_SessionFromHandle (hSession, PR_TRUE); fort11_TokenRemoved(slot, session); fort11_FreeSession(session); FORT11_RETURN (CKR_SESSION_HANDLE_INVALID); } search = session->search; session->search = NULL; if (search == NULL) { fort11_FreeSession(session); FORT11_RETURN (CKR_OK); } fort11_FreeSearch(search); /* UnloadPersonalityList(&fortezzaSockets[session->slot->slotID-1]); */ fort11_FreeSession(session); FORT11_RETURN (CKR_OK); } /* C_EncryptInit initializes an encryption operation. */ PR_PUBLIC_API(CK_RV) C_EncryptInit(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hKey) { FORT11_ENTER() PK11Session *session = fort11_SessionFromHandle(hSession, PR_FALSE); PK11Slot *slot = fort11_SlotFromSessionHandle(hSession); PK11Object *keyObject; FortezzaSocket *socket = &fortezzaSockets[slot->slotID-1]; FortezzaContext *context; HSESSION hs = socket->maciSession; FortezzaKey *fortezzaKey; CI_IV fortezzaIV; int ciRV, registerIndex; if (pMechanism->mechanism != CKM_SKIPJACK_CBC64) { if (session) { fort11_FreeSession(session); } FORT11_RETURN (CKR_MECHANISM_INVALID); } if (session == NULL) { session = fort11_SessionFromHandle (hSession, PR_TRUE); fort11_TokenRemoved(slot, session); fort11_FreeSession(session); FORT11_RETURN (CKR_SESSION_HANDLE_INVALID); } keyObject = fort11_ObjectFromHandle (hKey, session); if (keyObject == NULL) { fort11_FreeSession(session); FORT11_RETURN (CKR_KEY_HANDLE_INVALID); } ciRV = MACI_Select (hs, slot->slotID); if (ciRV != CI_OK) { fort11_FreeSession(session); FORT11_RETURN (CKR_DEVICE_ERROR); } ciRV = MACI_SetMode(hs, CI_ENCRYPT_TYPE, CI_CBC64_MODE); if (ciRV != CI_OK) { fort11_FreeSession(session); FORT11_RETURN (CKR_DEVICE_ERROR); } /*Load the correct key into a key register*/ fortezzaKey = (FortezzaKey*)keyObject->objectInfo; fort11_FreeObject (keyObject); if (fortezzaKey == NULL) { fort11_FreeSession(session); FORT11_RETURN (CKR_GENERAL_ERROR); } if (fortezzaKey->keyRegister == KeyNotLoaded) { registerIndex = LoadKeyIntoRegister (fortezzaKey); } else { registerIndex = fortezzaKey->keyRegister; } if (registerIndex == KeyNotLoaded) { fort11_FreeSession(session); FORT11_RETURN (CKR_DEVICE_ERROR); } ciRV = MACI_SetKey (hs,registerIndex); if (ciRV != CI_OK) { fort11_FreeSession(session); FORT11_RETURN (CKR_DEVICE_ERROR); } ciRV = MACI_GenerateIV(hs, fortezzaIV); if (ciRV != CI_OK) { fort11_FreeSession(session); FORT11_RETURN (CKR_DEVICE_ERROR); } context = &session->fortezzaContext; InitContext(context, socket, hKey); ciRV = SaveState(context, fortezzaIV, session, fortezzaKey, CI_ENCRYPT_EXT_TYPE, pMechanism->mechanism); if (ciRV != SOCKET_SUCCESS) { fort11_FreeSession(session); FORT11_RETURN (CKR_GENERAL_ERROR); } if (pMechanism->pParameter != NULL && pMechanism->ulParameterLen >= sizeof(CI_IV)) { PORT_Memcpy (pMechanism->pParameter, fortezzaIV, sizeof(CI_IV)); } InitCryptoOperation(context, Encrypt); fort11_FreeSession(session); FORT11_RETURN (CKR_OK); } /* C_Encrypt encrypts single-part data. */ PR_PUBLIC_API(CK_RV) C_Encrypt (CK_SESSION_HANDLE hSession, CK_BYTE_PTR pData, CK_ULONG ulDataLen, CK_BYTE_PTR pEncryptedData, CK_ULONG_PTR pulEncryptedDataLen) { FORT11_ENTER() PK11Session *session = fort11_SessionFromHandle (hSession, PR_FALSE); PK11Slot *slot = fort11_SlotFromSessionHandle(hSession); FortezzaSocket *socket = &fortezzaSockets[slot->slotID-1]; FortezzaContext *context; HSESSION hs; CK_RV rv; if (session == NULL) { session = fort11_SessionFromHandle (hSession , PR_TRUE); fort11_TokenRemoved(slot, session); fort11_FreeSession(session); FORT11_RETURN (CKR_SESSION_HANDLE_INVALID); } context = &session->fortezzaContext; if (GetCryptoOperation(context) != Encrypt) { fort11_FreeSession(session); FORT11_RETURN (CKR_OPERATION_NOT_INITIALIZED); } *pulEncryptedDataLen = ulDataLen; if (pEncryptedData == NULL) { fort11_FreeSession(session); FORT11_RETURN (CKR_OK); } hs = socket->maciSession; FMUTEX_Lock(socket->registersLock); MACI_Lock(hs, CI_BLOCK_LOCK_FLAG); rv = EncryptData (context, pData, ulDataLen, pEncryptedData, *pulEncryptedDataLen); MACI_Unlock(hs); FMUTEX_Unlock(socket->registersLock); if (rv != SOCKET_SUCCESS) { fort11_FreeSession(session); FORT11_RETURN (CKR_GENERAL_ERROR); } EndCryptoOperation(context, Encrypt); fort11_FreeSession(session); FORT11_RETURN (CKR_OK); } /* C_EncryptUpdate continues a multiple-part encryption operation. */ PR_PUBLIC_API(CK_RV) C_EncryptUpdate(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pPart, CK_ULONG ulPartLen, CK_BYTE_PTR pEncryptedPart, CK_ULONG_PTR pulEncryptedPartLen) { FORT11_ENTER() PK11Session *session = fort11_SessionFromHandle(hSession,PR_FALSE); PK11Slot *slot = fort11_SlotFromSessionHandle(hSession); FortezzaSocket *socket = &fortezzaSockets[slot->slotID-1]; FortezzaContext *context; int rv; if (session == NULL) { session = fort11_SessionFromHandle(hSession, PR_TRUE); fort11_TokenRemoved (slot, session); fort11_FreeSession(session); FORT11_RETURN (CKR_SESSION_HANDLE_INVALID); } context = &session->fortezzaContext; if (GetCryptoOperation(context) != Encrypt) { fort11_FreeSession(session); FORT11_RETURN (CKR_OPERATION_NOT_INITIALIZED); } if (pEncryptedPart == NULL) { *pulEncryptedPartLen = ulPartLen; fort11_FreeSession(session); FORT11_RETURN (CKR_OK); } if (*pulEncryptedPartLen < ulPartLen) { fort11_FreeSession(session); FORT11_RETURN (CKR_BUFFER_TOO_SMALL); } *pulEncryptedPartLen = ulPartLen; FMUTEX_Lock(socket->registersLock); MACI_Lock(socket->maciSession, CI_BLOCK_LOCK_FLAG); rv = EncryptData(context,pPart, ulPartLen, pEncryptedPart, *pulEncryptedPartLen); MACI_Unlock(socket->maciSession); FMUTEX_Unlock(socket->registersLock); fort11_FreeSession(session); if (rv != SOCKET_SUCCESS) { FORT11_RETURN (CKR_GENERAL_ERROR); } FORT11_RETURN (CKR_OK); } /* C_EncryptFinal finishes a multiple-part encryption operation. */ PR_PUBLIC_API(CK_RV) C_EncryptFinal(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pLastEncryptedPart, CK_ULONG_PTR pulLastEncryptedPartLen){ FORT11_ENTER() PK11Session *session = fort11_SessionFromHandle(hSession, PR_FALSE); PK11Slot *slot = fort11_SlotFromSessionHandle(hSession); FortezzaContext *context; int rv; if (session == NULL) { session = fort11_SessionFromHandle(hSession, PR_TRUE); fort11_TokenRemoved(slot, session); fort11_FreeSession(session); FORT11_RETURN (CKR_SESSION_HANDLE_INVALID); } context = &session->fortezzaContext; rv = EndCryptoOperation(context, Encrypt); fort11_FreeSession(session); FORT11_RETURN (CKR_OK); } /* C_DecryptInit initializes a decryption operation. */ PR_PUBLIC_API(CK_RV) C_DecryptInit( CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hKey) { FORT11_ENTER() PK11Session *session = fort11_SessionFromHandle(hSession, PR_FALSE); PK11Slot *slot = fort11_SlotFromSessionHandle(hSession); PK11Object *keyObject; FortezzaSocket *socket = &fortezzaSockets[slot->slotID-1]; FortezzaContext *context; HSESSION hs = socket->maciSession; FortezzaKey *fortezzaKey; CI_IV fortezzaIV; int ciRV, registerIndex; if (pMechanism->mechanism != CKM_SKIPJACK_CBC64) { if (session) fort11_FreeSession(session); FORT11_RETURN (CKR_MECHANISM_INVALID); } if (session == NULL) { session = fort11_SessionFromHandle (hSession, PR_TRUE); fort11_TokenRemoved(slot, session); fort11_FreeSession(session); FORT11_RETURN (CKR_SESSION_HANDLE_INVALID); } keyObject = fort11_ObjectFromHandle (hKey, session); if (keyObject == NULL) { fort11_FreeSession(session); FORT11_RETURN (CKR_KEY_HANDLE_INVALID); } fortezzaKey = (FortezzaKey*)keyObject->objectInfo; fort11_FreeObject(keyObject); if (fortezzaKey == NULL) { fort11_FreeSession(session); FORT11_RETURN (CKR_GENERAL_ERROR); } ciRV = MACI_Select (hs, slot->slotID); if (ciRV != CI_OK) { fort11_FreeSession(session); FORT11_RETURN (CKR_DEVICE_ERROR); } ciRV = MACI_SetMode(hs, CI_DECRYPT_TYPE, CI_CBC64_MODE); if (ciRV != CI_OK) { fort11_FreeSession(session); FORT11_RETURN (CKR_DEVICE_ERROR); } FMUTEX_Lock(socket->registersLock); if (fortezzaKey->keyRegister == KeyNotLoaded) { registerIndex = LoadKeyIntoRegister(fortezzaKey); } else { registerIndex = fortezzaKey->keyRegister; } if (registerIndex == KeyNotLoaded) { FMUTEX_Unlock(socket->registersLock); FORT11_RETURN (CKR_DEVICE_ERROR); } if (pMechanism->pParameter == NULL || pMechanism->ulParameterLen < sizeof (CI_IV)) { FORT11_RETURN (CKR_MECHANISM_PARAM_INVALID); } PORT_Memcpy (fortezzaIV, pMechanism->pParameter, sizeof(CI_IV)); ciRV = MACI_SetKey (hs, registerIndex); if (ciRV != CI_OK) { FMUTEX_Unlock(socket->registersLock); fort11_FreeSession(session); FORT11_RETURN (CKR_DEVICE_ERROR); } ciRV = MACI_LoadIV (hs, fortezzaIV); if (ciRV != CI_OK) { FMUTEX_Unlock(socket->registersLock); fort11_FreeSession(session); FORT11_RETURN (CKR_DEVICE_ERROR); } context = &session->fortezzaContext; InitContext(context, socket, hKey); ciRV = SaveState (context, fortezzaIV, session, fortezzaKey, CI_DECRYPT_EXT_TYPE, pMechanism->mechanism); FMUTEX_Unlock(socket->registersLock); if (ciRV != SOCKET_SUCCESS) { FORT11_RETURN (CKR_GENERAL_ERROR); } InitCryptoOperation (context, Decrypt); fort11_FreeSession (session); FORT11_RETURN (CKR_OK); } /* C_Decrypt decrypts encrypted data in a single part. */ PR_PUBLIC_API(CK_RV) C_Decrypt(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pEncryptedData, CK_ULONG ulEncryptedDataLen, CK_BYTE_PTR pData, CK_ULONG_PTR pulDataLen) { FORT11_ENTER() PK11Session *session = fort11_SessionFromHandle (hSession, PR_FALSE); PK11Slot *slot = fort11_SlotFromSessionHandle(hSession); FortezzaSocket *socket = &fortezzaSockets[slot->slotID-1]; FortezzaContext *context; HSESSION hs; CK_RV rv; if (session == NULL) { session = fort11_SessionFromHandle(hSession, PR_TRUE); fort11_TokenRemoved(slot, session); fort11_FreeSession(session); FORT11_RETURN (CKR_SESSION_HANDLE_INVALID); } context = &session->fortezzaContext; if (GetCryptoOperation(context) != Decrypt) { fort11_FreeSession(session); FORT11_RETURN (CKR_OPERATION_NOT_INITIALIZED); } *pulDataLen = ulEncryptedDataLen; if (pData == NULL) { fort11_FreeSession(session); FORT11_RETURN (CKR_OK); } hs = socket->maciSession; FMUTEX_Lock(socket->registersLock); MACI_Lock(hs, CI_NULL_FLAG); rv = DecryptData (context, pEncryptedData, ulEncryptedDataLen, pData, *pulDataLen); MACI_Unlock(hs); FMUTEX_Unlock(socket->registersLock); if (rv != SOCKET_SUCCESS) { fort11_FreeSession(session); FORT11_RETURN (CKR_GENERAL_ERROR); } EndCryptoOperation (context, Decrypt); fort11_FreeSession(session); FORT11_RETURN (CKR_OK); } /* C_DecryptUpdate continues a multiple-part decryption operation. */ PR_PUBLIC_API(CK_RV) C_DecryptUpdate(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pEncryptedPart, CK_ULONG ulEncryptedPartLen, CK_BYTE_PTR pPart, CK_ULONG_PTR pulPartLen) { FORT11_ENTER() PK11Session *session = fort11_SessionFromHandle(hSession,PR_FALSE); PK11Slot *slot = fort11_SlotFromSessionHandle(hSession); FortezzaSocket *socket = &fortezzaSockets[slot->slotID-1]; FortezzaContext *context; HSESSION hs; int rv; if (session == NULL) { session = fort11_SessionFromHandle(hSession, PR_TRUE); fort11_TokenRemoved (slot, session); fort11_FreeSession (session); FORT11_RETURN (CKR_SESSION_HANDLE_INVALID); } context = &session->fortezzaContext; hs = socket->maciSession; if (GetCryptoOperation(context) != Decrypt) { fort11_FreeSession(session); FORT11_RETURN (CKR_OPERATION_NOT_INITIALIZED); } if (pPart == NULL) { *pulPartLen = ulEncryptedPartLen; fort11_FreeSession(session); FORT11_RETURN (CKR_OK); } *pulPartLen = ulEncryptedPartLen; FMUTEX_Lock(socket->registersLock); MACI_Lock (hs, CI_NULL_FLAG); rv = DecryptData (context, pEncryptedPart, ulEncryptedPartLen, pPart, *pulPartLen); MACI_Unlock(hs); FMUTEX_Unlock(socket->registersLock); fort11_FreeSession(session); if (rv != SOCKET_SUCCESS) { FORT11_RETURN (CKR_GENERAL_ERROR); } FORT11_RETURN (CKR_OK); } /* C_DecryptFinal finishes a multiple-part decryption operation. */ PR_PUBLIC_API(CK_RV) C_DecryptFinal(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pLastPart, CK_ULONG_PTR pulLastPartLen) { FORT11_ENTER() PK11Session *session = fort11_SessionFromHandle(hSession, PR_FALSE); PK11Slot *slot = fort11_SlotFromSessionHandle(hSession); FortezzaContext *context; if (session == NULL) { session = fort11_SessionFromHandle (hSession, PR_TRUE); fort11_TokenRemoved (slot, session); fort11_FreeSession(session); FORT11_RETURN (CKR_SESSION_HANDLE_INVALID); } context = &session->fortezzaContext; EndCryptoOperation (context, Decrypt); fort11_FreeSession(session); FORT11_RETURN (CKR_OK); } /* ************** Crypto Functions: Digest (HASH) ************************ */ /* C_DigestInit initializes a message-digesting operation. */ PR_PUBLIC_API(CK_RV) C_DigestInit(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism) { /* For functions that don't access globals, we don't have to worry about the * stack. */ return CKR_FUNCTION_NOT_SUPPORTED; } /* C_Digest digests data in a single part. */ PR_PUBLIC_API(CK_RV) C_Digest(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pData, CK_ULONG ulDataLen, CK_BYTE_PTR pDigest, CK_ULONG_PTR pulDigestLen) { /* For functions that don't access globals, we don't have to worry about the * stack. */ return CKR_FUNCTION_NOT_SUPPORTED; } /* C_DigestUpdate continues a multiple-part message-digesting operation. */ PR_PUBLIC_API(CK_RV) C_DigestUpdate(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pPart, CK_ULONG ulPartLen) { /* For functions that don't access globals, we don't have to worry about the * stack. */ return CKR_FUNCTION_NOT_SUPPORTED; } /* C_DigestFinal finishes a multiple-part message-digesting operation. */ PR_PUBLIC_API(CK_RV) C_DigestFinal(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pDigest, CK_ULONG_PTR pulDigestLen) { /* For functions that don't access globals, we don't have to worry about the * stack. */ return CKR_FUNCTION_NOT_SUPPORTED; } /* ************** Crypto Functions: Sign ************************ */ /* C_SignInit initializes a signature (private key encryption) operation, * where the signature is (will be) an appendix to the data, * and plaintext cannot be recovered from the signature */ PR_PUBLIC_API(CK_RV) C_SignInit(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hKey) { FORT11_ENTER() PK11Session *session = fort11_SessionFromHandle (hSession, PR_FALSE); PK11Slot *slot = fort11_SlotFromSessionHandle(hSession); PK11Object *keyObject; FortezzaSocket *socket = &fortezzaSockets[slot->slotID-1]; FortezzaContext *context; PK11Attribute *idAttribute; int personalityIndex; HSESSION hs = socket->maciSession; if (session == NULL) { session = fort11_SessionFromHandle(hSession, PR_TRUE); fort11_TokenRemoved(slot, session); fort11_FreeSession(session); FORT11_RETURN (CKR_SESSION_HANDLE_INVALID); } if (pMechanism->mechanism != CKM_DSA) { FORT11_RETURN (CKR_MECHANISM_INVALID); } keyObject = fort11_ObjectFromHandle (hKey, session); if (keyObject == NULL) { fort11_FreeSession(session); FORT11_RETURN (CKR_KEY_HANDLE_INVALID); } context = &session->fortezzaContext; InitContext(context, socket, hKey); InitCryptoOperation (context, Sign); fort11_FreeSession(session); idAttribute = fort11_FindAttribute(keyObject, CKA_ID); fort11_FreeObject(keyObject); if (idAttribute == NULL) { FORT11_RETURN (CKR_KEY_HANDLE_INVALID); } personalityIndex = *(int*)(idAttribute->attrib.pValue); fort11_FreeAttribute(idAttribute); MACI_Select (hs, slot->slotID); if (MACI_SetPersonality (hs,personalityIndex) != CI_OK) { FORT11_RETURN (CKR_GENERAL_ERROR); } FORT11_RETURN (CKR_OK); } /* C_Sign signs (encrypts with private key) data in a single part, * where the signature is (will be) an appendix to the data, * and plaintext cannot be recovered from the signature */ PR_PUBLIC_API(CK_RV) C_Sign(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pData, CK_ULONG ulDataLen, CK_BYTE_PTR pSignature, CK_ULONG_PTR pulSignatureLen) { FORT11_ENTER() PK11Session *session = fort11_SessionFromHandle(hSession, PR_FALSE); PK11Slot *slot = fort11_SlotFromSessionHandle(hSession); FortezzaContext *context; FortezzaSocket *socket = &fortezzaSockets[slot->slotID-1]; HSESSION hs = socket->maciSession; PK11Object *keyObject; PK11Attribute *idAttribute; int ciRV, personalityIndex; if (session == NULL) { session = fort11_SessionFromHandle(hSession, PR_TRUE); fort11_TokenRemoved (slot, session); fort11_FreeSession(session); FORT11_RETURN (CKR_SESSION_HANDLE_INVALID); } context = &session->fortezzaContext; if (GetCryptoOperation(context) != Sign) { fort11_FreeSession(session); FORT11_RETURN (CKR_OPERATION_NOT_INITIALIZED); } if (pSignature == NULL) { *pulSignatureLen = 40; fort11_FreeSession(session); FORT11_RETURN (CKR_OK); } if (ulDataLen > 20) { FORT11_RETURN (CKR_DATA_LEN_RANGE); } if (*pulSignatureLen < 40) { fort11_FreeSession(session); FORT11_RETURN (CKR_BUFFER_TOO_SMALL); } *pulSignatureLen = 40; keyObject = fort11_ObjectFromHandle(context->hKey, session); if (keyObject == NULL) { fort11_FreeSession(session); FORT11_RETURN(CKR_GENERAL_ERROR); } idAttribute = fort11_FindAttribute(keyObject, CKA_ID); fort11_FreeObject(keyObject); personalityIndex = *(int*)(idAttribute->attrib.pValue); fort11_FreeAttribute(idAttribute); MACI_Select(hs, slot->slotID); MACI_Lock(hs, CI_BLOCK_LOCK_FLAG); ciRV = MACI_SetPersonality(hs, personalityIndex); if (ciRV != CI_OK) { MACI_Unlock(hs); fort11_FreeSession(session); FORT11_RETURN(CKR_DEVICE_ERROR); } ciRV = MACI_Sign (hs, pData, pSignature); if (ciRV != CI_OK) { MACI_Unlock(hs); fort11_FreeSession(session); FORT11_RETURN (CKR_DEVICE_ERROR); } MACI_Unlock(hs); EndCryptoOperation (context, Sign); fort11_FreeSession(session); FORT11_RETURN (CKR_OK); } /* C_SignUpdate continues a multiple-part signature operation, * where the signature is (will be) an appendix to the data, * and plaintext cannot be recovered from the signature */ PR_PUBLIC_API(CK_RV) C_SignUpdate(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pPart, CK_ULONG ulPartLen) { /* For functions that don't access globals, we don't have to worry about the * stack. */ return CKR_FUNCTION_NOT_SUPPORTED; } /* C_SignFinal finishes a multiple-part signature operation, * FORT11_RETURNing the signature. */ PR_PUBLIC_API(CK_RV) C_SignFinal(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pSignature, CK_ULONG_PTR pulSignatureLen) { /* For functions that don't access globals, we don't have to worry about the * stack. */ return CKR_FUNCTION_NOT_SUPPORTED; } /* ************** Crypto Functions: Sign Recover ************************ */ /* C_SignRecoverInit initializes a signature operation, * where the (digest) data can be recovered from the signature. * E.g. encryption with the user's private key */ PR_PUBLIC_API(CK_RV) C_SignRecoverInit(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hKey) { /* For functions that don't access globals, we don't have to worry about the * stack. */ return CKR_FUNCTION_NOT_SUPPORTED; } /* C_SignRecover signs data in a single operation * where the (digest) data can be recovered from the signature. * E.g. encryption with the user's private key */ PR_PUBLIC_API(CK_RV) C_SignRecover(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pData, CK_ULONG ulDataLen, CK_BYTE_PTR pSignature, CK_ULONG_PTR pulSignatureLen) { /* For functions that don't access globals, we don't have to worry about the * stack. */ return CKR_FUNCTION_NOT_SUPPORTED; } /* ************** Crypto Functions: verify ************************ */ /* C_VerifyInit initializes a verification operation, * where the signature is an appendix to the data, * and plaintext cannot be recovered from the signature (e.g. DSA) */ PR_PUBLIC_API(CK_RV) C_VerifyInit(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hKey) { /* For functions that don't access globals, we don't have to worry about the * stack. */ return CKR_FUNCTION_NOT_SUPPORTED; } /* C_Verify verifies a signature in a single-part operation, * where the signature is an appendix to the data, * and plaintext cannot be recovered from the signature */ PR_PUBLIC_API(CK_RV) C_Verify(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pData, CK_ULONG ulDataLen, CK_BYTE_PTR pSignature, CK_ULONG ulSignatureLen) { /* For functions that don't access globals, we don't have to worry about the * stack. */ return CKR_FUNCTION_NOT_SUPPORTED; } /* C_VerifyUpdate continues a multiple-part verification operation, * where the signature is an appendix to the data, * and plaintext cannot be recovered from the signature */ PR_PUBLIC_API(CK_RV) C_VerifyUpdate( CK_SESSION_HANDLE hSession, CK_BYTE_PTR pPart, CK_ULONG ulPartLen) { return CKR_FUNCTION_NOT_SUPPORTED; } /* C_VerifyFinal finishes a multiple-part verification operation, * checking the signature. */ PR_PUBLIC_API(CK_RV) C_VerifyFinal(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pSignature, CK_ULONG ulSignatureLen) { /* For functions that don't access globals, we don't have to worry about the * stack. */ return CKR_FUNCTION_NOT_SUPPORTED; } /* ************** Crypto Functions: Verify Recover ************************ */ /* C_VerifyRecoverInit initializes a signature verification operation, * where the data is recovered from the signature. * E.g. Decryption with the user's public key */ PR_PUBLIC_API(CK_RV) C_VerifyRecoverInit(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hKey) { /* For functions that don't access globals, we don't have to worry about the * stack. */ return CKR_FUNCTION_NOT_SUPPORTED; } /* C_VerifyRecover verifies a signature in a single-part operation, * where the data is recovered from the signature. * E.g. Decryption with the user's public key */ PR_PUBLIC_API(CK_RV) C_VerifyRecover(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pSignature, CK_ULONG ulSignatureLen, CK_BYTE_PTR pData, CK_ULONG_PTR pulDataLen) { return CKR_FUNCTION_NOT_SUPPORTED; } /* **************************** Key Functions: ************************ */ #define MAX_KEY_LEN 256 /* C_GenerateKey generates a secret key, creating a new key object. */ PR_PUBLIC_API(CK_RV) C_GenerateKey(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount, CK_OBJECT_HANDLE_PTR phKey) { FORT11_ENTER() PK11Session *session = fort11_SessionFromHandle(hSession, PR_FALSE); PK11Slot *slot = fort11_SlotFromSessionHandle(hSession); FortezzaSocket *socket = &fortezzaSockets[slot->slotID-1]; PK11Object *key; FortezzaKey *newKey; int i, keyRegister; CK_ULONG key_length = 0; CK_RV crv = CKR_OK; CK_OBJECT_CLASS secretKey = CKO_SECRET_KEY; CK_BBOOL False = FALSE; CK_BBOOL cktrue = TRUE; if (session == NULL) { session = fort11_SessionFromHandle (hSession, PR_TRUE); fort11_TokenRemoved (slot, session); fort11_FreeSession(session); FORT11_RETURN (CKR_SESSION_HANDLE_INVALID); } if (pMechanism->mechanism != CKM_SKIPJACK_KEY_GEN) { fort11_FreeSession(session); FORT11_RETURN (CKR_MECHANISM_INVALID); } key = fort11_NewObject(slot); if (key == NULL) { fort11_FreeSession(session); FORT11_RETURN (CKR_HOST_MEMORY); } for (i=0; i < (int) ulCount; i++) { if (pTemplate[i].type == CKA_VALUE_LEN) { key_length = *(CK_ULONG *)pTemplate[i].pValue; continue; } crv = fort11_AddAttributeType (key, pk11_attr_expand (&pTemplate[i])); if (crv != CKR_OK) break; } if (crv != CKR_OK) { fort11_FreeObject(key); fort11_FreeSession(session); FORT11_RETURN (crv); } /* make sure we don't have any class, key_type, or value fields */ fort11_DeleteAttributeType(key,CKA_CLASS); fort11_DeleteAttributeType(key,CKA_KEY_TYPE); fort11_DeleteAttributeType(key,CKA_VALUE); if (MAX_KEY_LEN < key_length) { crv = CKR_TEMPLATE_INCONSISTENT; } if (crv != CKR_OK) { fort11_FreeObject(key); fort11_FreeSession(session); FORT11_RETURN (crv); } if (fort11_AddAttributeType(key, CKA_CLASS,&secretKey, sizeof(CK_OBJECT_CLASS)) != CKR_OK) { fort11_FreeObject(key); fort11_FreeSession(session); FORT11_RETURN (CKR_GENERAL_ERROR); } if (fort11_AddAttributeType(key, CKA_TOKEN, &False, sizeof(CK_BBOOL)) != CKR_OK) { fort11_FreeObject(key); fort11_FreeSession(session); FORT11_RETURN (CKR_GENERAL_ERROR); } if (fort11_isTrue(key,CKA_SENSITIVE)) { fort11_forceAttribute(key,CKA_ALWAYS_SENSITIVE,&cktrue, sizeof(CK_BBOOL)); } if (!fort11_isTrue(key,CKA_EXTRACTABLE)) { fort11_forceAttribute(key,CKA_NEVER_EXTRACTABLE,&cktrue, sizeof(CK_BBOOL)); } FMUTEX_Lock(socket->registersLock); keyRegister = GetBestKeyRegister(socket); newKey = NewFortezzaKey(socket, MEK, NULL, keyRegister); FMUTEX_Unlock(socket->registersLock); if (newKey == NULL) { fort11_FreeObject(key); fort11_FreeSession(session); FORT11_RETURN (CKR_HOST_MEMORY); } key->objectInfo = (void*)newKey; key->infoFree = fort11_FreeFortezzaKey; FMUTEX_Lock(slot->objectLock); key->handle = slot->tokenIDCount++; key->handle |= (PK11_TOKEN_MAGIC | PK11_TOKEN_TYPE_PRIV); FMUTEX_Unlock(slot->objectLock); key->objclass = secretKey; key->slot = slot; key->inDB = PR_TRUE; fort11_AddObject(session, key); fort11_FreeSession(session); SetFortezzaKeyHandle(newKey, key->handle); *phKey = key->handle; FORT11_RETURN (CKR_OK); } /* C_GenerateKeyPair generates a public-key/private-key pair, * creating new key objects. */ PR_PUBLIC_API(CK_RV) C_GenerateKeyPair (CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, CK_ATTRIBUTE_PTR pPublicKeyTemplate, CK_ULONG ulPublicKeyAttributeCount, CK_ATTRIBUTE_PTR pPrivateKeyTemplate, CK_ULONG ulPrivateKeyAttributeCount, CK_OBJECT_HANDLE_PTR phPrivateKey, CK_OBJECT_HANDLE_PTR phPublicKey) { return CKR_FUNCTION_NOT_SUPPORTED; } /* C_WrapKey wraps (i.e., encrypts) a key. */ PR_PUBLIC_API(CK_RV) C_WrapKey(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hWrappingKey, CK_OBJECT_HANDLE hKey, CK_BYTE_PTR pWrappedKey, CK_ULONG_PTR pulWrappedKeyLen) { FORT11_ENTER() PK11Session *session = fort11_SessionFromHandle (hSession, PR_FALSE); PK11Slot *slot = fort11_SlotFromSessionHandle(hSession); FortezzaSocket *socket = &fortezzaSockets[slot->slotID-1]; PK11Object *wrapKey; PK11Object *srcKey; FortezzaKey *wrapFortKey; FortezzaKey *srcFortKey; int rv; if (session == NULL) { session = fort11_SessionFromHandle (hSession, PR_TRUE); fort11_TokenRemoved(slot, session); fort11_FreeSession(session); FORT11_RETURN (CKR_SESSION_HANDLE_INVALID); } if (!socket->isLoggedIn) { fort11_FreeSession(session); FORT11_RETURN (CKR_USER_NOT_LOGGED_IN); } if (pMechanism->mechanism != CKM_SKIPJACK_WRAP) { fort11_FreeSession(session); FORT11_RETURN (CKR_MECHANISM_INVALID); } wrapKey = fort11_ObjectFromHandle (hWrappingKey, session); if ((wrapKey == NULL) || (wrapKey->objectInfo == NULL)) { if (wrapKey) fort11_FreeObject(wrapKey); fort11_FreeSession(session); FORT11_RETURN (CKR_KEY_HANDLE_INVALID); } srcKey = fort11_ObjectFromHandle (hKey, session); fort11_FreeSession(session); if ((srcKey == NULL) || (srcKey->objectInfo == NULL)) { FORT11_RETURN (CKR_KEY_HANDLE_INVALID); } wrapFortKey = (FortezzaKey*)wrapKey->objectInfo; fort11_FreeObject(wrapKey); srcFortKey = (FortezzaKey*)srcKey->objectInfo; fort11_FreeObject(srcKey); FMUTEX_Lock(socket->registersLock); if (wrapFortKey->keyRegister == KeyNotLoaded) { if (LoadKeyIntoRegister(wrapFortKey) == KeyNotLoaded) { FORT11_RETURN (CKR_DEVICE_ERROR); } } if (srcFortKey->keyRegister == KeyNotLoaded) { if (LoadKeyIntoRegister(srcFortKey) == KeyNotLoaded) { FMUTEX_Unlock(socket->registersLock); FORT11_RETURN (CKR_DEVICE_ERROR); } } MACI_Lock(socket->maciSession, CI_BLOCK_LOCK_FLAG); rv = WrapKey (wrapFortKey, srcFortKey, pWrappedKey, *pulWrappedKeyLen); MACI_Unlock(socket->maciSession); FMUTEX_Unlock(socket->registersLock); if (rv != SOCKET_SUCCESS) { FORT11_RETURN (CKR_GENERAL_ERROR); } FORT11_RETURN (CKR_OK); } /* C_UnwrapKey unwraps (decrypts) a wrapped key, creating a new key object. */ PR_PUBLIC_API(CK_RV) C_UnwrapKey(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hUnwrappingKey, CK_BYTE_PTR pWrappedKey, CK_ULONG ulWrappedKeyLen, CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulAttributeCount, CK_OBJECT_HANDLE_PTR phKey) { FORT11_ENTER() PK11Session *session = fort11_SessionFromHandle(hSession, PR_FALSE); PK11Slot *slot = fort11_SlotFromSessionHandle(hSession); FortezzaSocket *socket = &fortezzaSockets[slot->slotID-1]; PK11Object *wrapKey; PK11Object *newKey; FortezzaKey *fortKey; FortezzaKey *unwrapFort; CK_ULONG key_length; int i, newKeyRegister; CK_RV crv = CKR_OK; if (session == NULL) { session = fort11_SessionFromHandle(hSession, PR_TRUE); fort11_TokenRemoved(slot, session); fort11_FreeSession(session); FORT11_RETURN (CKR_SESSION_HANDLE_INVALID); } if (pMechanism->mechanism != CKM_SKIPJACK_WRAP){ fort11_FreeSession(session); FORT11_RETURN (CKR_MECHANISM_INVALID); } if (!socket->isLoggedIn) { fort11_FreeSession(session); FORT11_RETURN (CKR_USER_NOT_LOGGED_IN); } wrapKey = fort11_ObjectFromHandle(hUnwrappingKey, session); if (wrapKey == NULL || wrapKey->objectInfo == NULL) { if (wrapKey) fort11_FreeObject(wrapKey); fort11_FreeSession(session); FORT11_RETURN (CKR_UNWRAPPING_KEY_HANDLE_INVALID); } fortKey = (FortezzaKey*)wrapKey->objectInfo; fort11_FreeObject(wrapKey); newKey = fort11_NewObject(slot); if (newKey == NULL) { fort11_FreeSession(session); FORT11_RETURN (CKR_HOST_MEMORY); } for (i=0; i< (int)ulAttributeCount; i++) { if (pTemplate[i].type == CKA_VALUE_LEN) { key_length = *(CK_ULONG*)pTemplate[i].pValue; continue; } crv=fort11_AddAttributeType(newKey,fort11_attr_expand(&pTemplate[i])); if (crv != CKR_OK) { break; } } if (crv != CKR_OK) { fort11_FreeSession(session); fort11_FreeObject(newKey); FORT11_RETURN (crv); } /* make sure we don't have any class, key_type, or value fields */ if (!fort11_hasAttribute(newKey,CKA_CLASS)) { fort11_FreeObject(newKey); fort11_FreeSession(session); FORT11_RETURN (CKR_TEMPLATE_INCOMPLETE); } if (!fort11_hasAttribute(newKey,CKA_KEY_TYPE)) { fort11_FreeObject(newKey); fort11_FreeSession(session); FORT11_RETURN (CKR_TEMPLATE_INCOMPLETE); } FMUTEX_Lock(socket->registersLock); newKeyRegister = UnwrapKey (pWrappedKey, fortKey); if (newKeyRegister == KeyNotLoaded) { /*Couldn't Unwrap the key*/ fort11_FreeObject(newKey); fort11_FreeSession(session); FMUTEX_Unlock(socket->registersLock); FORT11_RETURN (CKR_GENERAL_ERROR); } unwrapFort = NewUnwrappedKey(newKeyRegister, fortKey->id, socket); FMUTEX_Unlock(socket->registersLock); if (unwrapFort == NULL) { fort11_FreeObject(newKey); fort11_FreeSession(session); FORT11_RETURN (CKR_HOST_MEMORY); } newKey->objectInfo = unwrapFort; newKey->infoFree = fort11_FreeFortezzaKey; FMUTEX_Lock(slot->objectLock); newKey->handle = slot->tokenIDCount++; newKey->handle |= (PK11_TOKEN_MAGIC | PK11_TOKEN_TYPE_PRIV); FMUTEX_Unlock(slot->objectLock); newKey->objclass = CKO_SECRET_KEY; newKey->slot = slot; newKey->inDB = PR_TRUE; fort11_AddObject (session, newKey); fort11_FreeSession(session); SetFortezzaKeyHandle(unwrapFort, newKey->handle); *phKey = newKey->handle; FORT11_RETURN (CKR_OK); } /* C_DeriveKey derives a key from a base key, creating a new key object. */ PR_PUBLIC_API(CK_RV) C_DeriveKey( CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hBaseKey, CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulAttributeCount, CK_OBJECT_HANDLE_PTR phKey) { FORT11_ENTER() PK11Session *session = fort11_SessionFromHandle(hSession, PR_FALSE); PK11Slot *slot = fort11_SlotFromSessionHandle(hSession); FortezzaSocket *socket = &fortezzaSockets[slot->slotID-1]; PK11Object *key, *sourceKey; CK_ULONG i; CK_ULONG key_length = 0; CK_RV crv = 0; CK_KEY_TYPE keyType = CKK_SKIPJACK; CK_OBJECT_CLASS classType = CKO_SECRET_KEY; CK_BBOOL ckTrue = TRUE; CK_BBOOL ckFalse = FALSE; int ciRV; int personality; PK11Attribute *att; CK_KEA_DERIVE_PARAMS_PTR params; FortezzaKey *derivedKey; CreateTEKInfo tekInfo; if (session == NULL) { session = fort11_SessionFromHandle(hSession, PR_TRUE); fort11_TokenRemoved (slot, session); fort11_FreeSession(session); FORT11_RETURN (CKR_SESSION_HANDLE_INVALID); } if (pMechanism->mechanism != CKM_KEA_KEY_DERIVE) { fort11_FreeSession(session); FORT11_RETURN (CKR_MECHANISM_INVALID); } key = fort11_NewObject (slot); if (key == NULL) { fort11_FreeSession(session); FORT11_RETURN (CKR_HOST_MEMORY); } for (i = 0; i < ulAttributeCount; i++) { crv = fort11_AddAttributeType (key, fort11_attr_expand(&pTemplate[i])); if (crv != CKR_OK) { break; } if (pTemplate[i].type == CKA_KEY_TYPE) { keyType = *(CK_KEY_TYPE*)pTemplate[i].pValue; } else if (pTemplate[i].type == CKA_VALUE_LEN) { key_length = *(CK_ULONG*)pTemplate[i].pValue; } } if (crv != CKR_OK) { fort11_FreeObject(key); fort11_FreeSession(session); FORT11_RETURN (crv); } if (key_length == 0) { key_length = 12; } classType = CKO_SECRET_KEY; crv = fort11_forceAttribute (key, CKA_CLASS, &classType, sizeof(classType)); if (crv != CKR_OK) { fort11_FreeObject(key); fort11_FreeSession(session); FORT11_RETURN (crv); } crv = fort11_forceAttribute (key, CKA_SENSITIVE, &ckTrue, sizeof(CK_BBOOL)); if (crv != CKR_OK) { fort11_FreeObject(key); fort11_FreeSession(session); FORT11_RETURN (crv); } crv = fort11_forceAttribute (key, CKA_EXTRACTABLE, &ckFalse, sizeof(CK_BBOOL)); if (crv != CKR_OK) { fort11_FreeSession(session); fort11_FreeObject(key); FORT11_RETURN (crv); } sourceKey = fort11_ObjectFromHandle (hBaseKey, session); if (sourceKey == NULL) { fort11_FreeObject(key); fort11_FreeSession(session); FORT11_RETURN (CKR_KEY_HANDLE_INVALID); } att = fort11_FindAttribute(sourceKey,CKA_ID); fort11_FreeObject(sourceKey); if (att == NULL) { fort11_FreeObject(key); fort11_FreeSession(session); FORT11_RETURN (CKR_KEY_TYPE_INCONSISTENT); } personality = *(int *) att->attrib.pValue; fort11_FreeAttribute(att); params = (CK_KEA_DERIVE_PARAMS_PTR)pMechanism->pParameter; if (params == NULL) { fort11_FreeObject(key); fort11_FreeSession(session); FORT11_RETURN (CKR_MECHANISM_PARAM_INVALID); } ciRV = MACI_SetPersonality(socket->maciSession,personality); if (ciRV != CI_OK) { fort11_FreeObject(key); fort11_FreeSession(session); FORT11_RETURN (CKR_DEVICE_ERROR); } /* * If we're sending, generate our own RA. */ if (params->isSender) { ciRV = MACI_GenerateRa(socket->maciSession,params->pRandomA); if (ciRV != CI_OK) { fort11_FreeObject(key); fort11_FreeSession(session); FORT11_RETURN (CKR_DEVICE_ERROR); } } PORT_Memcpy (tekInfo.Ra, params->pRandomA, params->ulRandomLen); PORT_Memcpy (tekInfo.Rb, params->pRandomB, params->ulRandomLen); tekInfo.randomLen = params->ulRandomLen; tekInfo.personality = personality; tekInfo.flag = (params->isSender) ? CI_INITIATOR_FLAG : CI_RECIPIENT_FLAG; PORT_Memcpy (tekInfo.pY, params->pPublicData, params->ulPublicDataLen); tekInfo.YSize = params->ulPublicDataLen; FMUTEX_Lock(socket->registersLock); derivedKey = NewFortezzaKey(socket, TEK, &tekInfo, GetBestKeyRegister(socket)); FMUTEX_Unlock(socket->registersLock); if (derivedKey == NULL) { fort11_FreeObject(key); fort11_FreeSession(session); FORT11_RETURN (CKR_GENERAL_ERROR); } key->objectInfo = derivedKey; key->infoFree = fort11_FreeFortezzaKey; FMUTEX_Lock(slot->objectLock); key->handle = slot->tokenIDCount++; key->handle |= (PK11_TOKEN_MAGIC | PK11_TOKEN_TYPE_PRIV); FMUTEX_Unlock(slot->objectLock); key->objclass = classType; key->slot = slot; key->inDB = PR_TRUE; fort11_AddObject (session, key); fort11_FreeSession(session); SetFortezzaKeyHandle(derivedKey, key->handle); *phKey = key->handle; FORT11_RETURN (CKR_OK); } /* **************************** Random Functions: ************************ */ /* C_SeedRandom mixes additional seed material into the token's random number * generator. */ PR_PUBLIC_API(CK_RV) C_SeedRandom(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pSeed, CK_ULONG ulSeedLen) { return CKR_FUNCTION_NOT_SUPPORTED; } /* C_GenerateRandom generates random data. */ PR_PUBLIC_API(CK_RV) C_GenerateRandom(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pRandomData, CK_ULONG ulRandomLen) { FORT11_ENTER() PK11Slot *slot = fort11_SlotFromSessionHandle(hSession); PK11Session *session = fort11_SessionFromHandle(hSession,PR_FALSE); CI_RANDOM randomNum; CK_ULONG randomSize = sizeof (CI_RANDOM); int ciRV; CK_ULONG bytesCopied = 0, bytesToCopy; CK_ULONG bufferSize = 0, bytesRemaining; if (session == NULL) { session = fort11_SessionFromHandle (hSession, PR_TRUE); fort11_TokenRemoved(slot, session); fort11_FreeSession(session); FORT11_RETURN (CKR_SESSION_HANDLE_INVALID); } fort11_FreeSession(session); ciRV = MACI_Select(fortezzaSockets[slot->slotID-1].maciSession, slot->slotID); if (ciRV != CI_OK) { FORT11_RETURN (CKR_DEVICE_ERROR); } while (bytesCopied < ulRandomLen) { bytesRemaining = ulRandomLen - bytesCopied; if (bufferSize < bytesRemaining) { ciRV = MACI_GenerateRandom(fortezzaSockets[slot->slotID-1].maciSession, randomNum); if (ciRV != CI_OK) FORT11_RETURN (CKR_DEVICE_ERROR); bufferSize = randomSize; } bytesToCopy = (bytesRemaining > randomSize) ? randomSize : bytesRemaining; PORT_Memcpy (&pRandomData[bytesCopied], &randomNum[randomSize-bufferSize], bytesToCopy); bytesCopied += bytesToCopy; bufferSize -= bytesToCopy; } FORT11_RETURN (CKR_OK); } /* C_GetFunctionStatus obtains an updated status of a function running * in parallel with an application. */ PR_PUBLIC_API(CK_RV) C_GetFunctionStatus(CK_SESSION_HANDLE hSession) { return CKR_FUNCTION_NOT_SUPPORTED; } /* C_CancelFunction cancels a function running in parallel */ PR_PUBLIC_API(CK_RV) C_CancelFunction(CK_SESSION_HANDLE hSession) { return CKR_FUNCTION_NOT_SUPPORTED; } /* C_GetOperationState saves the state of the cryptographic *operation in a session. */ PR_PUBLIC_API(CK_RV) C_GetOperationState(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pOperationState, CK_ULONG_PTR pulOperationStateLen) { FORT11_ENTER() PK11Session *session = fort11_SessionFromHandle(hSession, PR_FALSE); PK11Slot *slot = fort11_SlotFromSessionHandle(hSession); FortezzaContext *context; if (session == NULL) { session = fort11_SessionFromHandle(hSession, PR_TRUE); fort11_TokenRemoved (slot, session); fort11_FreeSession(session); FORT11_RETURN (CKR_SESSION_HANDLE_INVALID); } if (pOperationState == NULL) { *pulOperationStateLen = sizeof (FortezzaContext); fort11_FreeSession(session); FORT11_RETURN (CKR_OK); } if (*pulOperationStateLen < sizeof (FortezzaContext)) { fort11_FreeSession(session); FORT11_RETURN (CKR_BUFFER_TOO_SMALL); } context = &session->fortezzaContext; fort11_FreeSession(session); PORT_Memcpy (pOperationState, context, sizeof(FortezzaContext)); ((FortezzaContext *)pOperationState)->session = NULL; ((FortezzaContext *)pOperationState)->fortezzaKey = NULL; *pulOperationStateLen = sizeof(FortezzaContext); FORT11_RETURN (CKR_OK); } /* C_SetOperationState restores the state of the cryptographic operation in a session. */ PR_PUBLIC_API(CK_RV) C_SetOperationState(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pOperationState, CK_ULONG ulOperationStateLen, CK_OBJECT_HANDLE hEncryptionKey, CK_OBJECT_HANDLE hAuthenticationKey){ FORT11_ENTER() PK11Session *session = fort11_SessionFromHandle(hSession, PR_FALSE); PK11Slot *slot = fort11_SlotFromSessionHandle(hSession); FortezzaContext *context; FortezzaContext passedInCxt; PK11Object *keyObject; FortezzaKey *fortKey; if (session == NULL) { session = fort11_SessionFromHandle(hSession, PR_TRUE); fort11_TokenRemoved (slot, session); fort11_FreeSession(session); FORT11_RETURN (CKR_SESSION_HANDLE_INVALID); } if (ulOperationStateLen != sizeof(FortezzaContext)) { fort11_FreeSession(session); FORT11_RETURN (CKR_SAVED_STATE_INVALID); } PORT_Memcpy(&passedInCxt, pOperationState, sizeof(FortezzaContext)); if (passedInCxt.fortezzaSocket->slotID != slot->slotID) { fort11_FreeSession(session); FORT11_RETURN (CKR_SAVED_STATE_INVALID); } passedInCxt.session = NULL; passedInCxt.fortezzaKey = NULL; if (hEncryptionKey != 0) { keyObject = fort11_ObjectFromHandle(hEncryptionKey, session); if (keyObject == NULL) { fort11_FreeSession(session); FORT11_RETURN (CKR_KEY_HANDLE_INVALID); } fortKey = (FortezzaKey*)keyObject->objectInfo; fort11_FreeObject(keyObject); if (fortKey == NULL) { fort11_FreeSession(session); FORT11_RETURN (CKR_SAVED_STATE_INVALID); } if (fortKey->keyRegister == KeyNotLoaded) { if (LoadKeyIntoRegister (fortKey) == KeyNotLoaded) { fort11_FreeSession(session); FORT11_RETURN (CKR_DEVICE_ERROR); } } passedInCxt.fortezzaKey = fortKey; } if (hAuthenticationKey != 0) { fort11_FreeSession(session); FORT11_RETURN (CKR_DEVICE_ERROR); } passedInCxt.session = session; context = &session->fortezzaContext; fort11_FreeSession (session); PORT_Memcpy (context, &passedInCxt, sizeof(passedInCxt)); FORT11_RETURN (CKR_OK); } /* Dual-function cryptographic operations */ /* C_DigestEncryptUpdate continues a multiple-part digesting and encryption operation. */ PR_PUBLIC_API(CK_RV) C_DigestEncryptUpdate(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pPart, CK_ULONG ulPartLen, CK_BYTE_PTR pEncryptedPart, CK_ULONG_PTR pulEncryptedPartLen){ return CKR_FUNCTION_NOT_SUPPORTED; } /* C_DecryptDigestUpdate continues a multiple-part decryption and digesting operation. */ PR_PUBLIC_API(CK_RV) C_DecryptDigestUpdate(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pEncryptedPart, CK_ULONG ulEncryptedPartLen, CK_BYTE_PTR pPart, CK_ULONG_PTR pulPartLen){ return CKR_FUNCTION_NOT_SUPPORTED; } /* C_SignEncryptUpdate continues a multiple-part signing and encryption operation. */ PR_PUBLIC_API(CK_RV) C_SignEncryptUpdate(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pPart, CK_ULONG ulPartLen, CK_BYTE_PTR pEncryptedPart, CK_ULONG_PTR pulEncryptedPartLen){ return CKR_FUNCTION_NOT_SUPPORTED; } /* C_DecryptVerifyUpdate continues a multiple-part decryption and verify operation. */ PR_PUBLIC_API(CK_RV) C_DecryptVerifyUpdate(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pEncryptedData, CK_ULONG ulEncryptedDataLen, CK_BYTE_PTR pData, CK_ULONG_PTR pulDataLen){ return CKR_FUNCTION_NOT_SUPPORTED; } /* C_DigestKey continues a multi-part message-digesting operation, * by digesting the value of a secret key as part of the data already digested. */ PR_PUBLIC_API(CK_RV) C_DigestKey(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hKey) { return CKR_FUNCTION_NOT_SUPPORTED; } PR_PUBLIC_API(CK_RV) C_WaitForSlotEvent(CK_FLAGS flags, CK_SLOT_ID_PTR pSlot, CK_VOID_PTR pRserved) { return CKR_FUNCTION_FAILED; }