diff options
Diffstat (limited to 'security/nss/lib/fortcrypt/fortpk11.c')
-rw-r--r-- | security/nss/lib/fortcrypt/fortpk11.c | 4553 |
1 files changed, 4553 insertions, 0 deletions
diff --git a/security/nss/lib/fortcrypt/fortpk11.c b/security/nss/lib/fortcrypt/fortpk11.c new file mode 100644 index 000000000..e28fd7909 --- /dev/null +++ b/security/nss/lib/fortcrypt/fortpk11.c @@ -0,0 +1,4553 @@ +/* + * 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 <ctype.h> +#include <stdio.h> +#endif + +/* sigh */ +#ifndef EOF +/* stdio was not included */ +extern int sprintf(char *out, char *fmt, ...); +#endif + +#ifdef XP_MAC +#ifndef __POWERPC__ +#include <A4Stuff.h> +#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 <Quickdraw.h> + +/* +** 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 = NULL, *oldObject; + int i; + + for (i=0; i<HASH_SIZE; i++) { + currObject = slot->tokObjects[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; i<ulLen; i++) { + ciPin[i] = pPin[i]; + } + ciPin[ulLen] = '\0'; +} + + +/* + * return true if object has attribute + */ +static PRBool +fort11_hasAttribute(PK11Object *object,CK_ATTRIBUTE_TYPE type) { + PK11Attribute *attribute; + + FMUTEX_Lock(object->attributeLock); + 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", (int) slotID); +#else + sprintf (tmp, "FORTEZZA Slot #%d", (int) 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; +} + |