/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/*
 * Internal data structures and functions used by pkcs11.c
 */
#ifndef _PKCS11I_H_
#define _PKCS11I_H_ 1

#include "nssilock.h"
#include "seccomon.h"
#include "secoidt.h"
#include "lowkeyti.h" 
#include "pkcs11t.h"

#include "sftkdbt.h" 
#include "chacha20poly1305.h"
#include "hasht.h"

/* 
 * Configuration Defines 
 *
 * The following defines affect the space verse speed trade offs of
 * the PKCS #11 module. For the most part the current settings are optimized
 * for web servers, where we want faster speed and lower lock contention at
 * the expense of space.
 */

/* 
 * The attribute allocation strategy is static allocation:
 *   Attributes are pre-allocated as part of the session object and used from
 *   the object array.
 */
#define MAX_OBJS_ATTRS 45	/* number of attributes to preallocate in
				 * the object (must me the absolute max) */
#define ATTR_SPACE 50  		/* Maximum size of attribute data before extra
				 * data needs to be allocated. This is set to
				 * enough space to hold an SSL MASTER secret */

#define NSC_STRICT      PR_FALSE  /* forces the code to do strict template
				   * matching when doing C_FindObject on token
				   * objects. This will slow down search in
				   * NSS. */
/* default search block allocations and increments */
#define NSC_CERT_BLOCK_SIZE     50
#define NSC_SEARCH_BLOCK_SIZE   5 
#define NSC_SLOT_LIST_BLOCK_SIZE 10

#define NSC_FIPS_MODULE 1
#define NSC_NON_FIPS_MODULE 0

/* these are data base storage hashes, not cryptographic hashes.. The define
 * the effective size of the various object hash tables */
/* clients care more about memory usage than lookup performance on
 * cyrptographic objects. Clients also have less objects around to play with 
 *
 * we eventually should make this configurable at runtime! Especially now that
 * NSS is a shared library.
 */
#define SPACE_ATTRIBUTE_HASH_SIZE 32 
#define SPACE_SESSION_OBJECT_HASH_SIZE 32
#define SPACE_SESSION_HASH_SIZE 32
#define TIME_ATTRIBUTE_HASH_SIZE 32
#define TIME_SESSION_OBJECT_HASH_SIZE 1024
#define TIME_SESSION_HASH_SIZE 1024
#define MAX_OBJECT_LIST_SIZE 800  
				  /* how many objects to keep on the free list
				   * before we start freeing them */
#define MAX_KEY_LEN 256 	  /* maximum symmetric key length in bytes */

/*
 * LOG2_BUCKETS_PER_SESSION_LOCK must be a prime number.
 * With SESSION_HASH_SIZE=1024, LOG2 can be 9, 5, 1, or 0.
 * With SESSION_HASH_SIZE=4096, LOG2 can be 11, 9, 5, 1, or 0.
 *
 * HASH_SIZE   LOG2_BUCKETS_PER   BUCKETS_PER_LOCK  NUMBER_OF_BUCKETS
 * 1024        9                  512               2
 * 1024        5                  32                32
 * 1024        1                  2                 512
 * 1024        0                  1                 1024
 * 4096        11                 2048              2
 * 4096        9                  512               8
 * 4096        5                  32                128
 * 4096        1                  2                 2048
 * 4096        0                  1                 4096
 */
#define LOG2_BUCKETS_PER_SESSION_LOCK 1
#define BUCKETS_PER_SESSION_LOCK (1 << (LOG2_BUCKETS_PER_SESSION_LOCK))
/* NOSPREAD sessionID to hash table index macro has been slower. */

