mirror of
https://github.com/rn10950/RetroZilla.git
synced 2024-11-10 18:00:15 +01:00
44b7f056d9
bug1001332, 56b691c003ad, bug1086145, bug1054069, bug1155922, bug991783, bug1125025, bug1162521, bug1162644, bug1132941, bug1164364, bug1166205, bug1166163, bug1166515, bug1138554, bug1167046, bug1167043, bug1169451, bug1172128, bug1170322, bug102794, bug1128184, bug557830, bug1174648, bug1180244, bug1177784, bug1173413, bug1169174, bug1084669, bug951455, bug1183395, bug1177430, bug1183827, bug1160139, bug1154106, bug1142209, bug1185033, bug1193467, bug1182667(with sha512 changes backed out, which breaks VC6 compilation), bug1158489, bug337796
2673 lines
80 KiB
C
2673 lines
80 KiB
C
/* 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/. */
|
|
/*
|
|
* This file implements the Symkey wrapper and the PKCS context
|
|
* Interfaces.
|
|
*/
|
|
|
|
#include "seccomon.h"
|
|
#include "secmod.h"
|
|
#include "nssilock.h"
|
|
#include "secmodi.h"
|
|
#include "secmodti.h"
|
|
#include "pkcs11.h"
|
|
#include "pk11func.h"
|
|
#include "secitem.h"
|
|
#include "secoid.h"
|
|
#include "secerr.h"
|
|
#include "hasht.h"
|
|
|
|
static void
|
|
pk11_EnterKeyMonitor(PK11SymKey *symKey) {
|
|
if (!symKey->sessionOwner || !(symKey->slot->isThreadSafe))
|
|
PK11_EnterSlotMonitor(symKey->slot);
|
|
}
|
|
|
|
static void
|
|
pk11_ExitKeyMonitor(PK11SymKey *symKey) {
|
|
if (!symKey->sessionOwner || !(symKey->slot->isThreadSafe))
|
|
PK11_ExitSlotMonitor(symKey->slot);
|
|
}
|
|
|
|
/*
|
|
* pk11_getKeyFromList returns a symKey that has a session (if needSession
|
|
* was specified), or explicitly does not have a session (if needSession
|
|
* was not specified).
|
|
*/
|
|
static PK11SymKey *
|
|
pk11_getKeyFromList(PK11SlotInfo *slot, PRBool needSession) {
|
|
PK11SymKey *symKey = NULL;
|
|
|
|
PZ_Lock(slot->freeListLock);
|
|
/* own session list are symkeys with sessions that the symkey owns.
|
|
* 'most' symkeys will own their own session. */
|
|
if (needSession) {
|
|
if (slot->freeSymKeysWithSessionHead) {
|
|
symKey = slot->freeSymKeysWithSessionHead;
|
|
slot->freeSymKeysWithSessionHead = symKey->next;
|
|
slot->keyCount--;
|
|
}
|
|
}
|
|
/* if we don't need a symkey with its own session, or we couldn't find
|
|
* one on the owner list, get one from the non-owner free list. */
|
|
if (!symKey) {
|
|
if (slot->freeSymKeysHead) {
|
|
symKey = slot->freeSymKeysHead;
|
|
slot->freeSymKeysHead = symKey->next;
|
|
slot->keyCount--;
|
|
}
|
|
}
|
|
PZ_Unlock(slot->freeListLock);
|
|
if (symKey) {
|
|
symKey->next = NULL;
|
|
if (!needSession) {
|
|
return symKey;
|
|
}
|
|
/* if we are getting an owner key, make sure we have a valid session.
|
|
* session could be invalid if the token has been removed or because
|
|
* we got it from the non-owner free list */
|
|
if ((symKey->series != slot->series) ||
|
|
(symKey->session == CK_INVALID_SESSION)) {
|
|
symKey->session = pk11_GetNewSession(slot, &symKey->sessionOwner);
|
|
}
|
|
PORT_Assert(symKey->session != CK_INVALID_SESSION);
|
|
if (symKey->session != CK_INVALID_SESSION)
|
|
return symKey;
|
|
PK11_FreeSymKey(symKey);
|
|
/* if we are here, we need a session, but couldn't get one, it's
|
|
* unlikely we pk11_GetNewSession will succeed if we call it a second
|
|
* time. */
|
|
return NULL;
|
|
}
|
|
|
|
symKey = PORT_New(PK11SymKey);
|
|
if (symKey == NULL) {
|
|
return NULL;
|
|
}
|
|
|
|
symKey->next = NULL;
|
|
if (needSession) {
|
|
symKey->session = pk11_GetNewSession(slot,&symKey->sessionOwner);
|
|
PORT_Assert(symKey->session != CK_INVALID_SESSION);
|
|
if (symKey->session == CK_INVALID_SESSION) {
|
|
PK11_FreeSymKey(symKey);
|
|
symKey = NULL;
|
|
}
|
|
} else {
|
|
symKey->session = CK_INVALID_SESSION;
|
|
}
|
|
return symKey;
|
|
}
|
|
|
|
/* Caller MUST hold slot->freeListLock (or ref count == 0?) !! */
|
|
void
|
|
PK11_CleanKeyList(PK11SlotInfo *slot)
|
|
{
|
|
PK11SymKey *symKey = NULL;
|
|
|
|
while (slot->freeSymKeysWithSessionHead) {
|
|
symKey = slot->freeSymKeysWithSessionHead;
|
|
slot->freeSymKeysWithSessionHead = symKey->next;
|
|
pk11_CloseSession(slot, symKey->session, symKey->sessionOwner);
|
|
PORT_Free(symKey);
|
|
}
|
|
while (slot->freeSymKeysHead) {
|
|
symKey = slot->freeSymKeysHead;
|
|
slot->freeSymKeysHead = symKey->next;
|
|
pk11_CloseSession(slot, symKey->session, symKey->sessionOwner);
|
|
PORT_Free(symKey);
|
|
}
|
|
return;
|
|
}
|
|
|
|
/*
|
|
* create a symetric key:
|
|
* Slot is the slot to create the key in.
|
|
* type is the mechanism type
|
|
* owner is does this symKey structure own it's object handle (rare
|
|
* that this is false).
|
|
* needSession means the returned symKey will return with a valid session
|
|
* allocated already.
|
|
*/
|
|
static PK11SymKey *
|
|
pk11_CreateSymKey(PK11SlotInfo *slot, CK_MECHANISM_TYPE type,
|
|
PRBool owner, PRBool needSession, void *wincx)
|
|
{
|
|
|
|
PK11SymKey *symKey = pk11_getKeyFromList(slot, needSession);
|
|
|
|
if (symKey == NULL) {
|
|
return NULL;
|
|
}
|
|
/* if needSession was specified, make sure we have a valid session.
|
|
* callers which specify needSession as false should do their own
|
|
* check of the session before returning the symKey */
|
|
if (needSession && symKey->session == CK_INVALID_SESSION) {
|
|
PK11_FreeSymKey(symKey);
|
|
PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
|
|
return NULL;
|
|
}
|
|
|
|
symKey->type = type;
|
|
symKey->data.type = siBuffer;
|
|
symKey->data.data = NULL;
|
|
symKey->data.len = 0;
|
|
symKey->owner = owner;
|
|
symKey->objectID = CK_INVALID_HANDLE;
|
|
symKey->slot = slot;
|
|
symKey->series = slot->series;
|
|
symKey->cx = wincx;
|
|
symKey->size = 0;
|
|
symKey->refCount = 1;
|
|
symKey->origin = PK11_OriginNULL;
|
|
symKey->parent = NULL;
|
|
symKey->freeFunc = NULL;
|
|
symKey->userData = NULL;
|
|
PK11_ReferenceSlot(slot);
|
|
return symKey;
|
|
}
|
|
|
|
/*
|
|
* destroy a symetric key
|
|
*/
|
|
void
|
|
PK11_FreeSymKey(PK11SymKey *symKey)
|
|
{
|
|
PK11SlotInfo *slot;
|
|
PRBool freeit = PR_TRUE;
|
|
|
|
if (PR_ATOMIC_DECREMENT(&symKey->refCount) == 0) {
|
|
PK11SymKey *parent = symKey->parent;
|
|
|
|
symKey->parent = NULL;
|
|
if ((symKey->owner) && symKey->objectID != CK_INVALID_HANDLE) {
|
|
pk11_EnterKeyMonitor(symKey);
|
|
(void) PK11_GETTAB(symKey->slot)->
|
|
C_DestroyObject(symKey->session, symKey->objectID);
|
|
pk11_ExitKeyMonitor(symKey);
|
|
}
|
|
if (symKey->data.data) {
|
|
PORT_Memset(symKey->data.data, 0, symKey->data.len);
|
|
PORT_Free(symKey->data.data);
|
|
}
|
|
/* free any existing data */
|
|
if (symKey->userData && symKey->freeFunc) {
|
|
(*symKey->freeFunc)(symKey->userData);
|
|
}
|
|
slot = symKey->slot;
|
|
PZ_Lock(slot->freeListLock);
|
|
if (slot->keyCount < slot->maxKeyCount) {
|
|
/*
|
|
* freeSymkeysWithSessionHead contain a list of reusable
|
|
* SymKey structures with valid sessions.
|
|
* sessionOwner must be true.
|
|
* session must be valid.
|
|
* freeSymKeysHead contain a list of SymKey structures without
|
|
* valid session.
|
|
* session must be CK_INVALID_SESSION.
|
|
* though sessionOwner is false, callers should not depend on
|
|
* this fact.
|
|
*/
|
|
if (symKey->sessionOwner) {
|
|
PORT_Assert (symKey->session != CK_INVALID_SESSION);
|
|
symKey->next = slot->freeSymKeysWithSessionHead;
|
|
slot->freeSymKeysWithSessionHead = symKey;
|
|
} else {
|
|
symKey->session = CK_INVALID_SESSION;
|
|
symKey->next = slot->freeSymKeysHead;
|
|
slot->freeSymKeysHead = symKey;
|
|
}
|
|
slot->keyCount++;
|
|
symKey->slot = NULL;
|
|
freeit = PR_FALSE;
|
|
}
|
|
PZ_Unlock(slot->freeListLock);
|
|
if (freeit) {
|
|
pk11_CloseSession(symKey->slot, symKey->session,
|
|
symKey->sessionOwner);
|
|
PORT_Free(symKey);
|
|
}
|
|
PK11_FreeSlot(slot);
|
|
|
|
if (parent) {
|
|
PK11_FreeSymKey(parent);
|
|
}
|
|
}
|
|
}
|
|
|
|
PK11SymKey *
|
|
PK11_ReferenceSymKey(PK11SymKey *symKey)
|
|
{
|
|
PR_ATOMIC_INCREMENT(&symKey->refCount);
|
|
return symKey;
|
|
}
|
|
|
|
/*
|
|
* Accessors
|
|
*/
|
|
CK_MECHANISM_TYPE
|
|
PK11_GetMechanism(PK11SymKey *symKey)
|
|
{
|
|
return symKey->type;
|
|
}
|
|
|
|
/*
|
|
* return the slot associated with a symetric key
|
|
*/
|
|
PK11SlotInfo *
|
|
PK11_GetSlotFromKey(PK11SymKey *symKey)
|
|
{
|
|
return PK11_ReferenceSlot(symKey->slot);
|
|
}
|
|
|
|
CK_KEY_TYPE PK11_GetSymKeyType(PK11SymKey *symKey)
|
|
{
|
|
return PK11_GetKeyType(symKey->type,symKey->size);
|
|
}
|
|
|
|
PK11SymKey *
|
|
PK11_GetNextSymKey(PK11SymKey *symKey)
|
|
{
|
|
return symKey ? symKey->next : NULL;
|
|
}
|
|
|
|
char *
|
|
PK11_GetSymKeyNickname(PK11SymKey *symKey)
|
|
{
|
|
return PK11_GetObjectNickname(symKey->slot,symKey->objectID);
|
|
}
|
|
|
|
SECStatus
|
|
PK11_SetSymKeyNickname(PK11SymKey *symKey, const char *nickname)
|
|
{
|
|
return PK11_SetObjectNickname(symKey->slot,symKey->objectID,nickname);
|
|
}
|
|
|
|
void *
|
|
PK11_GetSymKeyUserData(PK11SymKey *symKey)
|
|
{
|
|
return symKey->userData;
|
|
}
|
|
|
|
void
|
|
PK11_SetSymKeyUserData(PK11SymKey *symKey, void *userData,
|
|
PK11FreeDataFunc freeFunc)
|
|
{
|
|
/* free any existing data */
|
|
if (symKey->userData && symKey->freeFunc) {
|
|
(*symKey->freeFunc)(symKey->userData);
|
|
}
|
|
symKey->userData = userData;
|
|
symKey->freeFunc = freeFunc;
|
|
return;
|
|
}
|
|
|
|
/*
|
|
* turn key handle into an appropriate key object
|
|
*/
|
|
PK11SymKey *
|
|
PK11_SymKeyFromHandle(PK11SlotInfo *slot, PK11SymKey *parent, PK11Origin origin,
|
|
CK_MECHANISM_TYPE type, CK_OBJECT_HANDLE keyID, PRBool owner, void *wincx)
|
|
{
|
|
PK11SymKey *symKey;
|
|
PRBool needSession = !(owner && parent);
|
|
|
|
if (keyID == CK_INVALID_HANDLE) {
|
|
return NULL;
|
|
}
|
|
|
|
symKey = pk11_CreateSymKey(slot, type, owner, needSession, wincx);
|
|
if (symKey == NULL) {
|
|
return NULL;
|
|
}
|
|
|
|
symKey->objectID = keyID;
|
|
symKey->origin = origin;
|
|
|
|
/* adopt the parent's session */
|
|
/* This is only used by SSL. What we really want here is a session
|
|
* structure with a ref count so the session goes away only after all the
|
|
* keys do. */
|
|
if (!needSession) {
|
|
symKey->sessionOwner = PR_FALSE;
|
|
symKey->session = parent->session;
|
|
symKey->parent = PK11_ReferenceSymKey(parent);
|
|
/* This is the only case where pk11_CreateSymKey does not explicitly
|
|
* check symKey->session. We need to assert here to make sure.
|
|
* the session isn't invalid. */
|
|
PORT_Assert(parent->session != CK_INVALID_SESSION);
|
|
if (parent->session == CK_INVALID_SESSION) {
|
|
PK11_FreeSymKey(symKey);
|
|
PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
return symKey;
|
|
}
|
|
|
|
/*
|
|
* turn key handle into an appropriate key object
|
|
*/
|
|
PK11SymKey *
|
|
PK11_GetWrapKey(PK11SlotInfo *slot, int wrap, CK_MECHANISM_TYPE type,
|
|
int series, void *wincx)
|
|
{
|
|
PK11SymKey *symKey = NULL;
|
|
|
|
if (slot->series != series) return NULL;
|
|
if (slot->refKeys[wrap] == CK_INVALID_HANDLE) return NULL;
|
|
if (type == CKM_INVALID_MECHANISM) type = slot->wrapMechanism;
|
|
|
|
symKey = PK11_SymKeyFromHandle(slot, NULL, PK11_OriginDerive,
|
|
slot->wrapMechanism, slot->refKeys[wrap], PR_FALSE, wincx);
|
|
return symKey;
|
|
}
|
|
|
|
/*
|
|
* This function is not thread-safe because it sets wrapKey->sessionOwner
|
|
* without using a lock or atomic routine. It can only be called when
|
|
* only one thread has a reference to wrapKey.
|
|
*/
|
|
void
|
|
PK11_SetWrapKey(PK11SlotInfo *slot, int wrap, PK11SymKey *wrapKey)
|
|
{
|
|
/* save the handle and mechanism for the wrapping key */
|
|
/* mark the key and session as not owned by us to they don't get freed
|
|
* when the key goes way... that lets us reuse the key later */
|
|
slot->refKeys[wrap] = wrapKey->objectID;
|
|
wrapKey->owner = PR_FALSE;
|
|
wrapKey->sessionOwner = PR_FALSE;
|
|
slot->wrapMechanism = wrapKey->type;
|
|
}
|
|
|
|
|
|
/*
|
|
* figure out if a key is still valid or if it is stale.
|
|
*/
|
|
PRBool
|
|
PK11_VerifyKeyOK(PK11SymKey *key) {
|
|
if (!PK11_IsPresent(key->slot)) {
|
|
return PR_FALSE;
|
|
}
|
|
return (PRBool)(key->series == key->slot->series);
|
|
}
|
|
|
|
static PK11SymKey *
|
|
pk11_ImportSymKeyWithTempl(PK11SlotInfo *slot, CK_MECHANISM_TYPE type,
|
|
PK11Origin origin, PRBool isToken, CK_ATTRIBUTE *keyTemplate,
|
|
unsigned int templateCount, SECItem *key, void *wincx)
|
|
{
|
|
PK11SymKey * symKey;
|
|
SECStatus rv;
|
|
|
|
symKey = pk11_CreateSymKey(slot, type, !isToken, PR_TRUE, wincx);
|
|
if (symKey == NULL) {
|
|
return NULL;
|
|
}
|
|
|
|
symKey->size = key->len;
|
|
|
|
PK11_SETATTRS(&keyTemplate[templateCount], CKA_VALUE, key->data, key->len);
|
|
templateCount++;
|
|
|
|
if (SECITEM_CopyItem(NULL,&symKey->data,key) != SECSuccess) {
|
|
PK11_FreeSymKey(symKey);
|
|
return NULL;
|
|
}
|
|
|
|
symKey->origin = origin;
|
|
|
|
/* import the keys */
|
|
rv = PK11_CreateNewObject(slot, symKey->session, keyTemplate,
|
|
templateCount, isToken, &symKey->objectID);
|
|
if ( rv != SECSuccess) {
|
|
PK11_FreeSymKey(symKey);
|
|
return NULL;
|
|
}
|
|
|
|
return symKey;
|
|
}
|
|
|
|
/*
|
|
* turn key bits into an appropriate key object
|
|
*/
|
|
PK11SymKey *
|
|
PK11_ImportSymKey(PK11SlotInfo *slot, CK_MECHANISM_TYPE type,
|
|
PK11Origin origin, CK_ATTRIBUTE_TYPE operation, SECItem *key,void *wincx)
|
|
{
|
|
PK11SymKey * symKey;
|
|
unsigned int templateCount = 0;
|
|
CK_OBJECT_CLASS keyClass = CKO_SECRET_KEY;
|
|
CK_KEY_TYPE keyType = CKK_GENERIC_SECRET;
|
|
CK_BBOOL cktrue = CK_TRUE; /* sigh */
|
|
CK_ATTRIBUTE keyTemplate[5];
|
|
CK_ATTRIBUTE * attrs = keyTemplate;
|
|
|
|
PK11_SETATTRS(attrs, CKA_CLASS, &keyClass, sizeof(keyClass) ); attrs++;
|
|
PK11_SETATTRS(attrs, CKA_KEY_TYPE, &keyType, sizeof(keyType) ); attrs++;
|
|
PK11_SETATTRS(attrs, operation, &cktrue, 1); attrs++;
|
|
templateCount = attrs - keyTemplate;
|
|
PR_ASSERT(templateCount+1 <= sizeof(keyTemplate)/sizeof(CK_ATTRIBUTE));
|
|
|
|
keyType = PK11_GetKeyType(type,key->len);
|
|
symKey = pk11_ImportSymKeyWithTempl(slot, type, origin, PR_FALSE,
|
|
keyTemplate, templateCount, key, wincx);
|
|
return symKey;
|
|
}
|
|
|
|
|
|
/*
|
|
* turn key bits into an appropriate key object
|
|
*/
|
|
PK11SymKey *
|
|
PK11_ImportSymKeyWithFlags(PK11SlotInfo *slot, CK_MECHANISM_TYPE type,
|
|
PK11Origin origin, CK_ATTRIBUTE_TYPE operation, SECItem *key,
|
|
CK_FLAGS flags, PRBool isPerm, void *wincx)
|
|
{
|
|
PK11SymKey * symKey;
|
|
unsigned int templateCount = 0;
|
|
CK_OBJECT_CLASS keyClass = CKO_SECRET_KEY;
|
|
CK_KEY_TYPE keyType = CKK_GENERIC_SECRET;
|
|
CK_BBOOL cktrue = CK_TRUE; /* sigh */
|
|
CK_ATTRIBUTE keyTemplate[MAX_TEMPL_ATTRS];
|
|
CK_ATTRIBUTE * attrs = keyTemplate;
|
|
|
|
PK11_SETATTRS(attrs, CKA_CLASS, &keyClass, sizeof(keyClass) ); attrs++;
|
|
PK11_SETATTRS(attrs, CKA_KEY_TYPE, &keyType, sizeof(keyType) ); attrs++;
|
|
if (isPerm) {
|
|
PK11_SETATTRS(attrs, CKA_TOKEN, &cktrue, sizeof(cktrue) ); attrs++;
|
|
/* sigh some tokens think CKA_PRIVATE = false is a reasonable
|
|
* default for secret keys */
|
|
PK11_SETATTRS(attrs, CKA_PRIVATE, &cktrue, sizeof(cktrue) ); attrs++;
|
|
}
|
|
attrs += pk11_OpFlagsToAttributes(flags, attrs, &cktrue);
|
|
if ((operation != CKA_FLAGS_ONLY) &&
|
|
!pk11_FindAttrInTemplate(keyTemplate, attrs-keyTemplate, operation)) {
|
|
PK11_SETATTRS(attrs, operation, &cktrue, sizeof(cktrue)); attrs++;
|
|
}
|
|
templateCount = attrs - keyTemplate;
|
|
PR_ASSERT(templateCount+1 <= sizeof(keyTemplate)/sizeof(CK_ATTRIBUTE));
|
|
|
|
keyType = PK11_GetKeyType(type,key->len);
|
|
symKey = pk11_ImportSymKeyWithTempl(slot, type, origin, isPerm,
|
|
keyTemplate, templateCount, key, wincx);
|
|
if (symKey && isPerm) {
|
|
symKey->owner = PR_FALSE;
|
|
}
|
|
return symKey;
|
|
}
|
|
|
|
|
|
PK11SymKey *
|
|
PK11_FindFixedKey(PK11SlotInfo *slot, CK_MECHANISM_TYPE type, SECItem *keyID,
|
|
void *wincx)
|
|
{
|
|
CK_ATTRIBUTE findTemp[4];
|
|
CK_ATTRIBUTE *attrs;
|
|
CK_BBOOL ckTrue = CK_TRUE;
|
|
CK_OBJECT_CLASS keyclass = CKO_SECRET_KEY;
|
|
int tsize = 0;
|
|
CK_OBJECT_HANDLE key_id;
|
|
|
|
attrs = findTemp;
|
|
PK11_SETATTRS(attrs, CKA_CLASS, &keyclass, sizeof(keyclass)); attrs++;
|
|
PK11_SETATTRS(attrs, CKA_TOKEN, &ckTrue, sizeof(ckTrue)); attrs++;
|
|
if (keyID) {
|
|
PK11_SETATTRS(attrs, CKA_ID, keyID->data, keyID->len); attrs++;
|
|
}
|
|
tsize = attrs - findTemp;
|
|
PORT_Assert(tsize <= sizeof(findTemp)/sizeof(CK_ATTRIBUTE));
|
|
|
|
key_id = pk11_FindObjectByTemplate(slot,findTemp,tsize);
|
|
if (key_id == CK_INVALID_HANDLE) {
|
|
return NULL;
|
|
}
|
|
return PK11_SymKeyFromHandle(slot, NULL, PK11_OriginDerive, type, key_id,
|
|
PR_FALSE, wincx);
|
|
}
|
|
|
|
PK11SymKey *
|
|
PK11_ListFixedKeysInSlot(PK11SlotInfo *slot, char *nickname, void *wincx)
|
|
{
|
|
CK_ATTRIBUTE findTemp[4];
|
|
CK_ATTRIBUTE *attrs;
|
|
CK_BBOOL ckTrue = CK_TRUE;
|
|
CK_OBJECT_CLASS keyclass = CKO_SECRET_KEY;
|
|
int tsize = 0;
|
|
int objCount = 0;
|
|
CK_OBJECT_HANDLE *key_ids;
|
|
PK11SymKey *nextKey = NULL;
|
|
PK11SymKey *topKey = NULL;
|
|
int i,len;
|
|
|
|
attrs = findTemp;
|
|
PK11_SETATTRS(attrs, CKA_CLASS, &keyclass, sizeof(keyclass)); attrs++;
|
|
PK11_SETATTRS(attrs, CKA_TOKEN, &ckTrue, sizeof(ckTrue)); attrs++;
|
|
if (nickname) {
|
|
len = PORT_Strlen(nickname);
|
|
PK11_SETATTRS(attrs, CKA_LABEL, nickname, len); attrs++;
|
|
}
|
|
tsize = attrs - findTemp;
|
|
PORT_Assert(tsize <= sizeof(findTemp)/sizeof(CK_ATTRIBUTE));
|
|
|
|
key_ids = pk11_FindObjectsByTemplate(slot,findTemp,tsize,&objCount);
|
|
if (key_ids == NULL) {
|
|
return NULL;
|
|
}
|
|
|
|
for (i=0; i < objCount ; i++) {
|
|
SECItem typeData;
|
|
CK_KEY_TYPE type = CKK_GENERIC_SECRET;
|
|
SECStatus rv = PK11_ReadAttribute(slot, key_ids[i],
|
|
CKA_KEY_TYPE, NULL, &typeData);
|
|
if (rv == SECSuccess) {
|
|
if (typeData.len == sizeof(CK_KEY_TYPE)) {
|
|
type = *(CK_KEY_TYPE *)typeData.data;
|
|
}
|
|
PORT_Free(typeData.data);
|
|
}
|
|
nextKey = PK11_SymKeyFromHandle(slot, NULL, PK11_OriginDerive,
|
|
PK11_GetKeyMechanism(type), key_ids[i], PR_FALSE, wincx);
|
|
if (nextKey) {
|
|
nextKey->next = topKey;
|
|
topKey = nextKey;
|
|
}
|
|
}
|
|
PORT_Free(key_ids);
|
|
return topKey;
|
|
}
|
|
|
|
void *
|
|
PK11_GetWindow(PK11SymKey *key)
|
|
{
|
|
return key->cx;
|
|
}
|
|
|
|
|
|
/*
|
|
* extract a symetric key value. NOTE: if the key is sensitive, we will
|
|
* not be able to do this operation. This function is used to move
|
|
* keys from one token to another */
|
|
SECStatus
|
|
PK11_ExtractKeyValue(PK11SymKey *symKey)
|
|
{
|
|
SECStatus rv;
|
|
|
|
if (symKey->data.data != NULL) {
|
|
if (symKey->size == 0) {
|
|
symKey->size = symKey->data.len;
|
|
}
|
|
return SECSuccess;
|
|
}
|
|
|
|
if (symKey->slot == NULL) {
|
|
PORT_SetError( SEC_ERROR_INVALID_KEY );
|
|
return SECFailure;
|
|
}
|
|
|
|
rv = PK11_ReadAttribute(symKey->slot,symKey->objectID,CKA_VALUE,NULL,
|
|
&symKey->data);
|
|
if (rv == SECSuccess) {
|
|
symKey->size = symKey->data.len;
|
|
}
|
|
return rv;
|
|
}
|
|
|
|
SECStatus
|
|
PK11_DeleteTokenSymKey(PK11SymKey *symKey)
|
|
{
|
|
if (!PK11_IsPermObject(symKey->slot, symKey->objectID)) {
|
|
return SECFailure;
|
|
}
|
|
PK11_DestroyTokenObject(symKey->slot,symKey->objectID);
|
|
symKey->objectID = CK_INVALID_HANDLE;
|
|
return SECSuccess;
|
|
}
|
|
|
|
SECItem *
|
|
PK11_GetKeyData(PK11SymKey *symKey)
|
|
{
|
|
return &symKey->data;
|
|
}
|
|
|
|
/* This symbol is exported for backward compatibility. */
|
|
SECItem *
|
|
__PK11_GetKeyData(PK11SymKey *symKey)
|
|
{
|
|
return PK11_GetKeyData(symKey);
|
|
}
|
|
|
|
|
|
/*
|
|
* PKCS #11 key Types with predefined length
|
|
*/
|
|
unsigned int
|
|
pk11_GetPredefinedKeyLength(CK_KEY_TYPE keyType)
|
|
{
|
|
int length = 0;
|
|
switch (keyType) {
|
|
case CKK_DES: length = 8; break;
|
|
case CKK_DES2: length = 16; break;
|
|
case CKK_DES3: length = 24; break;
|
|
case CKK_SKIPJACK: length = 10; break;
|
|
case CKK_BATON: length = 20; break;
|
|
case CKK_JUNIPER: length = 20; break;
|
|
default: break;
|
|
}
|
|
return length;
|
|
}
|
|
|
|
/* return the keylength if possible. '0' if not */
|
|
unsigned int
|
|
PK11_GetKeyLength(PK11SymKey *key)
|
|
{
|
|
CK_KEY_TYPE keyType;
|
|
|
|
if (key->size != 0) return key->size;
|
|
|
|
/* First try to figure out the key length from its type */
|
|
keyType = PK11_ReadULongAttribute(key->slot,key->objectID,CKA_KEY_TYPE);
|
|
key->size = pk11_GetPredefinedKeyLength(keyType);
|
|
if ((keyType == CKK_GENERIC_SECRET) &&
|
|
(key->type == CKM_SSL3_PRE_MASTER_KEY_GEN)) {
|
|
key->size=48;
|
|
}
|
|
|
|
if( key->size != 0 ) return key->size;
|
|
|
|
if (key->data.data == NULL) {
|
|
PK11_ExtractKeyValue(key);
|
|
}
|
|
/* key is probably secret. Look up its length */
|
|
/* this is new PKCS #11 version 2.0 functionality. */
|
|
if (key->size == 0) {
|
|
CK_ULONG keyLength;
|
|
|
|
keyLength = PK11_ReadULongAttribute(key->slot,key->objectID,CKA_VALUE_LEN);
|
|
if (keyLength != CK_UNAVAILABLE_INFORMATION) {
|
|
key->size = (unsigned int)keyLength;
|
|
}
|
|
}
|
|
|
|
return key->size;
|
|
}
|
|
|
|
/* return the strength of a key. This is different from length in that
|
|
* 1) it returns the size in bits, and 2) it returns only the secret portions
|
|
* of the key minus any checksums or parity.
|
|
*/
|
|
unsigned int
|
|
PK11_GetKeyStrength(PK11SymKey *key, SECAlgorithmID *algid)
|
|
{
|
|
int size=0;
|
|
CK_MECHANISM_TYPE mechanism= CKM_INVALID_MECHANISM; /* RC2 only */
|
|
SECItem *param = NULL; /* RC2 only */
|
|
CK_RC2_CBC_PARAMS *rc2_params = NULL; /* RC2 ONLY */
|
|
unsigned int effectiveBits = 0; /* RC2 ONLY */
|
|
|
|
switch (PK11_GetKeyType(key->type,0)) {
|
|
case CKK_CDMF:
|
|
return 40;
|
|
case CKK_DES:
|
|
return 56;
|
|
case CKK_DES3:
|
|
case CKK_DES2:
|
|
size = PK11_GetKeyLength(key);
|
|
if (size == 16) {
|
|
/* double des */
|
|
return 112; /* 16*7 */
|
|
}
|
|
return 168;
|
|
/*
|
|
* RC2 has is different than other ciphers in that it allows the user
|
|
* to deprecating keysize while still requiring all the bits for the
|
|
* original key. The info
|
|
* on what the effective key strength is in the parameter for the key.
|
|
* In S/MIME this parameter is stored in the DER encoded algid. In Our
|
|
* other uses of RC2, effectiveBits == keyBits, so this code functions
|
|
* correctly without an algid.
|
|
*/
|
|
case CKK_RC2:
|
|
/* if no algid was provided, fall through to default */
|
|
if (!algid) {
|
|
break;
|
|
}
|
|
/* verify that the algid is for RC2 */
|
|
mechanism = PK11_AlgtagToMechanism(SECOID_GetAlgorithmTag(algid));
|
|
if ((mechanism != CKM_RC2_CBC) && (mechanism != CKM_RC2_ECB)) {
|
|
break;
|
|
}
|
|
|
|
/* now get effective bits from the algorithm ID. */
|
|
param = PK11_ParamFromAlgid(algid);
|
|
/* if we couldn't get memory just use key length */
|
|
if (param == NULL) {
|
|
break;
|
|
}
|
|
|
|
rc2_params = (CK_RC2_CBC_PARAMS *) param->data;
|
|
/* paranoia... shouldn't happen */
|
|
PORT_Assert(param->data != NULL);
|
|
if (param->data == NULL) {
|
|
SECITEM_FreeItem(param,PR_TRUE);
|
|
break;
|
|
}
|
|
effectiveBits = (unsigned int)rc2_params->ulEffectiveBits;
|
|
SECITEM_FreeItem(param,PR_TRUE);
|
|
param = NULL; rc2_params=NULL; /* paranoia */
|
|
|
|
/* we have effective bits, is and allocated memory is free, now
|
|
* we need to return the smaller of effective bits and keysize */
|
|
size = PK11_GetKeyLength(key);
|
|
if ((unsigned int)size*8 > effectiveBits) {
|
|
return effectiveBits;
|
|
}
|
|
|
|
return size*8; /* the actual key is smaller, the strength can't be
|
|
* greater than the actual key size */
|
|
|
|
default:
|
|
break;
|
|
}
|
|
return PK11_GetKeyLength(key) * 8;
|
|
}
|
|
|
|
/*
|
|
* The next three utilities are to deal with the fact that a given operation
|
|
* may be a multi-slot affair. This creates a new key object that is copied
|
|
* into the new slot.
|
|
*/
|
|
PK11SymKey *
|
|
pk11_CopyToSlotPerm(PK11SlotInfo *slot,CK_MECHANISM_TYPE type,
|
|
CK_ATTRIBUTE_TYPE operation, CK_FLAGS flags,
|
|
PRBool isPerm, PK11SymKey *symKey)
|
|
{
|
|
SECStatus rv;
|
|
PK11SymKey *newKey = NULL;
|
|
|
|
/* Extract the raw key data if possible */
|
|
if (symKey->data.data == NULL) {
|
|
rv = PK11_ExtractKeyValue(symKey);
|
|
/* KEY is sensitive, we're try key exchanging it. */
|
|
if (rv != SECSuccess) {
|
|
return pk11_KeyExchange(slot, type, operation,
|
|
flags, isPerm, symKey);
|
|
}
|
|
}
|
|
|
|
newKey = PK11_ImportSymKeyWithFlags(slot, type, symKey->origin,
|
|
operation, &symKey->data, flags, isPerm, symKey->cx);
|
|
if (newKey == NULL) {
|
|
newKey = pk11_KeyExchange(slot, type, operation, flags, isPerm, symKey);
|
|
}
|
|
return newKey;
|
|
}
|
|
|
|
PK11SymKey *
|
|
pk11_CopyToSlot(PK11SlotInfo *slot,CK_MECHANISM_TYPE type,
|
|
CK_ATTRIBUTE_TYPE operation, PK11SymKey *symKey)
|
|
{
|
|
return pk11_CopyToSlotPerm(slot, type, operation, 0, PR_FALSE, symKey);
|
|
}
|
|
|
|
/*
|
|
* Make sure the slot we are in is the correct slot for the operation
|
|
* by verifying that it supports all of the specified mechanism types.
|
|
*/
|
|
PK11SymKey *
|
|
pk11_ForceSlotMultiple(PK11SymKey *symKey, CK_MECHANISM_TYPE *type,
|
|
int mechCount, CK_ATTRIBUTE_TYPE operation)
|
|
{
|
|
PK11SlotInfo *slot = symKey->slot;
|
|
PK11SymKey *newKey = NULL;
|
|
PRBool needToCopy = PR_FALSE;
|
|
int i;
|
|
|
|
if (slot == NULL) {
|
|
needToCopy = PR_TRUE;
|
|
} else {
|
|
i = 0;
|
|
while ((i < mechCount) && (needToCopy == PR_FALSE)) {
|
|
if (!PK11_DoesMechanism(slot,type[i])) {
|
|
needToCopy = PR_TRUE;
|
|
}
|
|
i++;
|
|
}
|
|
}
|
|
|
|
if (needToCopy == PR_TRUE) {
|
|
slot = PK11_GetBestSlotMultiple(type,mechCount,symKey->cx);
|
|
if (slot == NULL) {
|
|
PORT_SetError( SEC_ERROR_NO_MODULE );
|
|
return NULL;
|
|
}
|
|
newKey = pk11_CopyToSlot(slot, type[0], operation, symKey);
|
|
PK11_FreeSlot(slot);
|
|
}
|
|
return newKey;
|
|
}
|
|
|
|
/*
|
|
* Make sure the slot we are in is the correct slot for the operation
|
|
*/
|
|
PK11SymKey *
|
|
pk11_ForceSlot(PK11SymKey *symKey,CK_MECHANISM_TYPE type,
|
|
CK_ATTRIBUTE_TYPE operation)
|
|
{
|
|
return pk11_ForceSlotMultiple(symKey, &type, 1, operation);
|
|
}
|
|
|
|
PK11SymKey *
|
|
PK11_MoveSymKey(PK11SlotInfo *slot, CK_ATTRIBUTE_TYPE operation,
|
|
CK_FLAGS flags, PRBool perm, PK11SymKey *symKey)
|
|
{
|
|
if (symKey->slot == slot) {
|
|
if (perm) {
|
|
return PK11_ConvertSessionSymKeyToTokenSymKey(symKey,symKey->cx);
|
|
} else {
|
|
return PK11_ReferenceSymKey(symKey);
|
|
}
|
|
}
|
|
|
|
return pk11_CopyToSlotPerm(slot, symKey->type,
|
|
operation, flags, perm, symKey);
|
|
}
|
|
|
|
/*
|
|
* Use the token to generate a key.
|
|
*
|
|
* keySize must be 'zero' for fixed key length algorithms. A nonzero
|
|
* keySize causes the CKA_VALUE_LEN attribute to be added to the template
|
|
* for the key. Most PKCS #11 modules fail if you specify the CKA_VALUE_LEN
|
|
* attribute for keys with fixed length. The exception is DES2. If you
|
|
* select a CKM_DES3_CBC mechanism, this code will not add the CKA_VALUE_LEN
|
|
* parameter and use the key size to determine which underlying DES keygen
|
|
* function to use (CKM_DES2_KEY_GEN or CKM_DES3_KEY_GEN).
|
|
*
|
|
* keyType must be -1 for most algorithms. Some PBE algorthims cannot
|
|
* determine the correct key type from the mechanism or the parameters,
|
|
* so key type must be specified. Other PKCS #11 mechanisms may do so in
|
|
* the future. Currently there is no need to export this publically.
|
|
* Keep it private until there is a need in case we need to expand the
|
|
* keygen parameters again...
|
|
*
|
|
* CK_FLAGS flags: key operation flags
|
|
* PK11AttrFlags attrFlags: PK11_ATTR_XXX key attribute flags
|
|
*/
|
|
PK11SymKey *
|
|
pk11_TokenKeyGenWithFlagsAndKeyType(PK11SlotInfo *slot, CK_MECHANISM_TYPE type,
|
|
SECItem *param, CK_KEY_TYPE keyType, int keySize, SECItem *keyid,
|
|
CK_FLAGS opFlags, PK11AttrFlags attrFlags, void *wincx)
|
|
{
|
|
PK11SymKey *symKey;
|
|
CK_ATTRIBUTE genTemplate[MAX_TEMPL_ATTRS];
|
|
CK_ATTRIBUTE *attrs = genTemplate;
|
|
int count = sizeof(genTemplate)/sizeof(genTemplate[0]);
|
|
CK_MECHANISM_TYPE keyGenType;
|
|
CK_BBOOL cktrue = CK_TRUE;
|
|
CK_BBOOL ckfalse = CK_FALSE;
|
|
CK_ULONG ck_key_size; /* only used for variable-length keys */
|
|
|
|
if (pk11_BadAttrFlags(attrFlags)) {
|
|
PORT_SetError( SEC_ERROR_INVALID_ARGS );
|
|
return NULL;
|
|
}
|
|
|
|
if ((keySize != 0) && (type != CKM_DES3_CBC) &&
|
|
(type !=CKM_DES3_CBC_PAD) && (type != CKM_DES3_ECB)) {
|
|
ck_key_size = keySize; /* Convert to PK11 type */
|
|
|
|
PK11_SETATTRS(attrs, CKA_VALUE_LEN, &ck_key_size, sizeof(ck_key_size));
|
|
attrs++;
|
|
}
|
|
|
|
if (keyType != -1) {
|
|
PK11_SETATTRS(attrs, CKA_KEY_TYPE, &keyType, sizeof(CK_KEY_TYPE));
|
|
attrs++;
|
|
}
|
|
|
|
/* Include key id value if provided */
|
|
if (keyid) {
|
|
PK11_SETATTRS(attrs, CKA_ID, keyid->data, keyid->len); attrs++;
|
|
}
|
|
|
|
attrs += pk11_AttrFlagsToAttributes(attrFlags, attrs, &cktrue, &ckfalse);
|
|
attrs += pk11_OpFlagsToAttributes(opFlags, attrs, &cktrue);
|
|
|
|
count = attrs - genTemplate;
|
|
PR_ASSERT(count <= sizeof(genTemplate)/sizeof(CK_ATTRIBUTE));
|
|
|
|
keyGenType = PK11_GetKeyGenWithSize(type, keySize);
|
|
if (keyGenType == CKM_FAKE_RANDOM) {
|
|
PORT_SetError( SEC_ERROR_NO_MODULE );
|
|
return NULL;
|
|
}
|
|
symKey = PK11_KeyGenWithTemplate(slot, type, keyGenType,
|
|
param, genTemplate, count, wincx);
|
|
if (symKey != NULL) {
|
|
symKey->size = keySize;
|
|
}
|
|
return symKey;
|
|
}
|
|
|
|
/*
|
|
* Use the token to generate a key. - Public
|
|
*
|
|
* keySize must be 'zero' for fixed key length algorithms. A nonzero
|
|
* keySize causes the CKA_VALUE_LEN attribute to be added to the template
|
|
* for the key. Most PKCS #11 modules fail if you specify the CKA_VALUE_LEN
|
|
* attribute for keys with fixed length. The exception is DES2. If you
|
|
* select a CKM_DES3_CBC mechanism, this code will not add the CKA_VALUE_LEN
|
|
* parameter and use the key size to determine which underlying DES keygen
|
|
* function to use (CKM_DES2_KEY_GEN or CKM_DES3_KEY_GEN).
|
|
*
|
|
* CK_FLAGS flags: key operation flags
|
|
* PK11AttrFlags attrFlags: PK11_ATTR_XXX key attribute flags
|
|
*/
|
|
PK11SymKey *
|
|
PK11_TokenKeyGenWithFlags(PK11SlotInfo *slot, CK_MECHANISM_TYPE type,
|
|
SECItem *param, int keySize, SECItem *keyid, CK_FLAGS opFlags,
|
|
PK11AttrFlags attrFlags, void *wincx)
|
|
{
|
|
return pk11_TokenKeyGenWithFlagsAndKeyType(slot, type, param, -1, keySize,
|
|
keyid, opFlags, attrFlags, wincx);
|
|
}
|
|
|
|
/*
|
|
* Use the token to generate a key. keySize must be 'zero' for fixed key
|
|
* length algorithms. A nonzero keySize causes the CKA_VALUE_LEN attribute
|
|
* to be added to the template for the key. PKCS #11 modules fail if you
|
|
* specify the CKA_VALUE_LEN attribute for keys with fixed length.
|
|
* NOTE: this means to generate a DES2 key from this interface you must
|
|
* specify CKM_DES2_KEY_GEN as the mechanism directly; specifying
|
|
* CKM_DES3_CBC as the mechanism and 16 as keySize currently doesn't work.
|
|
*/
|
|
PK11SymKey *
|
|
PK11_TokenKeyGen(PK11SlotInfo *slot, CK_MECHANISM_TYPE type, SECItem *param,
|
|
int keySize, SECItem *keyid, PRBool isToken, void *wincx)
|
|
{
|
|
PK11SymKey *symKey;
|
|
PRBool weird = PR_FALSE; /* hack for fortezza */
|
|
CK_FLAGS opFlags = CKF_SIGN;
|
|
PK11AttrFlags attrFlags = 0;
|
|
|
|
if ((keySize == -1) && (type == CKM_SKIPJACK_CBC64)) {
|
|
weird = PR_TRUE;
|
|
keySize = 0;
|
|
}
|
|
|
|
opFlags |= weird ? CKF_DECRYPT : CKF_ENCRYPT;
|
|
|
|
if (isToken) {
|
|
attrFlags |= (PK11_ATTR_TOKEN | PK11_ATTR_PRIVATE);
|
|
}
|
|
|
|
symKey = pk11_TokenKeyGenWithFlagsAndKeyType(slot, type, param,
|
|
-1, keySize, keyid, opFlags, attrFlags, wincx);
|
|
if (symKey && weird) {
|
|
PK11_SetFortezzaHack(symKey);
|
|
}
|
|
|
|
return symKey;
|
|
}
|
|
|
|
PK11SymKey *
|
|
PK11_KeyGen(PK11SlotInfo *slot, CK_MECHANISM_TYPE type, SECItem *param,
|
|
int keySize, void *wincx)
|
|
{
|
|
return PK11_TokenKeyGen(slot, type, param, keySize, 0, PR_FALSE, wincx);
|
|
}
|
|
|
|
PK11SymKey *
|
|
PK11_KeyGenWithTemplate(PK11SlotInfo *slot, CK_MECHANISM_TYPE type,
|
|
CK_MECHANISM_TYPE keyGenType,
|
|
SECItem *param, CK_ATTRIBUTE * attrs,
|
|
unsigned int attrsCount, void *wincx)
|
|
{
|
|
PK11SymKey *symKey;
|
|
CK_SESSION_HANDLE session;
|
|
CK_MECHANISM mechanism;
|
|
CK_RV crv;
|
|
PRBool isToken = CK_FALSE;
|
|
CK_ULONG keySize = 0;
|
|
unsigned i;
|
|
|
|
/* Extract the template's CKA_VALUE_LEN into keySize and CKA_TOKEN into
|
|
isToken. */
|
|
for (i = 0; i < attrsCount; ++i) {
|
|
switch (attrs[i].type) {
|
|
case CKA_VALUE_LEN:
|
|
if (attrs[i].pValue == NULL ||
|
|
attrs[i].ulValueLen != sizeof(CK_ULONG)) {
|
|
PORT_SetError(PK11_MapError(CKR_TEMPLATE_INCONSISTENT));
|
|
return NULL;
|
|
}
|
|
keySize = * (CK_ULONG *) attrs[i].pValue;
|
|
break;
|
|
case CKA_TOKEN:
|
|
if (attrs[i].pValue == NULL ||
|
|
attrs[i].ulValueLen != sizeof(CK_BBOOL)) {
|
|
PORT_SetError(PK11_MapError(CKR_TEMPLATE_INCONSISTENT));
|
|
return NULL;
|
|
}
|
|
isToken = (*(CK_BBOOL*)attrs[i].pValue) ? PR_TRUE : PR_FALSE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* find a slot to generate the key into */
|
|
/* Only do slot management if this is not a token key */
|
|
if (!isToken && (slot == NULL || !PK11_DoesMechanism(slot,type))) {
|
|
PK11SlotInfo *bestSlot = PK11_GetBestSlot(type,wincx);
|
|
if (bestSlot == NULL) {
|
|
PORT_SetError( SEC_ERROR_NO_MODULE );
|
|
return NULL;
|
|
}
|
|
symKey = pk11_CreateSymKey(bestSlot, type, !isToken, PR_TRUE, wincx);
|
|
PK11_FreeSlot(bestSlot);
|
|
} else {
|
|
symKey = pk11_CreateSymKey(slot, type, !isToken, PR_TRUE, wincx);
|
|
}
|
|
if (symKey == NULL) return NULL;
|
|
|
|
symKey->size = keySize;
|
|
symKey->origin = PK11_OriginGenerated;
|
|
|
|
/* Set the parameters for the key gen if provided */
|
|
mechanism.mechanism = keyGenType;
|
|
mechanism.pParameter = NULL;
|
|
mechanism.ulParameterLen = 0;
|
|
if (param) {
|
|
mechanism.pParameter = param->data;
|
|
mechanism.ulParameterLen = param->len;
|
|
}
|
|
|
|
/* Get session and perform locking */
|
|
if (isToken) {
|
|
PK11_Authenticate(symKey->slot,PR_TRUE,wincx);
|
|
/* Should always be original slot */
|
|
session = PK11_GetRWSession(symKey->slot);
|
|
symKey->owner = PR_FALSE;
|
|
} else {
|
|
session = symKey->session;
|
|
if (session != CK_INVALID_SESSION)
|
|
pk11_EnterKeyMonitor(symKey);
|
|
}
|
|
if (session == CK_INVALID_SESSION) {
|
|
PK11_FreeSymKey(symKey);
|
|
PORT_SetError(SEC_ERROR_BAD_DATA);
|
|
return NULL;
|
|
}
|
|
|
|
crv = PK11_GETTAB(symKey->slot)->C_GenerateKey(session,
|
|
&mechanism, attrs, attrsCount, &symKey->objectID);
|
|
|
|
/* Release lock and session */
|
|
if (isToken) {
|
|
PK11_RestoreROSession(symKey->slot, session);
|
|
} else {
|
|
pk11_ExitKeyMonitor(symKey);
|
|
}
|
|
|
|
if (crv != CKR_OK) {
|
|
PK11_FreeSymKey(symKey);
|
|
PORT_SetError( PK11_MapError(crv) );
|
|
return NULL;
|
|
}
|
|
|
|
return symKey;
|
|
}
|
|
|
|
|
|
/* --- */
|
|
PK11SymKey *
|
|
PK11_GenDES3TokenKey(PK11SlotInfo *slot, SECItem *keyid, void *cx)
|
|
{
|
|
return PK11_TokenKeyGen(slot, CKM_DES3_CBC, 0, 0, keyid, PR_TRUE, cx);
|
|
}
|
|
|
|
PK11SymKey*
|
|
PK11_ConvertSessionSymKeyToTokenSymKey(PK11SymKey *symk, void *wincx)
|
|
{
|
|
PK11SlotInfo* slot = symk->slot;
|
|
CK_ATTRIBUTE template[1];
|
|
CK_ATTRIBUTE *attrs = template;
|
|
CK_BBOOL cktrue = CK_TRUE;
|
|
CK_RV crv;
|
|
CK_OBJECT_HANDLE newKeyID;
|
|
CK_SESSION_HANDLE rwsession;
|
|
|
|
PK11_SETATTRS(attrs, CKA_TOKEN, &cktrue, sizeof(cktrue)); attrs++;
|
|
|
|
PK11_Authenticate(slot, PR_TRUE, wincx);
|
|
rwsession = PK11_GetRWSession(slot);
|
|
if (rwsession == CK_INVALID_SESSION) {
|
|
PORT_SetError(SEC_ERROR_BAD_DATA);
|
|
return NULL;
|
|
}
|
|
crv = PK11_GETTAB(slot)->C_CopyObject(rwsession, symk->objectID,
|
|
template, 1, &newKeyID);
|
|
PK11_RestoreROSession(slot, rwsession);
|
|
|
|
if (crv != CKR_OK) {
|
|
PORT_SetError( PK11_MapError(crv) );
|
|
return NULL;
|
|
}
|
|
|
|
return PK11_SymKeyFromHandle(slot, NULL /*parent*/, symk->origin,
|
|
symk->type, newKeyID, PR_FALSE /*owner*/, NULL /*wincx*/);
|
|
}
|
|
|
|
/*
|
|
* This function does a straight public key wrap (which only RSA can do).
|
|
* Use PK11_PubGenKey and PK11_WrapSymKey to implement the FORTEZZA and
|
|
* Diffie-Hellman Ciphers. */
|
|
SECStatus
|
|
PK11_PubWrapSymKey(CK_MECHANISM_TYPE type, SECKEYPublicKey *pubKey,
|
|
PK11SymKey *symKey, SECItem *wrappedKey)
|
|
{
|
|
PK11SlotInfo *slot;
|
|
CK_ULONG len = wrappedKey->len;
|
|
PK11SymKey *newKey = NULL;
|
|
CK_OBJECT_HANDLE id;
|
|
CK_MECHANISM mechanism;
|
|
PRBool owner = PR_TRUE;
|
|
CK_SESSION_HANDLE session;
|
|
CK_RV crv;
|
|
|
|
if (symKey == NULL) {
|
|
PORT_SetError( SEC_ERROR_INVALID_ARGS );
|
|
return SECFailure;
|
|
}
|
|
|
|
/* if this slot doesn't support the mechanism, go to a slot that does */
|
|
newKey = pk11_ForceSlot(symKey,type,CKA_ENCRYPT);
|
|
if (newKey != NULL) {
|
|
symKey = newKey;
|
|
}
|
|
|
|
if (symKey->slot == NULL) {
|
|
PORT_SetError( SEC_ERROR_NO_MODULE );
|
|
return SECFailure;
|
|
}
|
|
|
|
slot = symKey->slot;
|
|
mechanism.mechanism = pk11_mapWrapKeyType(pubKey->keyType);
|
|
mechanism.pParameter = NULL;
|
|
mechanism.ulParameterLen = 0;
|
|
|
|
id = PK11_ImportPublicKey(slot,pubKey,PR_FALSE);
|
|
if (id == CK_INVALID_HANDLE) {
|
|
if (newKey) {
|
|
PK11_FreeSymKey(newKey);
|
|
}
|
|
return SECFailure; /* Error code has been set. */
|
|
}
|
|
|
|
session = pk11_GetNewSession(slot,&owner);
|
|
if (!owner || !(slot->isThreadSafe)) PK11_EnterSlotMonitor(slot);
|
|
crv = PK11_GETTAB(slot)->C_WrapKey(session,&mechanism,
|
|
id,symKey->objectID,wrappedKey->data,&len);
|
|
if (!owner || !(slot->isThreadSafe)) PK11_ExitSlotMonitor(slot);
|
|
pk11_CloseSession(slot,session,owner);
|
|
if (newKey) {
|
|
PK11_FreeSymKey(newKey);
|
|
}
|
|
|
|
if (crv != CKR_OK) {
|
|
PORT_SetError( PK11_MapError(crv) );
|
|
return SECFailure;
|
|
}
|
|
wrappedKey->len = len;
|
|
return SECSuccess;
|
|
}
|
|
|
|
/*
|
|
* this little function uses the Encrypt function to wrap a key, just in
|
|
* case we have problems with the wrap implementation for a token.
|
|
*/
|
|
static SECStatus
|
|
pk11_HandWrap(PK11SymKey *wrappingKey, SECItem *param, CK_MECHANISM_TYPE type,
|
|
SECItem *inKey, SECItem *outKey)
|
|
{
|
|
PK11SlotInfo *slot;
|
|
CK_ULONG len;
|
|
SECItem *data;
|
|
CK_MECHANISM mech;
|
|
PRBool owner = PR_TRUE;
|
|
CK_SESSION_HANDLE session;
|
|
CK_RV crv;
|
|
|
|
slot = wrappingKey->slot;
|
|
/* use NULL IV's for wrapping */
|
|
mech.mechanism = type;
|
|
if (param) {
|
|
mech.pParameter = param->data;
|
|
mech.ulParameterLen = param->len;
|
|
} else {
|
|
mech.pParameter = NULL;
|
|
mech.ulParameterLen = 0;
|
|
}
|
|
session = pk11_GetNewSession(slot,&owner);
|
|
if (!owner || !(slot->isThreadSafe)) PK11_EnterSlotMonitor(slot);
|
|
crv = PK11_GETTAB(slot)->C_EncryptInit(session,&mech,
|
|
wrappingKey->objectID);
|
|
if (crv != CKR_OK) {
|
|
if (!owner || !(slot->isThreadSafe)) PK11_ExitSlotMonitor(slot);
|
|
pk11_CloseSession(slot,session,owner);
|
|
PORT_SetError( PK11_MapError(crv) );
|
|
return SECFailure;
|
|
}
|
|
|
|
/* keys are almost always aligned, but if we get this far,
|
|
* we've gone above and beyond anyway... */
|
|
data = PK11_BlockData(inKey,PK11_GetBlockSize(type,param));
|
|
if (data == NULL) {
|
|
if (!owner || !(slot->isThreadSafe)) PK11_ExitSlotMonitor(slot);
|
|
pk11_CloseSession(slot,session,owner);
|
|
PORT_SetError(SEC_ERROR_NO_MEMORY);
|
|
return SECFailure;
|
|
}
|
|
len = outKey->len;
|
|
crv = PK11_GETTAB(slot)->C_Encrypt(session,data->data,data->len,
|
|
outKey->data, &len);
|
|
if (!owner || !(slot->isThreadSafe)) PK11_ExitSlotMonitor(slot);
|
|
pk11_CloseSession(slot,session,owner);
|
|
SECITEM_FreeItem(data,PR_TRUE);
|
|
outKey->len = len;
|
|
if (crv != CKR_OK) {
|
|
PORT_SetError( PK11_MapError(crv) );
|
|
return SECFailure;
|
|
}
|
|
return SECSuccess;
|
|
}
|
|
|
|
/*
|
|
* This function does a symetric based wrap.
|
|
*/
|
|
SECStatus
|
|
PK11_WrapSymKey(CK_MECHANISM_TYPE type, SECItem *param,
|
|
PK11SymKey *wrappingKey, PK11SymKey *symKey, SECItem *wrappedKey)
|
|
{
|
|
PK11SlotInfo *slot;
|
|
CK_ULONG len = wrappedKey->len;
|
|
PK11SymKey *newKey = NULL;
|
|
SECItem *param_save = NULL;
|
|
CK_MECHANISM mechanism;
|
|
PRBool owner = PR_TRUE;
|
|
CK_SESSION_HANDLE session;
|
|
CK_RV crv;
|
|
SECStatus rv;
|
|
|
|
/* if this slot doesn't support the mechanism, go to a slot that does */
|
|
/* Force symKey and wrappingKey into the same slot */
|
|
if ((wrappingKey->slot == NULL) || (symKey->slot != wrappingKey->slot)) {
|
|
/* first try copying the wrapping Key to the symKey slot */
|
|
if (symKey->slot && PK11_DoesMechanism(symKey->slot,type)) {
|
|
newKey = pk11_CopyToSlot(symKey->slot,type,CKA_WRAP,wrappingKey);
|
|
}
|
|
/* Nope, try it the other way */
|
|
if (newKey == NULL) {
|
|
if (wrappingKey->slot) {
|
|
newKey = pk11_CopyToSlot(wrappingKey->slot,
|
|
symKey->type, CKA_ENCRYPT, symKey);
|
|
}
|
|
/* just not playing... one last thing, can we get symKey's data?
|
|
* If it's possible, we it should already be in the
|
|
* symKey->data.data pointer because pk11_CopyToSlot would have
|
|
* tried to put it there. */
|
|
if (newKey == NULL) {
|
|
/* Can't get symKey's data: Game Over */
|
|
if (symKey->data.data == NULL) {
|
|
PORT_SetError( SEC_ERROR_NO_MODULE );
|
|
return SECFailure;
|
|
}
|
|
if (param == NULL) {
|
|
param_save = param = PK11_ParamFromIV(type,NULL);
|
|
}
|
|
rv = pk11_HandWrap(wrappingKey, param, type,
|
|
&symKey->data,wrappedKey);
|
|
if (param_save) SECITEM_FreeItem(param_save,PR_TRUE);
|
|
return rv;
|
|
}
|
|
/* we successfully moved the sym Key */
|
|
symKey = newKey;
|
|
} else {
|
|
/* we successfully moved the wrapping Key */
|
|
wrappingKey = newKey;
|
|
}
|
|
}
|
|
|
|
/* at this point both keys are in the same token */
|
|
slot = wrappingKey->slot;
|
|
mechanism.mechanism = type;
|
|
/* use NULL IV's for wrapping */
|
|
if (param == NULL) {
|
|
param_save = param = PK11_ParamFromIV(type,NULL);
|
|
}
|
|
if (param) {
|
|
mechanism.pParameter = param->data;
|
|
mechanism.ulParameterLen = param->len;
|
|
} else {
|
|
mechanism.pParameter = NULL;
|
|
mechanism.ulParameterLen = 0;
|
|
}
|
|
|
|
len = wrappedKey->len;
|
|
|
|
session = pk11_GetNewSession(slot,&owner);
|
|
if (!owner || !(slot->isThreadSafe)) PK11_EnterSlotMonitor(slot);
|
|
crv = PK11_GETTAB(slot)->C_WrapKey(session, &mechanism,
|
|
wrappingKey->objectID, symKey->objectID,
|
|
wrappedKey->data, &len);
|
|
if (!owner || !(slot->isThreadSafe)) PK11_ExitSlotMonitor(slot);
|
|
pk11_CloseSession(slot,session,owner);
|
|
rv = SECSuccess;
|
|
if (crv != CKR_OK) {
|
|
/* can't wrap it? try hand wrapping it... */
|
|
do {
|
|
if (symKey->data.data == NULL) {
|
|
rv = PK11_ExtractKeyValue(symKey);
|
|
if (rv != SECSuccess) break;
|
|
}
|
|
rv = pk11_HandWrap(wrappingKey, param, type, &symKey->data,
|
|
wrappedKey);
|
|
} while (PR_FALSE);
|
|
} else {
|
|
wrappedKey->len = len;
|
|
}
|
|
if (newKey) PK11_FreeSymKey(newKey);
|
|
if (param_save) SECITEM_FreeItem(param_save,PR_TRUE);
|
|
return rv;
|
|
}
|
|
|
|
/*
|
|
* This Generates a new key based on a symetricKey
|
|
*/
|
|
PK11SymKey *
|
|
PK11_Derive( PK11SymKey *baseKey, CK_MECHANISM_TYPE derive, SECItem *param,
|
|
CK_MECHANISM_TYPE target, CK_ATTRIBUTE_TYPE operation,
|
|
int keySize)
|
|
{
|
|
return PK11_DeriveWithTemplate(baseKey, derive, param, target, operation,
|
|
keySize, NULL, 0, PR_FALSE);
|
|
}
|
|
|
|
|
|
PK11SymKey *
|
|
PK11_DeriveWithFlags( PK11SymKey *baseKey, CK_MECHANISM_TYPE derive,
|
|
SECItem *param, CK_MECHANISM_TYPE target, CK_ATTRIBUTE_TYPE operation,
|
|
int keySize, CK_FLAGS flags)
|
|
{
|
|
CK_BBOOL ckTrue = CK_TRUE;
|
|
CK_ATTRIBUTE keyTemplate[MAX_TEMPL_ATTRS];
|
|
unsigned int templateCount;
|
|
|
|
templateCount = pk11_OpFlagsToAttributes(flags, keyTemplate, &ckTrue);
|
|
return PK11_DeriveWithTemplate(baseKey, derive, param, target, operation,
|
|
keySize, keyTemplate, templateCount, PR_FALSE);
|
|
}
|
|
|
|
PK11SymKey *
|
|
PK11_DeriveWithFlagsPerm( PK11SymKey *baseKey, CK_MECHANISM_TYPE derive,
|
|
SECItem *param, CK_MECHANISM_TYPE target, CK_ATTRIBUTE_TYPE operation,
|
|
int keySize, CK_FLAGS flags, PRBool isPerm)
|
|
{
|
|
CK_BBOOL cktrue = CK_TRUE;
|
|
CK_ATTRIBUTE keyTemplate[MAX_TEMPL_ATTRS];
|
|
CK_ATTRIBUTE *attrs;
|
|
unsigned int templateCount = 0;
|
|
|
|
attrs = keyTemplate;
|
|
if (isPerm) {
|
|
PK11_SETATTRS(attrs, CKA_TOKEN, &cktrue, sizeof(CK_BBOOL)); attrs++;
|
|
}
|
|
templateCount = attrs - keyTemplate;
|
|
templateCount += pk11_OpFlagsToAttributes(flags, attrs, &cktrue);
|
|
return PK11_DeriveWithTemplate(baseKey, derive, param, target, operation,
|
|
keySize, keyTemplate, templateCount, isPerm);
|
|
}
|
|
|
|
PK11SymKey *
|
|
PK11_DeriveWithTemplate( PK11SymKey *baseKey, CK_MECHANISM_TYPE derive,
|
|
SECItem *param, CK_MECHANISM_TYPE target, CK_ATTRIBUTE_TYPE operation,
|
|
int keySize, CK_ATTRIBUTE *userAttr, unsigned int numAttrs,
|
|
PRBool isPerm)
|
|
{
|
|
PK11SlotInfo * slot = baseKey->slot;
|
|
PK11SymKey * symKey;
|
|
PK11SymKey * newBaseKey = NULL;
|
|
CK_BBOOL cktrue = CK_TRUE;
|
|
CK_OBJECT_CLASS keyClass = CKO_SECRET_KEY;
|
|
CK_KEY_TYPE keyType = CKK_GENERIC_SECRET;
|
|
CK_ULONG valueLen = 0;
|
|
CK_MECHANISM mechanism;
|
|
CK_RV crv;
|
|
#define MAX_ADD_ATTRS 4
|
|
CK_ATTRIBUTE keyTemplate[MAX_TEMPL_ATTRS + MAX_ADD_ATTRS];
|
|
#undef MAX_ADD_ATTRS
|
|
CK_ATTRIBUTE * attrs = keyTemplate;
|
|
CK_SESSION_HANDLE session;
|
|
unsigned int templateCount;
|
|
|
|
if (numAttrs > MAX_TEMPL_ATTRS) {
|
|
PORT_SetError(SEC_ERROR_INVALID_ARGS);
|
|
return NULL;
|
|
}
|
|
|
|
/* first copy caller attributes in. */
|
|
for (templateCount = 0; templateCount < numAttrs; ++templateCount) {
|
|
*attrs++ = *userAttr++;
|
|
}
|
|
|
|
/* We only add the following attributes to the template if the caller
|
|
** didn't already supply them.
|
|
*/
|
|
if (!pk11_FindAttrInTemplate(keyTemplate, numAttrs, CKA_CLASS)) {
|
|
PK11_SETATTRS(attrs, CKA_CLASS, &keyClass, sizeof keyClass);
|
|
attrs++;
|
|
}
|
|
if (!pk11_FindAttrInTemplate(keyTemplate, numAttrs, CKA_KEY_TYPE)) {
|
|
keyType = PK11_GetKeyType(target, keySize);
|
|
PK11_SETATTRS(attrs, CKA_KEY_TYPE, &keyType, sizeof keyType );
|
|
attrs++;
|
|
}
|
|
if (keySize > 0 &&
|
|
!pk11_FindAttrInTemplate(keyTemplate, numAttrs, CKA_VALUE_LEN)) {
|
|
valueLen = (CK_ULONG)keySize;
|
|
PK11_SETATTRS(attrs, CKA_VALUE_LEN, &valueLen, sizeof valueLen);
|
|
attrs++;
|
|
}
|
|
if ((operation != CKA_FLAGS_ONLY) &&
|
|
!pk11_FindAttrInTemplate(keyTemplate, numAttrs, operation)) {
|
|
PK11_SETATTRS(attrs, operation, &cktrue, sizeof cktrue); attrs++;
|
|
}
|
|
|
|
templateCount = attrs - keyTemplate;
|
|
PR_ASSERT(templateCount <= sizeof(keyTemplate)/sizeof(CK_ATTRIBUTE));
|
|
|
|
/* move the key to a slot that can do the function */
|
|
if (!PK11_DoesMechanism(slot,derive)) {
|
|
/* get a new base key & slot */
|
|
PK11SlotInfo *newSlot = PK11_GetBestSlot(derive, baseKey->cx);
|
|
|
|
if (newSlot == NULL) return NULL;
|
|
|
|
newBaseKey = pk11_CopyToSlot (newSlot, derive, CKA_DERIVE,
|
|
baseKey);
|
|
PK11_FreeSlot(newSlot);
|
|
if (newBaseKey == NULL)
|
|
return NULL;
|
|
baseKey = newBaseKey;
|
|
slot = baseKey->slot;
|
|
}
|
|
|
|
|
|
/* get our key Structure */
|
|
symKey = pk11_CreateSymKey(slot, target, !isPerm, PR_TRUE, baseKey->cx);
|
|
if (symKey == NULL) {
|
|
return NULL;
|
|
}
|
|
|
|
symKey->size = keySize;
|
|
|
|
mechanism.mechanism = derive;
|
|
if (param) {
|
|
mechanism.pParameter = param->data;
|
|
mechanism.ulParameterLen = param->len;
|
|
} else {
|
|
mechanism.pParameter = NULL;
|
|
mechanism.ulParameterLen = 0;
|
|
}
|
|
symKey->origin=PK11_OriginDerive;
|
|
|
|
if (isPerm) {
|
|
session = PK11_GetRWSession(slot);
|
|
} else {
|
|
pk11_EnterKeyMonitor(symKey);
|
|
session = symKey->session;
|
|
}
|
|
if (session == CK_INVALID_SESSION) {
|
|
if (!isPerm)
|
|
pk11_ExitKeyMonitor(symKey);
|
|
crv = CKR_SESSION_HANDLE_INVALID;
|
|
} else {
|
|
crv = PK11_GETTAB(slot)->C_DeriveKey(session, &mechanism,
|
|
baseKey->objectID, keyTemplate, templateCount, &symKey->objectID);
|
|
if (isPerm) {
|
|
PK11_RestoreROSession(slot, session);
|
|
} else {
|
|
pk11_ExitKeyMonitor(symKey);
|
|
}
|
|
}
|
|
if (newBaseKey)
|
|
PK11_FreeSymKey(newBaseKey);
|
|
if (crv != CKR_OK) {
|
|
PK11_FreeSymKey(symKey);
|
|
return NULL;
|
|
}
|
|
return symKey;
|
|
}
|
|
|
|
/* Create a new key by concatenating base and data
|
|
*/
|
|
static PK11SymKey *pk11_ConcatenateBaseAndData(PK11SymKey *base,
|
|
CK_BYTE *data, CK_ULONG dataLen, CK_MECHANISM_TYPE target,
|
|
CK_ATTRIBUTE_TYPE operation)
|
|
{
|
|
CK_KEY_DERIVATION_STRING_DATA mechParams;
|
|
SECItem param;
|
|
|
|
if (base == NULL) {
|
|
PORT_SetError( SEC_ERROR_INVALID_ARGS );
|
|
return NULL;
|
|
}
|
|
|
|
mechParams.pData = data;
|
|
mechParams.ulLen = dataLen;
|
|
param.data = (unsigned char *)&mechParams;
|
|
param.len = sizeof(CK_KEY_DERIVATION_STRING_DATA);
|
|
|
|
return PK11_Derive(base, CKM_CONCATENATE_BASE_AND_DATA,
|
|
¶m, target, operation, 0);
|
|
}
|
|
|
|
/* Create a new key by concatenating base and key
|
|
*/
|
|
static PK11SymKey *pk11_ConcatenateBaseAndKey(PK11SymKey *base,
|
|
PK11SymKey *key, CK_MECHANISM_TYPE target,
|
|
CK_ATTRIBUTE_TYPE operation, CK_ULONG keySize)
|
|
{
|
|
SECItem param;
|
|
|
|
if ((base == NULL) || (key == NULL)) {
|
|
PORT_SetError( SEC_ERROR_INVALID_ARGS );
|
|
return NULL;
|
|
}
|
|
|
|
param.data = (unsigned char *)&(key->objectID);
|
|
param.len = sizeof(CK_OBJECT_HANDLE);
|
|
|
|
return PK11_Derive(base, CKM_CONCATENATE_BASE_AND_KEY,
|
|
¶m, target, operation, keySize);
|
|
}
|
|
|
|
/* Create a new key whose value is the hash of tobehashed.
|
|
* type is the mechanism for the derived key.
|
|
*/
|
|
static PK11SymKey *pk11_HashKeyDerivation(PK11SymKey *toBeHashed,
|
|
CK_MECHANISM_TYPE hashMechanism, CK_MECHANISM_TYPE target,
|
|
CK_ATTRIBUTE_TYPE operation, CK_ULONG keySize)
|
|
{
|
|
return PK11_Derive(toBeHashed, hashMechanism, NULL, target, operation, keySize);
|
|
}
|
|
|
|
/* This function implements the ANSI X9.63 key derivation function
|
|
*/
|
|
static PK11SymKey *pk11_ANSIX963Derive(PK11SymKey *sharedSecret,
|
|
CK_EC_KDF_TYPE kdf, SECItem *sharedData,
|
|
CK_MECHANISM_TYPE target, CK_ATTRIBUTE_TYPE operation,
|
|
CK_ULONG keySize)
|
|
{
|
|
CK_KEY_TYPE keyType;
|
|
CK_MECHANISM_TYPE hashMechanism, mechanismArray[4];
|
|
CK_ULONG derivedKeySize, HashLen, counter, maxCounter, bufferLen;
|
|
CK_ULONG SharedInfoLen;
|
|
CK_BYTE *buffer = NULL;
|
|
PK11SymKey *toBeHashed, *hashOutput;
|
|
PK11SymKey *newSharedSecret = NULL;
|
|
PK11SymKey *oldIntermediateResult, *intermediateResult = NULL;
|
|
|
|
if (sharedSecret == NULL) {
|
|
PORT_SetError( SEC_ERROR_INVALID_ARGS );
|
|
return NULL;
|
|
}
|
|
|
|
switch (kdf) {
|
|
case CKD_SHA1_KDF:
|
|
HashLen = SHA1_LENGTH;
|
|
hashMechanism = CKM_SHA1_KEY_DERIVATION;
|
|
break;
|
|
case CKD_SHA224_KDF:
|
|
HashLen = SHA224_LENGTH;
|
|
hashMechanism = CKM_SHA224_KEY_DERIVATION;
|
|
break;
|
|
case CKD_SHA256_KDF:
|
|
HashLen = SHA256_LENGTH;
|
|
hashMechanism = CKM_SHA256_KEY_DERIVATION;
|
|
break;
|
|
case CKD_SHA384_KDF:
|
|
HashLen = SHA384_LENGTH;
|
|
hashMechanism = CKM_SHA384_KEY_DERIVATION;
|
|
break;
|
|
case CKD_SHA512_KDF:
|
|
HashLen = SHA512_LENGTH;
|
|
hashMechanism = CKM_SHA512_KEY_DERIVATION;
|
|
break;
|
|
default:
|
|
PORT_SetError( SEC_ERROR_INVALID_ARGS );
|
|
return NULL;
|
|
}
|
|
|
|
derivedKeySize = keySize;
|
|
if (derivedKeySize == 0) {
|
|
keyType = PK11_GetKeyType(target,keySize);
|
|
derivedKeySize = pk11_GetPredefinedKeyLength(keyType);
|
|
if (derivedKeySize == 0) {
|
|
derivedKeySize = HashLen;
|
|
}
|
|
}
|
|
|
|
/* Check that key_len isn't too long. The maximum key length could be
|
|
* greatly increased if the code below did not limit the 4-byte counter
|
|
* to a maximum value of 255. */
|
|
if (derivedKeySize > 254 * HashLen) {
|
|
PORT_SetError( SEC_ERROR_INVALID_ARGS );
|
|
return NULL;
|
|
}
|
|
|
|
maxCounter = derivedKeySize / HashLen;
|
|
if (derivedKeySize > maxCounter * HashLen)
|
|
maxCounter++;
|
|
|
|
if ((sharedData == NULL) || (sharedData->data == NULL))
|
|
SharedInfoLen = 0;
|
|
else
|
|
SharedInfoLen = sharedData->len;
|
|
|
|
bufferLen = SharedInfoLen + 4;
|
|
|
|
/* Populate buffer with Counter || sharedData
|
|
* where Counter is 0x00000001. */
|
|
buffer = (unsigned char *)PORT_Alloc(bufferLen);
|
|
if (buffer == NULL) {
|
|
PORT_SetError(SEC_ERROR_NO_MEMORY);
|
|
return NULL;
|
|
}
|
|
|
|
buffer[0] = 0;
|
|
buffer[1] = 0;
|
|
buffer[2] = 0;
|
|
buffer[3] = 1;
|
|
if (SharedInfoLen > 0) {
|
|
PORT_Memcpy(&buffer[4], sharedData->data, SharedInfoLen);
|
|
}
|
|
|
|
/* Look for a slot that supports the mechanisms needed
|
|
* to implement the ANSI X9.63 KDF as well as the
|
|
* target mechanism.
|
|
*/
|
|
mechanismArray[0] = CKM_CONCATENATE_BASE_AND_DATA;
|
|
mechanismArray[1] = hashMechanism;
|
|
mechanismArray[2] = CKM_CONCATENATE_BASE_AND_KEY;
|
|
mechanismArray[3] = target;
|
|
|
|
newSharedSecret = pk11_ForceSlotMultiple(sharedSecret,
|
|
mechanismArray, 4, operation);
|
|
if (newSharedSecret != NULL) {
|
|
sharedSecret = newSharedSecret;
|
|
}
|
|
|
|
for(counter=1; counter <= maxCounter; counter++) {
|
|
/* Concatenate shared_secret and buffer */
|
|
toBeHashed = pk11_ConcatenateBaseAndData(sharedSecret, buffer,
|
|
bufferLen, hashMechanism, operation);
|
|
if (toBeHashed == NULL) {
|
|
goto loser;
|
|
}
|
|
|
|
/* Hash value */
|
|
if (maxCounter == 1) {
|
|
/* In this case the length of the key to be derived is
|
|
* less than or equal to the length of the hash output.
|
|
* So, the output of the hash operation will be the
|
|
* dervied key. */
|
|
hashOutput = pk11_HashKeyDerivation(toBeHashed, hashMechanism,
|
|
target, operation, keySize);
|
|
} else {
|
|
/* In this case, the output of the hash operation will be
|
|
* concatenated with other data to create the derived key. */
|
|
hashOutput = pk11_HashKeyDerivation(toBeHashed, hashMechanism,
|
|
CKM_CONCATENATE_BASE_AND_KEY, operation, 0);
|
|
}
|
|
PK11_FreeSymKey(toBeHashed);
|
|
if (hashOutput == NULL) {
|
|
goto loser;
|
|
}
|
|
|
|
/* Append result to intermediate result, if necessary */
|
|
oldIntermediateResult = intermediateResult;
|
|
|
|
if (oldIntermediateResult == NULL) {
|
|
intermediateResult = hashOutput;
|
|
} else {
|
|
if (counter == maxCounter) {
|
|
/* This is the final concatenation, and so the output
|
|
* will be the derived key. */
|
|
intermediateResult =
|
|
pk11_ConcatenateBaseAndKey(oldIntermediateResult,
|
|
hashOutput, target, operation, keySize);
|
|
} else {
|
|
/* The output of this concatenation will be concatenated
|
|
* with other data to create the derived key. */
|
|
intermediateResult =
|
|
pk11_ConcatenateBaseAndKey(oldIntermediateResult,
|
|
hashOutput, CKM_CONCATENATE_BASE_AND_KEY,
|
|
operation, 0);
|
|
}
|
|
|
|
PK11_FreeSymKey(hashOutput);
|
|
PK11_FreeSymKey(oldIntermediateResult);
|
|
if (intermediateResult == NULL) {
|
|
goto loser;
|
|
}
|
|
}
|
|
|
|
/* Increment counter (assumes maxCounter < 255) */
|
|
buffer[3]++;
|
|
}
|
|
|
|
PORT_ZFree(buffer, bufferLen);
|
|
if (newSharedSecret != NULL)
|
|
PK11_FreeSymKey(newSharedSecret);
|
|
return intermediateResult;
|
|
|
|
loser:
|
|
if (buffer != NULL)
|
|
PORT_ZFree(buffer, bufferLen);
|
|
if (newSharedSecret != NULL)
|
|
PK11_FreeSymKey(newSharedSecret);
|
|
if (intermediateResult != NULL)
|
|
PK11_FreeSymKey(intermediateResult);
|
|
return NULL;
|
|
}
|
|
|
|
/*
|
|
* This Generates a wrapping key based on a privateKey, publicKey, and two
|
|
* random numbers. For Mail usage RandomB should be NULL. In the Sender's
|
|
* case RandomA is generate, outherwize it is passed.
|
|
*/
|
|
static unsigned char *rb_email = NULL;
|
|
|
|
PK11SymKey *
|
|
PK11_PubDerive(SECKEYPrivateKey *privKey, SECKEYPublicKey *pubKey,
|
|
PRBool isSender, SECItem *randomA, SECItem *randomB,
|
|
CK_MECHANISM_TYPE derive, CK_MECHANISM_TYPE target,
|
|
CK_ATTRIBUTE_TYPE operation, int keySize,void *wincx)
|
|
{
|
|
PK11SlotInfo *slot = privKey->pkcs11Slot;
|
|
CK_MECHANISM mechanism;
|
|
PK11SymKey *symKey;
|
|
CK_RV crv;
|
|
|
|
|
|
if (rb_email == NULL) {
|
|
rb_email = PORT_ZAlloc(128);
|
|
if (rb_email == NULL) {
|
|
return NULL;
|
|
}
|
|
rb_email[127] = 1;
|
|
}
|
|
|
|
/* get our key Structure */
|
|
symKey = pk11_CreateSymKey(slot, target, PR_TRUE, PR_TRUE, wincx);
|
|
if (symKey == NULL) {
|
|
return NULL;
|
|
}
|
|
|
|
symKey->origin = PK11_OriginDerive;
|
|
|
|
switch (privKey->keyType) {
|
|
case rsaKey:
|
|
case rsaPssKey:
|
|
case rsaOaepKey:
|
|
case nullKey:
|
|
PORT_SetError(SEC_ERROR_BAD_KEY);
|
|
break;
|
|
case dsaKey:
|
|
case keaKey:
|
|
case fortezzaKey:
|
|
{
|
|
CK_KEA_DERIVE_PARAMS param;
|
|
param.isSender = (CK_BBOOL) isSender;
|
|
param.ulRandomLen = randomA->len;
|
|
param.pRandomA = randomA->data;
|
|
param.pRandomB = rb_email;
|
|
if (randomB)
|
|
param.pRandomB = randomB->data;
|
|
if (pubKey->keyType == fortezzaKey) {
|
|
param.ulPublicDataLen = pubKey->u.fortezza.KEAKey.len;
|
|
param.pPublicData = pubKey->u.fortezza.KEAKey.data;
|
|
} else {
|
|
/* assert type == keaKey */
|
|
/* XXX change to match key key types */
|
|
param.ulPublicDataLen = pubKey->u.fortezza.KEAKey.len;
|
|
param.pPublicData = pubKey->u.fortezza.KEAKey.data;
|
|
}
|
|
|
|
mechanism.mechanism = derive;
|
|
mechanism.pParameter = ¶m;
|
|
mechanism.ulParameterLen = sizeof(param);
|
|
|
|
/* get a new symKey structure */
|
|
pk11_EnterKeyMonitor(symKey);
|
|
crv=PK11_GETTAB(slot)->C_DeriveKey(symKey->session, &mechanism,
|
|
privKey->pkcs11ID, NULL, 0, &symKey->objectID);
|
|
pk11_ExitKeyMonitor(symKey);
|
|
if (crv == CKR_OK) return symKey;
|
|
PORT_SetError( PK11_MapError(crv) );
|
|
}
|
|
break;
|
|
case dhKey:
|
|
{
|
|
CK_BBOOL cktrue = CK_TRUE;
|
|
CK_OBJECT_CLASS keyClass = CKO_SECRET_KEY;
|
|
CK_KEY_TYPE keyType = CKK_GENERIC_SECRET;
|
|
CK_ULONG key_size = 0;
|
|
CK_ATTRIBUTE keyTemplate[4];
|
|
int templateCount;
|
|
CK_ATTRIBUTE *attrs = keyTemplate;
|
|
|
|
if (pubKey->keyType != dhKey) {
|
|
PORT_SetError(SEC_ERROR_BAD_KEY);
|
|
break;
|
|
}
|
|
|
|
PK11_SETATTRS(attrs, CKA_CLASS, &keyClass, sizeof(keyClass));
|
|
attrs++;
|
|
PK11_SETATTRS(attrs, CKA_KEY_TYPE, &keyType, sizeof(keyType));
|
|
attrs++;
|
|
PK11_SETATTRS(attrs, operation, &cktrue, 1); attrs++;
|
|
PK11_SETATTRS(attrs, CKA_VALUE_LEN, &key_size, sizeof(key_size));
|
|
attrs++;
|
|
templateCount = attrs - keyTemplate;
|
|
PR_ASSERT(templateCount <= sizeof(keyTemplate)/sizeof(CK_ATTRIBUTE));
|
|
|
|
keyType = PK11_GetKeyType(target,keySize);
|
|
key_size = keySize;
|
|
symKey->size = keySize;
|
|
if (key_size == 0) templateCount--;
|
|
|
|
mechanism.mechanism = derive;
|
|
|
|
/* we can undefine these when we define diffie-helman keys */
|
|
|
|
mechanism.pParameter = pubKey->u.dh.publicValue.data;
|
|
mechanism.ulParameterLen = pubKey->u.dh.publicValue.len;
|
|
|
|
pk11_EnterKeyMonitor(symKey);
|
|
crv = PK11_GETTAB(slot)->C_DeriveKey(symKey->session, &mechanism,
|
|
privKey->pkcs11ID, keyTemplate, templateCount, &symKey->objectID);
|
|
pk11_ExitKeyMonitor(symKey);
|
|
if (crv == CKR_OK) return symKey;
|
|
PORT_SetError( PK11_MapError(crv) );
|
|
}
|
|
break;
|
|
case ecKey:
|
|
{
|
|
CK_BBOOL cktrue = CK_TRUE;
|
|
CK_OBJECT_CLASS keyClass = CKO_SECRET_KEY;
|
|
CK_KEY_TYPE keyType = CKK_GENERIC_SECRET;
|
|
CK_ULONG key_size = 0;
|
|
CK_ATTRIBUTE keyTemplate[4];
|
|
int templateCount;
|
|
CK_ATTRIBUTE *attrs = keyTemplate;
|
|
CK_ECDH1_DERIVE_PARAMS *mechParams = NULL;
|
|
|
|
if (pubKey->keyType != ecKey) {
|
|
PORT_SetError(SEC_ERROR_BAD_KEY);
|
|
break;
|
|
}
|
|
|
|
PK11_SETATTRS(attrs, CKA_CLASS, &keyClass, sizeof(keyClass));
|
|
attrs++;
|
|
PK11_SETATTRS(attrs, CKA_KEY_TYPE, &keyType, sizeof(keyType));
|
|
attrs++;
|
|
PK11_SETATTRS(attrs, operation, &cktrue, 1); attrs++;
|
|
PK11_SETATTRS(attrs, CKA_VALUE_LEN, &key_size, sizeof(key_size));
|
|
attrs++;
|
|
templateCount = attrs - keyTemplate;
|
|
PR_ASSERT(templateCount <= sizeof(keyTemplate)/sizeof(CK_ATTRIBUTE));
|
|
|
|
keyType = PK11_GetKeyType(target,keySize);
|
|
key_size = keySize;
|
|
if (key_size == 0) {
|
|
if ((key_size = pk11_GetPredefinedKeyLength(keyType))) {
|
|
templateCount --;
|
|
} else {
|
|
/* sigh, some tokens can't figure this out and require
|
|
* CKA_VALUE_LEN to be set */
|
|
key_size = SHA1_LENGTH;
|
|
}
|
|
}
|
|
symKey->size = key_size;
|
|
|
|
mechParams = PORT_ZNew(CK_ECDH1_DERIVE_PARAMS);
|
|
mechParams->kdf = CKD_SHA1_KDF;
|
|
mechParams->ulSharedDataLen = 0;
|
|
mechParams->pSharedData = NULL;
|
|
mechParams->ulPublicDataLen = pubKey->u.ec.publicValue.len;
|
|
mechParams->pPublicData = pubKey->u.ec.publicValue.data;
|
|
|
|
mechanism.mechanism = derive;
|
|
mechanism.pParameter = mechParams;
|
|
mechanism.ulParameterLen = sizeof(CK_ECDH1_DERIVE_PARAMS);
|
|
|
|
pk11_EnterKeyMonitor(symKey);
|
|
crv = PK11_GETTAB(slot)->C_DeriveKey(symKey->session,
|
|
&mechanism, privKey->pkcs11ID, keyTemplate,
|
|
templateCount, &symKey->objectID);
|
|
pk11_ExitKeyMonitor(symKey);
|
|
|
|
/* old PKCS #11 spec was ambiguous on what needed to be passed,
|
|
* try this again with and encoded public key */
|
|
if (crv != CKR_OK) {
|
|
SECItem *pubValue = SEC_ASN1EncodeItem(NULL, NULL,
|
|
&pubKey->u.ec.publicValue,
|
|
SEC_ASN1_GET(SEC_OctetStringTemplate));
|
|
if (pubValue == NULL) {
|
|
PORT_ZFree(mechParams, sizeof(CK_ECDH1_DERIVE_PARAMS));
|
|
break;
|
|
}
|
|
mechParams->ulPublicDataLen = pubValue->len;
|
|
mechParams->pPublicData = pubValue->data;
|
|
|
|
pk11_EnterKeyMonitor(symKey);
|
|
crv = PK11_GETTAB(slot)->C_DeriveKey(symKey->session,
|
|
&mechanism, privKey->pkcs11ID, keyTemplate,
|
|
templateCount, &symKey->objectID);
|
|
pk11_ExitKeyMonitor(symKey);
|
|
|
|
SECITEM_FreeItem(pubValue,PR_TRUE);
|
|
}
|
|
|
|
PORT_ZFree(mechParams, sizeof(CK_ECDH1_DERIVE_PARAMS));
|
|
|
|
if (crv == CKR_OK) return symKey;
|
|
PORT_SetError( PK11_MapError(crv) );
|
|
}
|
|
}
|
|
|
|
PK11_FreeSymKey(symKey);
|
|
return NULL;
|
|
}
|
|
|
|
/* Returns the size of the public key, or 0 if there
|
|
* is an error. */
|
|
static CK_ULONG
|
|
pk11_ECPubKeySize(SECItem *publicValue)
|
|
{
|
|
if (publicValue->data[0] == 0x04) {
|
|
/* key encoded in uncompressed form */
|
|
return((publicValue->len - 1)/2);
|
|
} else if ( (publicValue->data[0] == 0x02) ||
|
|
(publicValue->data[0] == 0x03)) {
|
|
/* key encoded in compressed form */
|
|
return(publicValue->len - 1);
|
|
}
|
|
/* key encoding not recognized */
|
|
return(0);
|
|
}
|
|
|
|
static PK11SymKey *
|
|
pk11_PubDeriveECKeyWithKDF(
|
|
SECKEYPrivateKey *privKey, SECKEYPublicKey *pubKey,
|
|
PRBool isSender, SECItem *randomA, SECItem *randomB,
|
|
CK_MECHANISM_TYPE derive, CK_MECHANISM_TYPE target,
|
|
CK_ATTRIBUTE_TYPE operation, int keySize,
|
|
CK_ULONG kdf, SECItem *sharedData, void *wincx)
|
|
{
|
|
PK11SlotInfo *slot = privKey->pkcs11Slot;
|
|
PK11SymKey *symKey;
|
|
PK11SymKey *SharedSecret;
|
|
CK_MECHANISM mechanism;
|
|
CK_RV crv;
|
|
CK_BBOOL cktrue = CK_TRUE;
|
|
CK_OBJECT_CLASS keyClass = CKO_SECRET_KEY;
|
|
CK_KEY_TYPE keyType = CKK_GENERIC_SECRET;
|
|
CK_ULONG key_size = 0;
|
|
CK_ATTRIBUTE keyTemplate[4];
|
|
int templateCount;
|
|
CK_ATTRIBUTE *attrs = keyTemplate;
|
|
CK_ECDH1_DERIVE_PARAMS *mechParams = NULL;
|
|
|
|
if (pubKey->keyType != ecKey) {
|
|
PORT_SetError(SEC_ERROR_BAD_KEY);
|
|
return NULL;
|
|
}
|
|
if ((kdf != CKD_NULL) && (kdf != CKD_SHA1_KDF) &&
|
|
(kdf != CKD_SHA224_KDF) && (kdf != CKD_SHA256_KDF) &&
|
|
(kdf != CKD_SHA384_KDF) && (kdf != CKD_SHA512_KDF)) {
|
|
PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
|
|
return NULL;
|
|
}
|
|
|
|
/* get our key Structure */
|
|
symKey = pk11_CreateSymKey(slot, target, PR_TRUE, PR_TRUE, wincx);
|
|
if (symKey == NULL) {
|
|
return NULL;
|
|
}
|
|
|
|
symKey->origin = PK11_OriginDerive;
|
|
|
|
PK11_SETATTRS(attrs, CKA_CLASS, &keyClass, sizeof(keyClass)); attrs++;
|
|
PK11_SETATTRS(attrs, CKA_KEY_TYPE, &keyType, sizeof(keyType)); attrs++;
|
|
PK11_SETATTRS(attrs, operation, &cktrue, 1); attrs++;
|
|
PK11_SETATTRS(attrs, CKA_VALUE_LEN, &key_size, sizeof(key_size)); attrs++;
|
|
templateCount = attrs - keyTemplate;
|
|
PR_ASSERT(templateCount <= sizeof(keyTemplate)/sizeof(CK_ATTRIBUTE));
|
|
|
|
keyType = PK11_GetKeyType(target,keySize);
|
|
key_size = keySize;
|
|
if (key_size == 0) {
|
|
if ((key_size = pk11_GetPredefinedKeyLength(keyType))) {
|
|
templateCount --;
|
|
} else {
|
|
/* sigh, some tokens can't figure this out and require
|
|
* CKA_VALUE_LEN to be set */
|
|
switch (kdf) {
|
|
case CKD_NULL:
|
|
key_size = pk11_ECPubKeySize(&pubKey->u.ec.publicValue);
|
|
if (key_size == 0) {
|
|
PK11_FreeSymKey(symKey);
|
|
return NULL;
|
|
}
|
|
break;
|
|
case CKD_SHA1_KDF:
|
|
key_size = SHA1_LENGTH;
|
|
break;
|
|
case CKD_SHA224_KDF:
|
|
key_size = SHA224_LENGTH;
|
|
break;
|
|
case CKD_SHA256_KDF:
|
|
key_size = SHA256_LENGTH;
|
|
break;
|
|
case CKD_SHA384_KDF:
|
|
key_size = SHA384_LENGTH;
|
|
break;
|
|
case CKD_SHA512_KDF:
|
|
key_size = SHA512_LENGTH;
|
|
break;
|
|
default:
|
|
PORT_Assert(!"Invalid CKD");
|
|
PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
|
|
return NULL;
|
|
}
|
|
}
|
|
}
|
|
symKey->size = key_size;
|
|
|
|
mechParams = PORT_ZNew(CK_ECDH1_DERIVE_PARAMS);
|
|
if (!mechParams) {
|
|
PK11_FreeSymKey(symKey);
|
|
return NULL;
|
|
}
|
|
mechParams->kdf = kdf;
|
|
if (sharedData == NULL) {
|
|
mechParams->ulSharedDataLen = 0;
|
|
mechParams->pSharedData = NULL;
|
|
} else {
|
|
mechParams->ulSharedDataLen = sharedData->len;
|
|
mechParams->pSharedData = sharedData->data;
|
|
}
|
|
mechParams->ulPublicDataLen = pubKey->u.ec.publicValue.len;
|
|
mechParams->pPublicData = pubKey->u.ec.publicValue.data;
|
|
|
|
mechanism.mechanism = derive;
|
|
mechanism.pParameter = mechParams;
|
|
mechanism.ulParameterLen = sizeof(CK_ECDH1_DERIVE_PARAMS);
|
|
|
|
pk11_EnterKeyMonitor(symKey);
|
|
crv = PK11_GETTAB(slot)->C_DeriveKey(symKey->session, &mechanism,
|
|
privKey->pkcs11ID, keyTemplate, templateCount, &symKey->objectID);
|
|
pk11_ExitKeyMonitor(symKey);
|
|
|
|
/* old PKCS #11 spec was ambiguous on what needed to be passed,
|
|
* try this again with an encoded public key */
|
|
if (crv != CKR_OK) {
|
|
SECItem *pubValue = SEC_ASN1EncodeItem(NULL, NULL,
|
|
&pubKey->u.ec.publicValue,
|
|
SEC_ASN1_GET(SEC_OctetStringTemplate));
|
|
if (pubValue == NULL) {
|
|
goto loser;
|
|
}
|
|
mechParams->ulPublicDataLen = pubValue->len;
|
|
mechParams->pPublicData = pubValue->data;
|
|
|
|
pk11_EnterKeyMonitor(symKey);
|
|
crv = PK11_GETTAB(slot)->C_DeriveKey(symKey->session,
|
|
&mechanism, privKey->pkcs11ID, keyTemplate,
|
|
templateCount, &symKey->objectID);
|
|
pk11_ExitKeyMonitor(symKey);
|
|
|
|
if ((crv != CKR_OK) && (kdf != CKD_NULL)) {
|
|
/* Some PKCS #11 libraries cannot perform the key derivation
|
|
* function. So, try calling C_DeriveKey with CKD_NULL and then
|
|
* performing the KDF separately.
|
|
*/
|
|
CK_ULONG derivedKeySize = key_size;
|
|
|
|
keyType = CKK_GENERIC_SECRET;
|
|
key_size = pk11_ECPubKeySize(&pubKey->u.ec.publicValue);
|
|
if (key_size == 0) {
|
|
SECITEM_FreeItem(pubValue,PR_TRUE);
|
|
goto loser;
|
|
}
|
|
SharedSecret = symKey;
|
|
SharedSecret->size = key_size;
|
|
|
|
mechParams->kdf = CKD_NULL;
|
|
mechParams->ulSharedDataLen = 0;
|
|
mechParams->pSharedData = NULL;
|
|
mechParams->ulPublicDataLen = pubKey->u.ec.publicValue.len;
|
|
mechParams->pPublicData = pubKey->u.ec.publicValue.data;
|
|
|
|
pk11_EnterKeyMonitor(SharedSecret);
|
|
crv = PK11_GETTAB(slot)->C_DeriveKey(SharedSecret->session,
|
|
&mechanism, privKey->pkcs11ID, keyTemplate,
|
|
templateCount, &SharedSecret->objectID);
|
|
pk11_ExitKeyMonitor(SharedSecret);
|
|
|
|
if (crv != CKR_OK) {
|
|
/* old PKCS #11 spec was ambiguous on what needed to be passed,
|
|
* try this one final time with an encoded public key */
|
|
mechParams->ulPublicDataLen = pubValue->len;
|
|
mechParams->pPublicData = pubValue->data;
|
|
|
|
pk11_EnterKeyMonitor(SharedSecret);
|
|
crv = PK11_GETTAB(slot)->C_DeriveKey(SharedSecret->session,
|
|
&mechanism, privKey->pkcs11ID, keyTemplate,
|
|
templateCount, &SharedSecret->objectID);
|
|
pk11_ExitKeyMonitor(SharedSecret);
|
|
}
|
|
|
|
/* Perform KDF. */
|
|
if (crv == CKR_OK) {
|
|
symKey = pk11_ANSIX963Derive(SharedSecret, kdf,
|
|
sharedData, target, operation,
|
|
derivedKeySize);
|
|
PK11_FreeSymKey(SharedSecret);
|
|
if (symKey == NULL) {
|
|
SECITEM_FreeItem(pubValue,PR_TRUE);
|
|
PORT_ZFree(mechParams, sizeof(CK_ECDH1_DERIVE_PARAMS));
|
|
return NULL;
|
|
}
|
|
}
|
|
}
|
|
SECITEM_FreeItem(pubValue,PR_TRUE);
|
|
}
|
|
|
|
loser:
|
|
PORT_ZFree(mechParams, sizeof(CK_ECDH1_DERIVE_PARAMS));
|
|
|
|
if (crv != CKR_OK) {
|
|
PK11_FreeSymKey(symKey);
|
|
symKey = NULL;
|
|
PORT_SetError( PK11_MapError(crv) );
|
|
}
|
|
return symKey;
|
|
}
|
|
|
|
PK11SymKey *
|
|
PK11_PubDeriveWithKDF(SECKEYPrivateKey *privKey, SECKEYPublicKey *pubKey,
|
|
PRBool isSender, SECItem *randomA, SECItem *randomB,
|
|
CK_MECHANISM_TYPE derive, CK_MECHANISM_TYPE target,
|
|
CK_ATTRIBUTE_TYPE operation, int keySize,
|
|
CK_ULONG kdf, SECItem *sharedData, void *wincx)
|
|
{
|
|
|
|
switch (privKey->keyType) {
|
|
case rsaKey:
|
|
case nullKey:
|
|
case dsaKey:
|
|
case keaKey:
|
|
case fortezzaKey:
|
|
case dhKey:
|
|
return PK11_PubDerive(privKey, pubKey, isSender, randomA, randomB,
|
|
derive, target, operation, keySize, wincx);
|
|
case ecKey:
|
|
return pk11_PubDeriveECKeyWithKDF( privKey, pubKey, isSender,
|
|
randomA, randomB, derive, target, operation, keySize,
|
|
kdf, sharedData, wincx);
|
|
default:
|
|
PORT_SetError(SEC_ERROR_BAD_KEY);
|
|
break;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
/*
|
|
* this little function uses the Decrypt function to unwrap a key, just in
|
|
* case we are having problem with unwrap. NOTE: The key size may
|
|
* not be preserved properly for some algorithms!
|
|
*/
|
|
static PK11SymKey *
|
|
pk11_HandUnwrap(PK11SlotInfo *slot, CK_OBJECT_HANDLE wrappingKey,
|
|
CK_MECHANISM *mech, SECItem *inKey, CK_MECHANISM_TYPE target,
|
|
CK_ATTRIBUTE *keyTemplate, unsigned int templateCount,
|
|
int key_size, void * wincx, CK_RV *crvp, PRBool isPerm)
|
|
{
|
|
CK_ULONG len;
|
|
SECItem outKey;
|
|
PK11SymKey *symKey;
|
|
CK_RV crv;
|
|
PRBool owner = PR_TRUE;
|
|
CK_SESSION_HANDLE session;
|
|
|
|
/* remove any VALUE_LEN parameters */
|
|
if (keyTemplate[templateCount-1].type == CKA_VALUE_LEN) {
|
|
templateCount--;
|
|
}
|
|
|
|
/* keys are almost always aligned, but if we get this far,
|
|
* we've gone above and beyond anyway... */
|
|
outKey.data = (unsigned char*)PORT_Alloc(inKey->len);
|
|
if (outKey.data == NULL) {
|
|
PORT_SetError( SEC_ERROR_NO_MEMORY );
|
|
if (crvp) *crvp = CKR_HOST_MEMORY;
|
|
return NULL;
|
|
}
|
|
len = inKey->len;
|
|
|
|
/* use NULL IV's for wrapping */
|
|
session = pk11_GetNewSession(slot,&owner);
|
|
if (!owner || !(slot->isThreadSafe)) PK11_EnterSlotMonitor(slot);
|
|
crv = PK11_GETTAB(slot)->C_DecryptInit(session,mech,wrappingKey);
|
|
if (crv != CKR_OK) {
|
|
if (!owner || !(slot->isThreadSafe)) PK11_ExitSlotMonitor(slot);
|
|
pk11_CloseSession(slot,session,owner);
|
|
PORT_Free(outKey.data);
|
|
PORT_SetError( PK11_MapError(crv) );
|
|
if (crvp) *crvp =crv;
|
|
return NULL;
|
|
}
|
|
crv = PK11_GETTAB(slot)->C_Decrypt(session,inKey->data,inKey->len,
|
|
outKey.data, &len);
|
|
if (!owner || !(slot->isThreadSafe)) PK11_ExitSlotMonitor(slot);
|
|
pk11_CloseSession(slot,session,owner);
|
|
if (crv != CKR_OK) {
|
|
PORT_Free(outKey.data);
|
|
PORT_SetError( PK11_MapError(crv) );
|
|
if (crvp) *crvp =crv;
|
|
return NULL;
|
|
}
|
|
|
|
outKey.len = (key_size == 0) ? len : key_size;
|
|
outKey.type = siBuffer;
|
|
|
|
if (PK11_DoesMechanism(slot,target)) {
|
|
symKey = pk11_ImportSymKeyWithTempl(slot, target, PK11_OriginUnwrap,
|
|
isPerm, keyTemplate,
|
|
templateCount, &outKey, wincx);
|
|
} else {
|
|
slot = PK11_GetBestSlot(target,wincx);
|
|
if (slot == NULL) {
|
|
PORT_SetError( SEC_ERROR_NO_MODULE );
|
|
PORT_Free(outKey.data);
|
|
if (crvp) *crvp = CKR_DEVICE_ERROR;
|
|
return NULL;
|
|
}
|
|
symKey = pk11_ImportSymKeyWithTempl(slot, target, PK11_OriginUnwrap,
|
|
isPerm, keyTemplate,
|
|
templateCount, &outKey, wincx);
|
|
PK11_FreeSlot(slot);
|
|
}
|
|
PORT_Free(outKey.data);
|
|
|
|
if (crvp) *crvp = symKey? CKR_OK : CKR_DEVICE_ERROR;
|
|
return symKey;
|
|
}
|
|
|
|
/*
|
|
* The wrap/unwrap function is pretty much the same for private and
|
|
* public keys. It's just getting the Object ID and slot right. This is
|
|
* the combined unwrap function.
|
|
*/
|
|
static PK11SymKey *
|
|
pk11_AnyUnwrapKey(PK11SlotInfo *slot, CK_OBJECT_HANDLE wrappingKey,
|
|
CK_MECHANISM_TYPE wrapType, SECItem *param, SECItem *wrappedKey,
|
|
CK_MECHANISM_TYPE target, CK_ATTRIBUTE_TYPE operation, int keySize,
|
|
void *wincx, CK_ATTRIBUTE *userAttr, unsigned int numAttrs, PRBool isPerm)
|
|
{
|
|
PK11SymKey * symKey;
|
|
SECItem * param_free = NULL;
|
|
CK_BBOOL cktrue = CK_TRUE;
|
|
CK_OBJECT_CLASS keyClass = CKO_SECRET_KEY;
|
|
CK_KEY_TYPE keyType = CKK_GENERIC_SECRET;
|
|
CK_ULONG valueLen = 0;
|
|
CK_MECHANISM mechanism;
|
|
CK_SESSION_HANDLE rwsession;
|
|
CK_RV crv;
|
|
CK_MECHANISM_INFO mechanism_info;
|
|
#define MAX_ADD_ATTRS 4
|
|
CK_ATTRIBUTE keyTemplate[MAX_TEMPL_ATTRS + MAX_ADD_ATTRS];
|
|
#undef MAX_ADD_ATTRS
|
|
CK_ATTRIBUTE * attrs = keyTemplate;
|
|
unsigned int templateCount;
|
|
|
|
if (numAttrs > MAX_TEMPL_ATTRS) {
|
|
PORT_SetError(SEC_ERROR_INVALID_ARGS);
|
|
return NULL;
|
|
}
|
|
|
|
/* first copy caller attributes in. */
|
|
for (templateCount = 0; templateCount < numAttrs; ++templateCount) {
|
|
*attrs++ = *userAttr++;
|
|
}
|
|
|
|
/* We only add the following attributes to the template if the caller
|
|
** didn't already supply them.
|
|
*/
|
|
if (!pk11_FindAttrInTemplate(keyTemplate, numAttrs, CKA_CLASS)) {
|
|
PK11_SETATTRS(attrs, CKA_CLASS, &keyClass, sizeof keyClass);
|
|
attrs++;
|
|
}
|
|
if (!pk11_FindAttrInTemplate(keyTemplate, numAttrs, CKA_KEY_TYPE)) {
|
|
keyType = PK11_GetKeyType(target, keySize);
|
|
PK11_SETATTRS(attrs, CKA_KEY_TYPE, &keyType, sizeof keyType );
|
|
attrs++;
|
|
}
|
|
if ((operation != CKA_FLAGS_ONLY) &&
|
|
!pk11_FindAttrInTemplate(keyTemplate, numAttrs, operation)) {
|
|
PK11_SETATTRS(attrs, operation, &cktrue, 1); attrs++;
|
|
}
|
|
|
|
/*
|
|
* must be last in case we need to use this template to import the key
|
|
*/
|
|
if (keySize > 0 &&
|
|
!pk11_FindAttrInTemplate(keyTemplate, numAttrs, CKA_VALUE_LEN)) {
|
|
valueLen = (CK_ULONG)keySize;
|
|
PK11_SETATTRS(attrs, CKA_VALUE_LEN, &valueLen, sizeof valueLen);
|
|
attrs++;
|
|
}
|
|
|
|
templateCount = attrs - keyTemplate;
|
|
PR_ASSERT(templateCount <= sizeof(keyTemplate)/sizeof(CK_ATTRIBUTE));
|
|
|
|
|
|
/* find out if we can do wrap directly. Because the RSA case if *very*
|
|
* common, cache the results for it. */
|
|
if ((wrapType == CKM_RSA_PKCS) && (slot->hasRSAInfo)) {
|
|
mechanism_info.flags = slot->RSAInfoFlags;
|
|
} else {
|
|
if (!slot->isThreadSafe) PK11_EnterSlotMonitor(slot);
|
|
crv = PK11_GETTAB(slot)->C_GetMechanismInfo(slot->slotID,wrapType,
|
|
&mechanism_info);
|
|
if (!slot->isThreadSafe) PK11_ExitSlotMonitor(slot);
|
|
if (crv != CKR_OK) {
|
|
mechanism_info.flags = 0;
|
|
}
|
|
if (wrapType == CKM_RSA_PKCS) {
|
|
slot->RSAInfoFlags = mechanism_info.flags;
|
|
slot->hasRSAInfo = PR_TRUE;
|
|
}
|
|
}
|
|
|
|
/* initialize the mechanism structure */
|
|
mechanism.mechanism = wrapType;
|
|
/* use NULL IV's for wrapping */
|
|
if (param == NULL)
|
|
param = param_free = PK11_ParamFromIV(wrapType,NULL);
|
|
if (param) {
|
|
mechanism.pParameter = param->data;
|
|
mechanism.ulParameterLen = param->len;
|
|
} else {
|
|
mechanism.pParameter = NULL;
|
|
mechanism.ulParameterLen = 0;
|
|
}
|
|
|
|
if ((mechanism_info.flags & CKF_DECRYPT)
|
|
&& !PK11_DoesMechanism(slot,target)) {
|
|
symKey = pk11_HandUnwrap(slot, wrappingKey, &mechanism, wrappedKey,
|
|
target, keyTemplate, templateCount, keySize,
|
|
wincx, &crv, isPerm);
|
|
if (symKey) {
|
|
if (param_free) SECITEM_FreeItem(param_free,PR_TRUE);
|
|
return symKey;
|
|
}
|
|
/*
|
|
* if the RSA OP simply failed, don't try to unwrap again
|
|
* with this module.
|
|
*/
|
|
if (crv == CKR_DEVICE_ERROR){
|
|
if (param_free) SECITEM_FreeItem(param_free,PR_TRUE);
|
|
return NULL;
|
|
}
|
|
/* fall through, maybe they incorrectly set CKF_DECRYPT */
|
|
}
|
|
|
|
/* get our key Structure */
|
|
symKey = pk11_CreateSymKey(slot, target, !isPerm, PR_TRUE, wincx);
|
|
if (symKey == NULL) {
|
|
if (param_free) SECITEM_FreeItem(param_free,PR_TRUE);
|
|
return NULL;
|
|
}
|
|
|
|
symKey->size = keySize;
|
|
symKey->origin = PK11_OriginUnwrap;
|
|
|
|
if (isPerm) {
|
|
rwsession = PK11_GetRWSession(slot);
|
|
} else {
|
|
pk11_EnterKeyMonitor(symKey);
|
|
rwsession = symKey->session;
|
|
}
|
|
PORT_Assert(rwsession != CK_INVALID_SESSION);
|
|
if (rwsession == CK_INVALID_SESSION)
|
|
crv = CKR_SESSION_HANDLE_INVALID;
|
|
else
|
|
crv = PK11_GETTAB(slot)->C_UnwrapKey(rwsession,&mechanism,wrappingKey,
|
|
wrappedKey->data, wrappedKey->len, keyTemplate, templateCount,
|
|
&symKey->objectID);
|
|
if (isPerm) {
|
|
if (rwsession != CK_INVALID_SESSION)
|
|
PK11_RestoreROSession(slot, rwsession);
|
|
} else {
|
|
pk11_ExitKeyMonitor(symKey);
|
|
}
|
|
if (param_free) SECITEM_FreeItem(param_free,PR_TRUE);
|
|
if (crv != CKR_OK) {
|
|
PK11_FreeSymKey(symKey);
|
|
symKey = NULL;
|
|
if (crv != CKR_DEVICE_ERROR) {
|
|
/* try hand Unwrapping */
|
|
symKey = pk11_HandUnwrap(slot, wrappingKey, &mechanism, wrappedKey,
|
|
target, keyTemplate, templateCount,
|
|
keySize, wincx, NULL, isPerm);
|
|
}
|
|
}
|
|
|
|
return symKey;
|
|
}
|
|
|
|
/* use a symetric key to unwrap another symetric key */
|
|
PK11SymKey *
|
|
PK11_UnwrapSymKey( PK11SymKey *wrappingKey, CK_MECHANISM_TYPE wrapType,
|
|
SECItem *param, SECItem *wrappedKey,
|
|
CK_MECHANISM_TYPE target, CK_ATTRIBUTE_TYPE operation,
|
|
int keySize)
|
|
{
|
|
return pk11_AnyUnwrapKey(wrappingKey->slot, wrappingKey->objectID,
|
|
wrapType, param, wrappedKey, target, operation, keySize,
|
|
wrappingKey->cx, NULL, 0, PR_FALSE);
|
|
}
|
|
|
|
/* use a symetric key to unwrap another symetric key */
|
|
PK11SymKey *
|
|
PK11_UnwrapSymKeyWithFlags(PK11SymKey *wrappingKey, CK_MECHANISM_TYPE wrapType,
|
|
SECItem *param, SECItem *wrappedKey,
|
|
CK_MECHANISM_TYPE target, CK_ATTRIBUTE_TYPE operation,
|
|
int keySize, CK_FLAGS flags)
|
|
{
|
|
CK_BBOOL ckTrue = CK_TRUE;
|
|
CK_ATTRIBUTE keyTemplate[MAX_TEMPL_ATTRS];
|
|
unsigned int templateCount;
|
|
|
|
templateCount = pk11_OpFlagsToAttributes(flags, keyTemplate, &ckTrue);
|
|
return pk11_AnyUnwrapKey(wrappingKey->slot, wrappingKey->objectID,
|
|
wrapType, param, wrappedKey, target, operation, keySize,
|
|
wrappingKey->cx, keyTemplate, templateCount, PR_FALSE);
|
|
}
|
|
|
|
PK11SymKey *
|
|
PK11_UnwrapSymKeyWithFlagsPerm(PK11SymKey *wrappingKey,
|
|
CK_MECHANISM_TYPE wrapType,
|
|
SECItem *param, SECItem *wrappedKey,
|
|
CK_MECHANISM_TYPE target, CK_ATTRIBUTE_TYPE operation,
|
|
int keySize, CK_FLAGS flags, PRBool isPerm)
|
|
{
|
|
CK_BBOOL cktrue = CK_TRUE;
|
|
CK_ATTRIBUTE keyTemplate[MAX_TEMPL_ATTRS];
|
|
CK_ATTRIBUTE *attrs;
|
|
unsigned int templateCount;
|
|
|
|
attrs = keyTemplate;
|
|
if (isPerm) {
|
|
PK11_SETATTRS(attrs, CKA_TOKEN, &cktrue, sizeof(CK_BBOOL)); attrs++;
|
|
}
|
|
templateCount = attrs-keyTemplate;
|
|
templateCount += pk11_OpFlagsToAttributes(flags, attrs, &cktrue);
|
|
|
|
return pk11_AnyUnwrapKey(wrappingKey->slot, wrappingKey->objectID,
|
|
wrapType, param, wrappedKey, target, operation, keySize,
|
|
wrappingKey->cx, keyTemplate, templateCount, isPerm);
|
|
}
|
|
|
|
|
|
/* unwrap a symetric key with a private key. */
|
|
PK11SymKey *
|
|
PK11_PubUnwrapSymKey(SECKEYPrivateKey *wrappingKey, SECItem *wrappedKey,
|
|
CK_MECHANISM_TYPE target, CK_ATTRIBUTE_TYPE operation, int keySize)
|
|
{
|
|
CK_MECHANISM_TYPE wrapType = pk11_mapWrapKeyType(wrappingKey->keyType);
|
|
PK11SlotInfo *slot = wrappingKey->pkcs11Slot;
|
|
|
|
if (SECKEY_HAS_ATTRIBUTE_SET(wrappingKey,CKA_PRIVATE)) {
|
|
PK11_HandlePasswordCheck(slot,wrappingKey->wincx);
|
|
}
|
|
|
|
return pk11_AnyUnwrapKey(slot, wrappingKey->pkcs11ID,
|
|
wrapType, NULL, wrappedKey, target, operation, keySize,
|
|
wrappingKey->wincx, NULL, 0, PR_FALSE);
|
|
}
|
|
|
|
/* unwrap a symetric key with a private key. */
|
|
PK11SymKey *
|
|
PK11_PubUnwrapSymKeyWithFlags(SECKEYPrivateKey *wrappingKey,
|
|
SECItem *wrappedKey, CK_MECHANISM_TYPE target,
|
|
CK_ATTRIBUTE_TYPE operation, int keySize, CK_FLAGS flags)
|
|
{
|
|
CK_MECHANISM_TYPE wrapType = pk11_mapWrapKeyType(wrappingKey->keyType);
|
|
CK_BBOOL ckTrue = CK_TRUE;
|
|
CK_ATTRIBUTE keyTemplate[MAX_TEMPL_ATTRS];
|
|
unsigned int templateCount;
|
|
PK11SlotInfo *slot = wrappingKey->pkcs11Slot;
|
|
|
|
templateCount = pk11_OpFlagsToAttributes(flags, keyTemplate, &ckTrue);
|
|
|
|
if (SECKEY_HAS_ATTRIBUTE_SET(wrappingKey,CKA_PRIVATE)) {
|
|
PK11_HandlePasswordCheck(slot,wrappingKey->wincx);
|
|
}
|
|
|
|
return pk11_AnyUnwrapKey(slot, wrappingKey->pkcs11ID,
|
|
wrapType, NULL, wrappedKey, target, operation, keySize,
|
|
wrappingKey->wincx, keyTemplate, templateCount, PR_FALSE);
|
|
}
|
|
|
|
PK11SymKey *
|
|
PK11_PubUnwrapSymKeyWithFlagsPerm(SECKEYPrivateKey *wrappingKey,
|
|
SECItem *wrappedKey, CK_MECHANISM_TYPE target,
|
|
CK_ATTRIBUTE_TYPE operation, int keySize,
|
|
CK_FLAGS flags, PRBool isPerm)
|
|
{
|
|
CK_MECHANISM_TYPE wrapType = pk11_mapWrapKeyType(wrappingKey->keyType);
|
|
CK_BBOOL cktrue = CK_TRUE;
|
|
CK_ATTRIBUTE keyTemplate[MAX_TEMPL_ATTRS];
|
|
CK_ATTRIBUTE *attrs;
|
|
unsigned int templateCount;
|
|
PK11SlotInfo *slot = wrappingKey->pkcs11Slot;
|
|
|
|
attrs = keyTemplate;
|
|
if (isPerm) {
|
|
PK11_SETATTRS(attrs, CKA_TOKEN, &cktrue, sizeof(CK_BBOOL)); attrs++;
|
|
}
|
|
templateCount = attrs-keyTemplate;
|
|
|
|
templateCount += pk11_OpFlagsToAttributes(flags, attrs, &cktrue);
|
|
|
|
if (SECKEY_HAS_ATTRIBUTE_SET(wrappingKey,CKA_PRIVATE)) {
|
|
PK11_HandlePasswordCheck(slot,wrappingKey->wincx);
|
|
}
|
|
|
|
return pk11_AnyUnwrapKey(slot, wrappingKey->pkcs11ID,
|
|
wrapType, NULL, wrappedKey, target, operation, keySize,
|
|
wrappingKey->wincx, keyTemplate, templateCount, isPerm);
|
|
}
|
|
|
|
PK11SymKey*
|
|
PK11_CopySymKeyForSigning(PK11SymKey *originalKey, CK_MECHANISM_TYPE mech)
|
|
{
|
|
CK_RV crv;
|
|
CK_ATTRIBUTE setTemplate;
|
|
CK_BBOOL ckTrue = CK_TRUE;
|
|
PK11SlotInfo *slot = originalKey->slot;
|
|
|
|
/* first just try to set this key up for signing */
|
|
PK11_SETATTRS(&setTemplate, CKA_SIGN, &ckTrue, sizeof(ckTrue));
|
|
pk11_EnterKeyMonitor(originalKey);
|
|
crv = PK11_GETTAB(slot)-> C_SetAttributeValue(originalKey->session,
|
|
originalKey->objectID, &setTemplate, 1);
|
|
pk11_ExitKeyMonitor(originalKey);
|
|
if (crv == CKR_OK) {
|
|
return PK11_ReferenceSymKey(originalKey);
|
|
}
|
|
|
|
/* nope, doesn't like it, use the pk11 copy object command */
|
|
return pk11_CopyToSlot(slot, mech, CKA_SIGN, originalKey);
|
|
}
|
|
|
|
void
|
|
PK11_SetFortezzaHack(PK11SymKey *symKey) {
|
|
symKey->origin = PK11_OriginFortezzaHack;
|
|
}
|
|
|
|
/*
|
|
* This is required to allow FORTEZZA_NULL and FORTEZZA_RC4
|
|
* working. This function simply gets a valid IV for the keys.
|
|
*/
|
|
SECStatus
|
|
PK11_GenerateFortezzaIV(PK11SymKey *symKey,unsigned char *iv,int len)
|
|
{
|
|
CK_MECHANISM mech_info;
|
|
CK_ULONG count = 0;
|
|
CK_RV crv;
|
|
SECStatus rv = SECFailure;
|
|
|
|
mech_info.mechanism = CKM_SKIPJACK_CBC64;
|
|
mech_info.pParameter = iv;
|
|
mech_info.ulParameterLen = len;
|
|
|
|
/* generate the IV for fortezza */
|
|
PK11_EnterSlotMonitor(symKey->slot);
|
|
crv=PK11_GETTAB(symKey->slot)->C_EncryptInit(symKey->slot->session,
|
|
&mech_info, symKey->objectID);
|
|
if (crv == CKR_OK) {
|
|
PK11_GETTAB(symKey->slot)->C_EncryptFinal(symKey->slot->session,
|
|
NULL, &count);
|
|
rv = SECSuccess;
|
|
}
|
|
PK11_ExitSlotMonitor(symKey->slot);
|
|
return rv;
|
|
}
|
|
|
|
CK_OBJECT_HANDLE
|
|
PK11_GetSymKeyHandle(PK11SymKey *symKey)
|
|
{
|
|
return symKey->objectID;
|
|
}
|
|
|