/* define typedefs, double as forward declarations as well */
typedef struct SFTKAttributeStr SFTKAttribute;
typedef struct SFTKObjectListStr SFTKObjectList;
typedef struct SFTKObjectFreeListStr SFTKObjectFreeList;
typedef struct SFTKObjectListElementStr SFTKObjectListElement;
typedef struct SFTKObjectStr SFTKObject;
typedef struct SFTKSessionObjectStr SFTKSessionObject;
typedef struct SFTKTokenObjectStr SFTKTokenObject;
typedef struct SFTKSessionStr SFTKSession;
typedef struct SFTKSlotStr SFTKSlot;
typedef struct SFTKSessionContextStr SFTKSessionContext;
typedef struct SFTKSearchResultsStr SFTKSearchResults;
typedef struct SFTKHashVerifyInfoStr SFTKHashVerifyInfo;
typedef struct SFTKHashSignInfoStr SFTKHashSignInfo;
typedef struct SFTKOAEPEncryptInfoStr SFTKOAEPEncryptInfo;
typedef struct SFTKOAEPDecryptInfoStr SFTKOAEPDecryptInfo;
typedef struct SFTKSSLMACInfoStr SFTKSSLMACInfo;
typedef struct SFTKChaCha20Poly1305InfoStr SFTKChaCha20Poly1305Info;
typedef struct SFTKItemTemplateStr SFTKItemTemplate;

/* define function pointer typdefs for pointer tables */
typedef void (*SFTKDestroy)(void *, PRBool);
typedef void (*SFTKBegin)(void *);
typedef SECStatus (*SFTKCipher)(void *,void *,unsigned int *,unsigned int,
					void *, unsigned int);
typedef SECStatus (*SFTKVerify)(void *,void *,unsigned int,void *,unsigned int);
typedef void (*SFTKHash)(void *,const void *,unsigned int);
typedef void (*SFTKEnd)(void *,void *,unsigned int *,unsigned int);
typedef void (*SFTKFree)(void *);

/* Value to tell if an attribute is modifiable or not.
 *    NEVER: attribute is only set on creation.
 *    ONCOPY: attribute is set on creation and can only be changed on copy.
 *    SENSITIVE: attribute can only be changed to TRUE.
 *    ALWAYS: attribute can always be changed.
 */
typedef enum {
	SFTK_NEVER = 0,
	SFTK_ONCOPY = 1,
	SFTK_SENSITIVE = 2,
	SFTK_ALWAYS = 3
} SFTKModifyType;

/*
 * Free Status Enum... tell us more information when we think we're
 * deleting an object.
 */
typedef enum {
	SFTK_DestroyFailure,
	SFTK_Destroyed,
	SFTK_Busy
} SFTKFreeStatus;

/*
 * attribute values of an object.
 */
struct SFTKAttributeStr {
    SFTKAttribute  	*next;
    SFTKAttribute  	*prev;
    PRBool		freeAttr;
    PRBool		freeData;
    /*must be called handle to make sftkqueue_find work */
    CK_ATTRIBUTE_TYPE	handle;
    CK_ATTRIBUTE 	attrib;
    unsigned char space[ATTR_SPACE];
};


/*
 * doubly link list of objects
 */
struct SFTKObjectListStr {
    SFTKObjectList *next;
    SFTKObjectList *prev;
    SFTKObject	   *parent;
};

struct SFTKObjectFreeListStr {
    SFTKObject	*head;
    PZLock	*lock;
    int		count;
};

/*
 * PKCS 11 crypto object structure
 */
struct SFTKObjectStr {
    SFTKObject *next;
    SFTKObject	*prev;
    CK_OBJECT_CLASS 	objclass;
    CK_OBJECT_HANDLE	handle;
    int 		refCount;
    PZLock 		*refLock;
    SFTKSlot	   	*slot;
    void 		*objectInfo;
    SFTKFree 		infoFree;
};

struct SFTKTokenObjectStr {
    SFTKObject  obj;
    SECItem	dbKey;
};

struct SFTKSessionObjectStr {
    SFTKObject	   obj;
    SFTKObjectList sessionList;
    PZLock		*attributeLock;
    SFTKSession   	*session;
    PRBool		wasDerived;
    int nextAttr;
    SFTKAttribute	attrList[MAX_OBJS_ATTRS];
    PRBool		optimizeSpace;
    unsigned int	hashSize;
    SFTKAttribute 	*head[1];
};

/*
 * struct to deal with a temparary list of objects
 */
struct SFTKObjectListElementStr {
    SFTKObjectListElement	*next;
    SFTKObject 			*object;
};

/*
 * Area to hold Search results
 */
struct SFTKSearchResultsStr {
    CK_OBJECT_HANDLE	*handles;
    int			size;
    int			index;
    int			array_size;
};


/* 
 * the universal crypto/hash/sign/verify context structure
 */
typedef enum {
    SFTK_ENCRYPT,
    SFTK_DECRYPT,
    SFTK_HASH,
    SFTK_SIGN,
    SFTK_SIGN_RECOVER,
    SFTK_VERIFY,
    SFTK_VERIFY_RECOVER
} SFTKContextType;

/** max block size of supported block ciphers */
#define SFTK_MAX_BLOCK_SIZE 16
/** currently SHA512 is the biggest hash length */
#define SFTK_MAX_MAC_LENGTH 64
#define SFTK_INVALID_MAC_SIZE 0xffffffff

/** Particular ongoing operation in session (sign/verify/digest/encrypt/...)
 *
 *  Understanding sign/verify context:
 *      multi=1 hashInfo=0   block (symmetric) cipher MACing
 *      multi=1 hashInfo=X   PKC S/V with prior hashing
 *      multi=0 hashInfo=0   PKC S/V one shot (w/o hashing)
 *      multi=0 hashInfo=X   *** shouldn't happen ***
 */
struct SFTKSessionContextStr {
    SFTKContextType	type;
    PRBool		multi; 		/* is multipart */
    PRBool		rsa; 		/* is rsa */
    PRBool		doPad; 		/* use PKCS padding for block ciphers */
    unsigned int	blockSize; 	/* blocksize for padding */
    unsigned int	padDataLength; 	/* length of the valid data in padbuf */
    /** latest incomplete block of data for block cipher */
    unsigned char	padBuf[SFTK_MAX_BLOCK_SIZE];
    /** result of MAC'ing of latest full block of data with block cipher */
    unsigned char	macBuf[SFTK_MAX_BLOCK_SIZE];
    CK_ULONG		macSize;	/* size of a general block cipher mac*/
    void		*cipherInfo;
    void		*hashInfo;
    unsigned int	cipherInfoLen;
    CK_MECHANISM_TYPE	currentMech;
    SFTKCipher		update;
    SFTKHash		hashUpdate;
    SFTKEnd		end;
    SFTKDestroy		destroy;
    SFTKDestroy		hashdestroy;
    SFTKVerify		verify;
    unsigned int	maxLen;
    SFTKObject		*key;
};

/*
 * Sessions (have objects)
 */
struct SFTKSessionStr {
    SFTKSession        *next;
    SFTKSession        *prev;
    CK_SESSION_HANDLE	handle;
    int			refCount;
    PZLock		*objectLock;
    int			objectIDCount;
    CK_SESSION_INFO	info;
    CK_NOTIFY		notify;
    CK_VOID_PTR		appData;
    SFTKSlot		*slot;
    SFTKSearchResults	*search;
    SFTKSessionContext	*enc_context;
    SFTKSessionContext	*hash_context;
    SFTKSessionContext	*sign_context;
    SFTKObjectList	*objects[1];
};

/*
 * slots (have sessions and objects)
 *
 * The array of sessionLock's protect the session hash table (head[])
 * as well as the reference count of session objects in that bucket
 * (head[]->refCount),  objectLock protects all elements of the slot's
 * object hash tables (sessObjHashTable[] and tokObjHashTable), and
 * sessionObjectHandleCount.
 * slotLock protects the remaining protected elements:
 * password, isLoggedIn, ssoLoggedIn, and sessionCount,
 * and pwCheckLock serializes the key database password checks in
 * NSC_SetPIN and NSC_Login.
 *
 * Each of the fields below has the following lifetime as commented
 * next to the fields:
 *   invariant  - This value is set when the slot is first created and
 * never changed until it is destroyed.
 *   per load   - This value is set when the slot is first created, or 
 * when the slot is used to open another directory. Between open and close
 * this field does not change.
 *   variable - This value changes through the normal process of slot operation.
 *      - reset. The value of this variable is cleared during an open/close 
 *   cycles.
 *      - preserved. The value of this variable is preserved over open/close
 *   cycles.
 */
struct SFTKSlotStr {
    CK_SLOT_ID		slotID;			/* invariant */
    PZLock		*slotLock;		/* invariant */
    PZLock		**sessionLock;		/* invariant */
    unsigned int	numSessionLocks;	/* invariant */
    unsigned long	sessionLockMask;	/* invariant */
    PZLock		*objectLock;		/* invariant */
    PRLock		*pwCheckLock;		/* invariant */
    PRBool		present;		/* variable -set */
    PRBool		hasTokens;		/* per load */
    PRBool		isLoggedIn;		/* variable - reset */
    PRBool		ssoLoggedIn;		/* variable - reset */
    PRBool		needLogin;		/* per load */
    PRBool		DB_loaded;		/* per load */
    PRBool		readOnly;		/* per load */
    PRBool		optimizeSpace;		/* invariant */
    SFTKDBHandle	*certDB;		/* per load */
    SFTKDBHandle	*keyDB;			/* per load */
    int			minimumPinLen;		/* per load */
    PRInt32		sessionIDCount;		/* atomically incremented */
                                        	/* (preserved) */
    int			sessionIDConflict; 	/* not protected by a lock */
                                            	/* (preserved) */
    int			sessionCount;           /* variable - reset */
    PRInt32             rwSessionCount;    	/* set by atomic operations */
                                          	/* (reset) */
    int			sessionObjectHandleCount;/* variable - perserved */
    CK_ULONG		index;			/* invariant */
    PLHashTable		*tokObjHashTable;	/* invariant */
    SFTKObject		**sessObjHashTable;	/* variable - reset */
    unsigned int	sessObjHashSize;	/* invariant */
    SFTKSession		**head;			/* variable -reset */
    unsigned int	sessHashSize;		/* invariant */
    char		tokDescription[33];	/* per load */
    char		updateTokDescription[33]; /* per load */
    char		slotDescription[65];	/* invariant */
};

/*
 * special joint operations Contexts
 */
struct SFTKHashVerifyInfoStr {
    SECOidTag   	hashOid;
    void		*params;
    NSSLOWKEYPublicKey	*key;
};

struct SFTKHashSignInfoStr {
    SECOidTag   	hashOid;
    void		*params;
    NSSLOWKEYPrivateKey	*key;
};

/**
 * Contexts for RSA-OAEP
 */
struct SFTKOAEPEncryptInfoStr {
    CK_RSA_PKCS_OAEP_PARAMS *params;
    NSSLOWKEYPublicKey *key;
};

struct SFTKOAEPDecryptInfoStr {
    CK_RSA_PKCS_OAEP_PARAMS *params;
    NSSLOWKEYPrivateKey *key;
};

/* context for the Final SSLMAC message */
struct SFTKSSLMACInfoStr {
    void 		*hashContext;
    SFTKBegin		begin;
    SFTKHash		update;
    SFTKEnd		end;
    CK_ULONG		macSize;
    int			padSize;
    unsigned char	key[MAX_KEY_LEN];
    unsigned int	keySize;
};

/* SFTKChaCha20Poly1305Info saves the key, tag length, nonce,
 * and additional data for a ChaCha20+Poly1305 AEAD operation. */
struct SFTKChaCha20Poly1305InfoStr {
    ChaCha20Poly1305Context freeblCtx;
    unsigned char nonce[12];
    unsigned char ad[16];
    unsigned char *adOverflow;
    unsigned int adLen;
};

/*
 * Template based on SECItems, suitable for passing as arrays
 */
struct SFTKItemTemplateStr {
    CK_ATTRIBUTE_TYPE	type;
    SECItem		*item;
};

/* macro for setting SFTKTemplates. */
#define SFTK_SET_ITEM_TEMPLATE(templ, count, itemPtr, attr) \
   templ[count].type = attr; \
   templ[count].item = itemPtr

#define SFTK_MAX_ITEM_TEMPLATE 10

/*
 * session handle modifiers
 */
#define SFTK_SESSION_SLOT_MASK	0xff000000L

/*
 * object handle modifiers
 */
#define SFTK_TOKEN_MASK		0x80000000L
#define SFTK_TOKEN_MAGIC	0x80000000L
#define SFTK_TOKEN_TYPE_MASK	0x70000000L
/* keydb (high bit == 0) */
#define SFTK_TOKEN_TYPE_PRIV	0x10000000L
#define SFTK_TOKEN_TYPE_PUB	0x20000000L
#define SFTK_TOKEN_TYPE_KEY	0x30000000L
/* certdb (high bit == 1) */
#define SFTK_TOKEN_TYPE_TRUST	0x40000000L
#define SFTK_TOKEN_TYPE_CRL	0x50000000L
#define SFTK_TOKEN_TYPE_SMIME	0x60000000L
#define SFTK_TOKEN_TYPE_CERT	0x70000000L

#define SFTK_TOKEN_KRL_HANDLE	(SFTK_TOKEN_MAGIC|SFTK_TOKEN_TYPE_CRL|1)
/* how big (in bytes) a password/pin we can deal with */
#define SFTK_MAX_PIN	255
/* minimum password/pin length (in Unicode characters) in FIPS mode */
#define FIPS_MIN_PIN	7

/* slot ID's */
#define NETSCAPE_SLOT_ID 1
#define PRIVATE_KEY_SLOT_ID 2
#define FIPS_SLOT_ID 3

/* slot helper macros */
#define sftk_SlotFromSession(sp) ((sp)->slot)
#define sftk_isToken(id) (((id) & SFTK_TOKEN_MASK) == SFTK_TOKEN_MAGIC)

/* the session hash multiplier (see bug 201081) */
#define SHMULTIPLIER 1791398085

/* queueing helper macros */
#define sftk_hash(value,size) \
	((PRUint32)((value) * SHMULTIPLIER) & (size-1))
#define sftkqueue_add(element,id,head,hash_size) \
	{ int tmp = sftk_hash(id,hash_size); \
	(element)->next = (head)[tmp]; \
	(element)->prev = NULL; \
	if ((head)[tmp]) (head)[tmp]->prev = (element); \
	(head)[tmp] = (element); }
#define sftkqueue_find(element,id,head,hash_size) \
	for( (element) = (head)[sftk_hash(id,hash_size)]; (element) != NULL; \
					 (element) = (element)->next) { \
	    if ((element)->handle == (id)) { break; } }
#define sftkqueue_is_queued(element,id,head,hash_size) \
	( ((element)->next) || ((element)->prev) || \
	 ((head)[sftk_hash(id,hash_size)] == (element)) )
#define sftkqueue_delete(element,id,head,hash_size) \
	if ((element)->next) (element)->next->prev = (element)->prev; \
	if ((element)->prev) (element)->prev->next = (element)->next; \
	   else (head)[sftk_hash(id,hash_size)] = ((element)->next); \
	(element)->next = NULL; \
	(element)->prev = NULL; \

#define sftkqueue_init_element(element) \
    (element)->prev = NULL;

#define sftkqueue_add2(element, id, index, head) \
    {                                            \
	(element)->next = (head)[index];         \
	if ((head)[index])                       \
	    (head)[index]->prev = (element);     \
	(head)[index] = (element);               \
    }

#define sftkqueue_find2(element, id, index, head) \
    for ( (element) = (head)[index];              \
          (element) != NULL;                      \
          (element) = (element)->next) {          \
	if ((element)->handle == (id)) { break; } \
    }

#define sftkqueue_delete2(element, id, index, head) \
	if ((element)->next) (element)->next->prev = (element)->prev; \
	if ((element)->prev) (element)->prev->next = (element)->next; \
	   else (head)[index] = ((element)->next);

#define sftkqueue_clear_deleted_element(element) \
	(element)->next = NULL; \
	(element)->prev = NULL; \


/* sessionID (handle) is used to determine session lock bucket */
#ifdef NOSPREAD
/* NOSPREAD:	(ID>>L2LPB) & (perbucket-1) */
#define SFTK_SESSION_LOCK(slot,handle) \
    ((slot)->sessionLock[((handle) >> LOG2_BUCKETS_PER_SESSION_LOCK) \
        & (slot)->sessionLockMask])
#else
/* SPREAD:	ID & (perbucket-1) */
#define SFTK_SESSION_LOCK(slot,handle) \
    ((slot)->sessionLock[(handle) & (slot)->sessionLockMask])
#endif

/* expand an attribute & secitem structures out */
#define sftk_attr_expand(ap) (ap)->type,(ap)->pValue,(ap)->ulValueLen
#define sftk_item_expand(ip) (ip)->data,(ip)->len

typedef struct sftk_token_parametersStr {
    CK_SLOT_ID slotID;
    char *configdir;
    char *certPrefix;
    char *keyPrefix;
    char *updatedir;
    char *updCertPrefix;
    char *updKeyPrefix;
    char *updateID;
    char *tokdes;
    char *slotdes;
    char *updtokdes;
    int minPW; 
    PRBool readOnly;
    PRBool noCertDB;
    PRBool noKeyDB;
    PRBool forceOpen;
    PRBool pwRequired;
    PRBool optimizeSpace;
} sftk_token_parameters;

typedef struct sftk_parametersStr {
    char *configdir;
    char *updatedir;
    char *updateID;
    char *secmodName;
    char *man;
    char *libdes; 
    PRBool readOnly;
    PRBool noModDB;
    PRBool noCertDB;
    PRBool forceOpen;
    PRBool pwRequired;
    PRBool optimizeSpace;
    sftk_token_parameters *tokens;
    int token_count;
} sftk_parameters;


/* path stuff (was machine dependent) used by dbinit.c and pk11db.c */
#define CERT_DB_FMT "%scert%s.db"
#define KEY_DB_FMT "%skey%s.db"

SEC_BEGIN_PROTOS

/* shared functions between pkcs11.c and fipstokn.c */
extern PRBool nsf_init;
extern CK_RV nsc_CommonInitialize(CK_VOID_PTR pReserved, PRBool isFIPS);
extern CK_RV nsc_CommonFinalize(CK_VOID_PTR pReserved, PRBool isFIPS);
extern PRBool sftk_ForkReset(CK_VOID_PTR pReserved, CK_RV* crv);
extern CK_RV nsc_CommonGetSlotList(CK_BBOOL tokPresent, 
	CK_SLOT_ID_PTR pSlotList, CK_ULONG_PTR pulCount, int moduleIndex);

/* slot initialization, reinit, shutdown and destruction */
extern CK_RV SFTK_SlotInit(char *configdir, char *updatedir, char *updateID,
			sftk_token_parameters *params, int moduleIndex);
extern CK_RV SFTK_SlotReInit(SFTKSlot *slot, char *configdir,
			char *updatedir, char *updateID,
			sftk_token_parameters *params, int moduleIndex);
extern CK_RV SFTK_DestroySlotData(SFTKSlot *slot);
extern CK_RV SFTK_ShutdownSlot(SFTKSlot *slot);
extern CK_RV sftk_CloseAllSessions(SFTKSlot *slot, PRBool logout);


/* internal utility functions used by pkcs11.c */
extern SFTKAttribute *sftk_FindAttribute(SFTKObject *object,
					 CK_ATTRIBUTE_TYPE type);
extern void sftk_FreeAttribute(SFTKAttribute *attribute);
extern CK_RV sftk_AddAttributeType(SFTKObject *object, CK_ATTRIBUTE_TYPE type,
				   const void *valPtr, CK_ULONG length);
extern CK_RV sftk_Attribute2SecItem(PLArenaPool *arena, SECItem *item,
				    SFTKObject *object, CK_ATTRIBUTE_TYPE type);
extern CK_RV sftk_MultipleAttribute2SecItem(PLArenaPool *arena, 
		SFTKObject *object, SFTKItemTemplate *templ, int count);
extern unsigned int sftk_GetLengthInBits(unsigned char *buf,
							 unsigned int bufLen);
extern CK_RV sftk_ConstrainAttribute(SFTKObject *object, 
	CK_ATTRIBUTE_TYPE type, int minLength, int maxLength, int minMultiple);
extern PRBool sftk_hasAttribute(SFTKObject *object, CK_ATTRIBUTE_TYPE type);
extern PRBool sftk_isTrue(SFTKObject *object, CK_ATTRIBUTE_TYPE type);
extern void sftk_DeleteAttributeType(SFTKObject *object,
				     CK_ATTRIBUTE_TYPE type);
extern CK_RV sftk_Attribute2SecItem(PLArenaPool *arena, SECItem *item,
				    SFTKObject *object, CK_ATTRIBUTE_TYPE type);
extern CK_RV sftk_Attribute2SSecItem(PLArenaPool *arena, SECItem *item,
				     SFTKObject *object,
				     CK_ATTRIBUTE_TYPE type);
extern SFTKModifyType sftk_modifyType(CK_ATTRIBUTE_TYPE type,
				      CK_OBJECT_CLASS inClass);
extern PRBool sftk_isSensitive(CK_ATTRIBUTE_TYPE type, CK_OBJECT_CLASS inClass);
extern char *sftk_getString(SFTKObject *object, CK_ATTRIBUTE_TYPE type);
extern void sftk_nullAttribute(SFTKObject *object,CK_ATTRIBUTE_TYPE type);
extern CK_RV sftk_GetULongAttribute(SFTKObject *object, CK_ATTRIBUTE_TYPE type,
                                                         CK_ULONG *longData);
extern CK_RV sftk_forceAttribute(SFTKObject *object, CK_ATTRIBUTE_TYPE type,
				 const void *value, unsigned int len);
extern CK_RV sftk_defaultAttribute(SFTKObject *object, CK_ATTRIBUTE_TYPE type,
				   const void *value, unsigned int len);
extern unsigned int sftk_MapTrust(CK_TRUST trust, PRBool clientAuth);

extern SFTKObject *sftk_NewObject(SFTKSlot *slot);
extern CK_RV sftk_CopyObject(SFTKObject *destObject, SFTKObject *srcObject);
extern SFTKFreeStatus sftk_FreeObject(SFTKObject *object);
extern CK_RV sftk_DeleteObject(SFTKSession *session, SFTKObject *object);
extern void sftk_ReferenceObject(SFTKObject *object);
extern SFTKObject *sftk_ObjectFromHandle(CK_OBJECT_HANDLE handle,
					 SFTKSession *session);
extern void sftk_AddSlotObject(SFTKSlot *slot, SFTKObject *object);
extern void sftk_AddObject(SFTKSession *session, SFTKObject *object);
/* clear out all the existing object ID to database key mappings.
 * used to reinit a token */
extern CK_RV SFTK_ClearTokenKeyHashTable(SFTKSlot *slot);

extern CK_RV sftk_searchObjectList(SFTKSearchResults *search,
				   SFTKObject **head, unsigned int size,
				   PZLock *lock, CK_ATTRIBUTE_PTR inTemplate,
				   int count, PRBool isLoggedIn);
extern SFTKObjectListElement *sftk_FreeObjectListElement(
					     SFTKObjectListElement *objectList);
extern void sftk_FreeObjectList(SFTKObjectListElement *objectList);
extern void sftk_FreeSearch(SFTKSearchResults *search);
extern CK_RV sftk_handleObject(SFTKObject *object, SFTKSession *session);

extern SFTKSlot *sftk_SlotFromID(CK_SLOT_ID slotID, PRBool all);
extern SFTKSlot *sftk_SlotFromSessionHandle(CK_SESSION_HANDLE handle);
extern SFTKSession *sftk_SessionFromHandle(CK_SESSION_HANDLE handle);
extern void sftk_FreeSession(SFTKSession *session);
extern SFTKSession *sftk_NewSession(CK_SLOT_ID slotID, CK_NOTIFY notify,
				    CK_VOID_PTR pApplication, CK_FLAGS flags);
extern void sftk_update_state(SFTKSlot *slot,SFTKSession *session);
extern void sftk_update_all_states(SFTKSlot *slot);
extern void sftk_FreeContext(SFTKSessionContext *context);
extern void sftk_InitFreeLists(void);
extern void sftk_CleanupFreeLists(void);

extern NSSLOWKEYPublicKey *sftk_GetPubKey(SFTKObject *object,
					  CK_KEY_TYPE key_type, CK_RV *crvp);
extern NSSLOWKEYPrivateKey *sftk_GetPrivKey(SFTKObject *object,
					    CK_KEY_TYPE key_type, CK_RV *crvp);
extern void sftk_FormatDESKey(unsigned char *key, int length);
extern PRBool sftk_CheckDESKey(unsigned char *key);
extern PRBool sftk_IsWeakKey(unsigned char *key,CK_KEY_TYPE key_type);

/* mechanism allows this operation */
extern CK_RV sftk_MechAllowsOperation(CK_MECHANISM_TYPE type, CK_ATTRIBUTE_TYPE op);

/* helper function which calls nsslowkey_FindKeyByPublicKey after safely
 * acquiring a reference to the keydb from the slot */
NSSLOWKEYPrivateKey *sftk_FindKeyByPublicKey(SFTKSlot *slot, SECItem *dbKey);

/*
 * parameter parsing functions
 */
CK_RV sftk_parseParameters(char *param, sftk_parameters *parsed, PRBool isFIPS);
void sftk_freeParams(sftk_parameters *params);


/*
 * narrow objects
 */
SFTKSessionObject * sftk_narrowToSessionObject(SFTKObject *);
SFTKTokenObject * sftk_narrowToTokenObject(SFTKObject *);

/*
 * token object utilities
 */
void sftk_addHandle(SFTKSearchResults *search, CK_OBJECT_HANDLE handle);
PRBool sftk_poisonHandle(SFTKSlot *slot, SECItem *dbkey, 
						CK_OBJECT_HANDLE handle);
SFTKObject * sftk_NewTokenObject(SFTKSlot *slot, SECItem *dbKey, 
						CK_OBJECT_HANDLE handle);
SFTKTokenObject *sftk_convertSessionToToken(SFTKObject *so);


/* J-PAKE (jpakesftk.c) */
extern
CK_RV jpake_Round1(HASH_HashType hashType,
                   CK_NSS_JPAKERound1Params * params,
                   SFTKObject * key);
extern
CK_RV jpake_Round2(HASH_HashType hashType,
                   CK_NSS_JPAKERound2Params * params,
                   SFTKObject * sourceKey, SFTKObject * key);
extern
CK_RV jpake_Final(HASH_HashType hashType,
                  const CK_NSS_JPAKEFinalParams * params,
                  SFTKObject * sourceKey, SFTKObject * key);

/* Constant time MAC functions (hmacct.c) */

struct sftk_MACConstantTimeCtxStr {
    const SECHashObject *hash;
    unsigned char mac[64];
    unsigned char secret[64];
    unsigned int headerLength;
    unsigned int secretLength;
    unsigned int totalLength;
    unsigned char header[75];
};
typedef struct sftk_MACConstantTimeCtxStr sftk_MACConstantTimeCtx;
sftk_MACConstantTimeCtx* sftk_HMACConstantTime_New(
	CK_MECHANISM_PTR mech, SFTKObject *key);
sftk_MACConstantTimeCtx* sftk_SSLv3MACConstantTime_New(
	CK_MECHANISM_PTR mech, SFTKObject *key);
void sftk_HMACConstantTime_Update(void *pctx, const void *data, unsigned int len);
void sftk_SSLv3MACConstantTime_Update(void *pctx, const void *data, unsigned int len);
void sftk_MACConstantTime_EndHash(
	void *pctx, void *out, unsigned int *outLength, unsigned int maxLength);
void sftk_MACConstantTime_DestroyContext(void *pctx, PRBool);

/****************************************
 * implement TLS Pseudo Random Function (PRF)
 */

extern CK_RV
sftk_TLSPRFInit(SFTKSessionContext *context, 
		  SFTKObject *        key, 
		  CK_KEY_TYPE         key_type,
		  HASH_HashType       hash_alg,
		  unsigned int        out_len);

SEC_END_PROTOS

#endif /* _PKCS11I_H_ */
