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
2023 lines
55 KiB
C
2023 lines
55 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 manages object type indepentent functions.
|
|
*/
|
|
#include "seccomon.h"
|
|
#include "secmod.h"
|
|
#include "secmodi.h"
|
|
#include "secmodti.h"
|
|
#include "pkcs11.h"
|
|
#include "pkcs11t.h"
|
|
#include "pk11func.h"
|
|
#include "key.h"
|
|
#include "secitem.h"
|
|
#include "secerr.h"
|
|
#include "sslerr.h"
|
|
|
|
#define PK11_SEARCH_CHUNKSIZE 10
|
|
|
|
/*
|
|
* Build a block big enough to hold the data
|
|
*/
|
|
SECItem *
|
|
PK11_BlockData(SECItem *data,unsigned long size) {
|
|
SECItem *newData;
|
|
|
|
newData = (SECItem *)PORT_Alloc(sizeof(SECItem));
|
|
if (newData == NULL) return NULL;
|
|
|
|
newData->len = (data->len + (size-1))/size;
|
|
newData->len *= size;
|
|
|
|
newData->data = (unsigned char *) PORT_ZAlloc(newData->len);
|
|
if (newData->data == NULL) {
|
|
PORT_Free(newData);
|
|
return NULL;
|
|
}
|
|
PORT_Memset(newData->data,newData->len-data->len,newData->len);
|
|
PORT_Memcpy(newData->data,data->data,data->len);
|
|
return newData;
|
|
}
|
|
|
|
|
|
SECStatus
|
|
PK11_DestroyObject(PK11SlotInfo *slot,CK_OBJECT_HANDLE object) {
|
|
CK_RV crv;
|
|
|
|
PK11_EnterSlotMonitor(slot);
|
|
crv = PK11_GETTAB(slot)->C_DestroyObject(slot->session,object);
|
|
PK11_ExitSlotMonitor(slot);
|
|
if (crv != CKR_OK) {
|
|
return SECFailure;
|
|
}
|
|
return SECSuccess;
|
|
}
|
|
|
|
SECStatus
|
|
PK11_DestroyTokenObject(PK11SlotInfo *slot,CK_OBJECT_HANDLE object) {
|
|
CK_RV crv;
|
|
SECStatus rv = SECSuccess;
|
|
CK_SESSION_HANDLE rwsession;
|
|
|
|
|
|
rwsession = PK11_GetRWSession(slot);
|
|
if (rwsession == CK_INVALID_SESSION) {
|
|
PORT_SetError(SEC_ERROR_BAD_DATA);
|
|
return SECFailure;
|
|
}
|
|
|
|
crv = PK11_GETTAB(slot)->C_DestroyObject(rwsession,object);
|
|
if (crv != CKR_OK) {
|
|
rv = SECFailure;
|
|
PORT_SetError(PK11_MapError(crv));
|
|
}
|
|
PK11_RestoreROSession(slot,rwsession);
|
|
return rv;
|
|
}
|
|
|
|
/*
|
|
* Read in a single attribute into a SECItem. Allocate space for it with
|
|
* PORT_Alloc unless an arena is supplied. In the latter case use the arena
|
|
* to allocate the space.
|
|
*
|
|
* PK11_ReadAttribute sets the 'data' and 'len' fields of the SECItem but
|
|
* does not modify its 'type' field.
|
|
*/
|
|
SECStatus
|
|
PK11_ReadAttribute(PK11SlotInfo *slot, CK_OBJECT_HANDLE id,
|
|
CK_ATTRIBUTE_TYPE type, PLArenaPool *arena, SECItem *result) {
|
|
CK_ATTRIBUTE attr = { 0, NULL, 0 };
|
|
CK_RV crv;
|
|
|
|
attr.type = type;
|
|
|
|
PK11_EnterSlotMonitor(slot);
|
|
crv = PK11_GETTAB(slot)->C_GetAttributeValue(slot->session,id,&attr,1);
|
|
if (crv != CKR_OK) {
|
|
PK11_ExitSlotMonitor(slot);
|
|
PORT_SetError(PK11_MapError(crv));
|
|
return SECFailure;
|
|
}
|
|
if (arena) {
|
|
attr.pValue = PORT_ArenaAlloc(arena,attr.ulValueLen);
|
|
} else {
|
|
attr.pValue = PORT_Alloc(attr.ulValueLen);
|
|
}
|
|
if (attr.pValue == NULL) {
|
|
PK11_ExitSlotMonitor(slot);
|
|
return SECFailure;
|
|
}
|
|
crv = PK11_GETTAB(slot)->C_GetAttributeValue(slot->session,id,&attr,1);
|
|
PK11_ExitSlotMonitor(slot);
|
|
if (crv != CKR_OK) {
|
|
PORT_SetError(PK11_MapError(crv));
|
|
if (!arena) PORT_Free(attr.pValue);
|
|
return SECFailure;
|
|
}
|
|
|
|
result->data = (unsigned char*)attr.pValue;
|
|
result->len = attr.ulValueLen;
|
|
|
|
return SECSuccess;
|
|
}
|
|
|
|
/*
|
|
* Read in a single attribute into As a Ulong.
|
|
*/
|
|
CK_ULONG
|
|
PK11_ReadULongAttribute(PK11SlotInfo *slot, CK_OBJECT_HANDLE id,
|
|
CK_ATTRIBUTE_TYPE type) {
|
|
CK_ATTRIBUTE attr;
|
|
CK_ULONG value = CK_UNAVAILABLE_INFORMATION;
|
|
CK_RV crv;
|
|
|
|
PK11_SETATTRS(&attr,type,&value,sizeof(value));
|
|
|
|
PK11_EnterSlotMonitor(slot);
|
|
crv = PK11_GETTAB(slot)->C_GetAttributeValue(slot->session,id,&attr,1);
|
|
PK11_ExitSlotMonitor(slot);
|
|
if (crv != CKR_OK) {
|
|
PORT_SetError(PK11_MapError(crv));
|
|
}
|
|
return value;
|
|
}
|
|
|
|
/*
|
|
* check to see if a bool has been set.
|
|
*/
|
|
CK_BBOOL
|
|
PK11_HasAttributeSet( PK11SlotInfo *slot, CK_OBJECT_HANDLE id,
|
|
CK_ATTRIBUTE_TYPE type, PRBool haslock )
|
|
{
|
|
CK_BBOOL ckvalue = CK_FALSE;
|
|
CK_ATTRIBUTE theTemplate;
|
|
CK_RV crv;
|
|
|
|
/* Prepare to retrieve the attribute. */
|
|
PK11_SETATTRS( &theTemplate, type, &ckvalue, sizeof( CK_BBOOL ) );
|
|
|
|
/* Retrieve attribute value. */
|
|
if (!haslock) PK11_EnterSlotMonitor(slot);
|
|
crv = PK11_GETTAB( slot )->C_GetAttributeValue( slot->session, id,
|
|
&theTemplate, 1 );
|
|
if (!haslock) PK11_ExitSlotMonitor(slot);
|
|
if( crv != CKR_OK ) {
|
|
PORT_SetError( PK11_MapError( crv ) );
|
|
return CK_FALSE;
|
|
}
|
|
|
|
return ckvalue;
|
|
}
|
|
|
|
/*
|
|
* returns a full list of attributes. Allocate space for them. If an arena is
|
|
* provided, allocate space out of the arena.
|
|
*/
|
|
CK_RV
|
|
PK11_GetAttributes(PLArenaPool *arena,PK11SlotInfo *slot,
|
|
CK_OBJECT_HANDLE obj,CK_ATTRIBUTE *attr, int count)
|
|
{
|
|
int i;
|
|
/* make pedantic happy... note that it's only used arena != NULL */
|
|
void *mark = NULL;
|
|
CK_RV crv;
|
|
PORT_Assert(slot->session != CK_INVALID_SESSION);
|
|
if (slot->session == CK_INVALID_SESSION)
|
|
return CKR_SESSION_HANDLE_INVALID;
|
|
|
|
/*
|
|
* first get all the lengths of the parameters.
|
|
*/
|
|
PK11_EnterSlotMonitor(slot);
|
|
crv = PK11_GETTAB(slot)->C_GetAttributeValue(slot->session,obj,attr,count);
|
|
if (crv != CKR_OK) {
|
|
PK11_ExitSlotMonitor(slot);
|
|
return crv;
|
|
}
|
|
|
|
if (arena) {
|
|
mark = PORT_ArenaMark(arena);
|
|
if (mark == NULL) return CKR_HOST_MEMORY;
|
|
}
|
|
|
|
/*
|
|
* now allocate space to store the results.
|
|
*/
|
|
for (i=0; i < count; i++) {
|
|
if (attr[i].ulValueLen == 0)
|
|
continue;
|
|
if (arena) {
|
|
attr[i].pValue = PORT_ArenaAlloc(arena,attr[i].ulValueLen);
|
|
if (attr[i].pValue == NULL) {
|
|
/* arena failures, just release the mark */
|
|
PORT_ArenaRelease(arena,mark);
|
|
PK11_ExitSlotMonitor(slot);
|
|
return CKR_HOST_MEMORY;
|
|
}
|
|
} else {
|
|
attr[i].pValue = PORT_Alloc(attr[i].ulValueLen);
|
|
if (attr[i].pValue == NULL) {
|
|
/* Separate malloc failures, loop to release what we have
|
|
* so far */
|
|
int j;
|
|
for (j= 0; j < i; j++) {
|
|
PORT_Free(attr[j].pValue);
|
|
/* don't give the caller pointers to freed memory */
|
|
attr[j].pValue = NULL;
|
|
}
|
|
PK11_ExitSlotMonitor(slot);
|
|
return CKR_HOST_MEMORY;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* finally get the results.
|
|
*/
|
|
crv = PK11_GETTAB(slot)->C_GetAttributeValue(slot->session,obj,attr,count);
|
|
PK11_ExitSlotMonitor(slot);
|
|
if (crv != CKR_OK) {
|
|
if (arena) {
|
|
PORT_ArenaRelease(arena,mark);
|
|
} else {
|
|
for (i= 0; i < count; i++) {
|
|
PORT_Free(attr[i].pValue);
|
|
/* don't give the caller pointers to freed memory */
|
|
attr[i].pValue = NULL;
|
|
}
|
|
}
|
|
} else if (arena && mark) {
|
|
PORT_ArenaUnmark(arena,mark);
|
|
}
|
|
return crv;
|
|
}
|
|
|
|
PRBool
|
|
PK11_IsPermObject(PK11SlotInfo *slot, CK_OBJECT_HANDLE handle)
|
|
{
|
|
return (PRBool) PK11_HasAttributeSet(slot, handle, CKA_TOKEN, PR_FALSE);
|
|
}
|
|
|
|
char *
|
|
PK11_GetObjectNickname(PK11SlotInfo *slot, CK_OBJECT_HANDLE id)
|
|
{
|
|
char *nickname = NULL;
|
|
SECItem result;
|
|
SECStatus rv;
|
|
|
|
rv = PK11_ReadAttribute(slot,id,CKA_LABEL,NULL,&result);
|
|
if (rv != SECSuccess) {
|
|
return NULL;
|
|
}
|
|
|
|
nickname = PORT_ZAlloc(result.len+1);
|
|
if (nickname == NULL) {
|
|
PORT_Free(result.data);
|
|
return NULL;
|
|
}
|
|
PORT_Memcpy(nickname, result.data, result.len);
|
|
PORT_Free(result.data);
|
|
return nickname;
|
|
}
|
|
|
|
SECStatus
|
|
PK11_SetObjectNickname(PK11SlotInfo *slot, CK_OBJECT_HANDLE id,
|
|
const char *nickname)
|
|
{
|
|
int len = PORT_Strlen(nickname);
|
|
CK_ATTRIBUTE setTemplate;
|
|
CK_RV crv;
|
|
CK_SESSION_HANDLE rwsession;
|
|
|
|
if (len < 0) {
|
|
return SECFailure;
|
|
}
|
|
|
|
PK11_SETATTRS(&setTemplate, CKA_LABEL, (CK_CHAR *) nickname, len);
|
|
rwsession = PK11_GetRWSession(slot);
|
|
if (rwsession == CK_INVALID_SESSION) {
|
|
PORT_SetError(SEC_ERROR_BAD_DATA);
|
|
return SECFailure;
|
|
}
|
|
crv = PK11_GETTAB(slot)->C_SetAttributeValue(rwsession, id,
|
|
&setTemplate, 1);
|
|
PK11_RestoreROSession(slot, rwsession);
|
|
if (crv != CKR_OK) {
|
|
PORT_SetError(PK11_MapError(crv));
|
|
return SECFailure;
|
|
}
|
|
return SECSuccess;
|
|
}
|
|
|
|
/*
|
|
* strip leading zero's from key material
|
|
*/
|
|
void
|
|
pk11_SignedToUnsigned(CK_ATTRIBUTE *attrib) {
|
|
char *ptr = (char *)attrib->pValue;
|
|
unsigned long len = attrib->ulValueLen;
|
|
|
|
while ((len > 1) && (*ptr == 0)) {
|
|
len--;
|
|
ptr++;
|
|
}
|
|
attrib->pValue = ptr;
|
|
attrib->ulValueLen = len;
|
|
}
|
|
|
|
/*
|
|
* get a new session on a slot. If we run out of session, use the slot's
|
|
* 'exclusive' session. In this case owner becomes false.
|
|
*/
|
|
CK_SESSION_HANDLE
|
|
pk11_GetNewSession(PK11SlotInfo *slot,PRBool *owner)
|
|
{
|
|
CK_SESSION_HANDLE session;
|
|
*owner = PR_TRUE;
|
|
if (!slot->isThreadSafe) PK11_EnterSlotMonitor(slot);
|
|
if ( PK11_GETTAB(slot)->C_OpenSession(slot->slotID,CKF_SERIAL_SESSION,
|
|
slot,pk11_notify,&session) != CKR_OK) {
|
|
*owner = PR_FALSE;
|
|
session = slot->session;
|
|
}
|
|
if (!slot->isThreadSafe) PK11_ExitSlotMonitor(slot);
|
|
|
|
return session;
|
|
}
|
|
|
|
void
|
|
pk11_CloseSession(PK11SlotInfo *slot,CK_SESSION_HANDLE session,PRBool owner)
|
|
{
|
|
if (!owner) return;
|
|
if (!slot->isThreadSafe) PK11_EnterSlotMonitor(slot);
|
|
(void) PK11_GETTAB(slot)->C_CloseSession(session);
|
|
if (!slot->isThreadSafe) PK11_ExitSlotMonitor(slot);
|
|
}
|
|
|
|
|
|
SECStatus
|
|
PK11_CreateNewObject(PK11SlotInfo *slot, CK_SESSION_HANDLE session,
|
|
const CK_ATTRIBUTE *theTemplate, int count,
|
|
PRBool token, CK_OBJECT_HANDLE *objectID)
|
|
{
|
|
CK_SESSION_HANDLE rwsession;
|
|
CK_RV crv;
|
|
SECStatus rv = SECSuccess;
|
|
|
|
rwsession = session;
|
|
if (token) {
|
|
rwsession = PK11_GetRWSession(slot);
|
|
} else if (rwsession == CK_INVALID_SESSION) {
|
|
rwsession = slot->session;
|
|
if (rwsession != CK_INVALID_SESSION)
|
|
PK11_EnterSlotMonitor(slot);
|
|
}
|
|
if (rwsession == CK_INVALID_SESSION) {
|
|
PORT_SetError(SEC_ERROR_BAD_DATA);
|
|
return SECFailure;
|
|
}
|
|
crv = PK11_GETTAB(slot)->C_CreateObject(rwsession,
|
|
/* cast away const :-( */ (CK_ATTRIBUTE_PTR)theTemplate,
|
|
count, objectID);
|
|
if(crv != CKR_OK) {
|
|
PORT_SetError( PK11_MapError(crv) );
|
|
rv = SECFailure;
|
|
}
|
|
if (token) {
|
|
PK11_RestoreROSession(slot, rwsession);
|
|
} else if (session == CK_INVALID_SESSION) {
|
|
PK11_ExitSlotMonitor(slot);
|
|
}
|
|
|
|
return rv;
|
|
}
|
|
|
|
|
|
/* This function may add a maximum of 9 attributes. */
|
|
unsigned int
|
|
pk11_OpFlagsToAttributes(CK_FLAGS flags, CK_ATTRIBUTE *attrs, CK_BBOOL *ckTrue)
|
|
{
|
|
|
|
const static CK_ATTRIBUTE_TYPE attrTypes[12] = {
|
|
CKA_ENCRYPT, CKA_DECRYPT, 0 /* DIGEST */, CKA_SIGN,
|
|
CKA_SIGN_RECOVER, CKA_VERIFY, CKA_VERIFY_RECOVER, 0 /* GEN */,
|
|
0 /* GEN PAIR */, CKA_WRAP, CKA_UNWRAP, CKA_DERIVE
|
|
};
|
|
|
|
const CK_ATTRIBUTE_TYPE *pType = attrTypes;
|
|
CK_ATTRIBUTE *attr = attrs;
|
|
CK_FLAGS test = CKF_ENCRYPT;
|
|
|
|
|
|
PR_ASSERT(!(flags & ~CKF_KEY_OPERATION_FLAGS));
|
|
flags &= CKF_KEY_OPERATION_FLAGS;
|
|
|
|
for (; flags && test <= CKF_DERIVE; test <<= 1, ++pType) {
|
|
if (test & flags) {
|
|
flags ^= test;
|
|
PR_ASSERT(*pType);
|
|
PK11_SETATTRS(attr, *pType, ckTrue, sizeof *ckTrue);
|
|
++attr;
|
|
}
|
|
}
|
|
return (attr - attrs);
|
|
}
|
|
|
|
/*
|
|
* Check for conflicting flags, for example, if both PK11_ATTR_PRIVATE
|
|
* and PK11_ATTR_PUBLIC are set.
|
|
*/
|
|
PRBool
|
|
pk11_BadAttrFlags(PK11AttrFlags attrFlags)
|
|
{
|
|
PK11AttrFlags trueFlags = attrFlags & 0x55555555;
|
|
PK11AttrFlags falseFlags = (attrFlags >> 1) & 0x55555555;
|
|
return ((trueFlags & falseFlags) != 0);
|
|
}
|
|
|
|
/*
|
|
* This function may add a maximum of 5 attributes.
|
|
* The caller must make sure the attribute flags don't have conflicts.
|
|
*/
|
|
unsigned int
|
|
pk11_AttrFlagsToAttributes(PK11AttrFlags attrFlags, CK_ATTRIBUTE *attrs,
|
|
CK_BBOOL *ckTrue, CK_BBOOL *ckFalse)
|
|
{
|
|
const static CK_ATTRIBUTE_TYPE attrTypes[5] = {
|
|
CKA_TOKEN, CKA_PRIVATE, CKA_MODIFIABLE, CKA_SENSITIVE,
|
|
CKA_EXTRACTABLE
|
|
};
|
|
|
|
const CK_ATTRIBUTE_TYPE *pType = attrTypes;
|
|
CK_ATTRIBUTE *attr = attrs;
|
|
PK11AttrFlags test = PK11_ATTR_TOKEN;
|
|
|
|
PR_ASSERT(!pk11_BadAttrFlags(attrFlags));
|
|
|
|
/* we test two related bitflags in each iteration */
|
|
for (; attrFlags && test <= PK11_ATTR_EXTRACTABLE; test <<= 2, ++pType) {
|
|
if (test & attrFlags) {
|
|
attrFlags ^= test;
|
|
PK11_SETATTRS(attr, *pType, ckTrue, sizeof *ckTrue);
|
|
++attr;
|
|
} else if ((test << 1) & attrFlags) {
|
|
attrFlags ^= (test << 1);
|
|
PK11_SETATTRS(attr, *pType, ckFalse, sizeof *ckFalse);
|
|
++attr;
|
|
}
|
|
}
|
|
return (attr - attrs);
|
|
}
|
|
|
|
/*
|
|
* Some non-compliant PKCS #11 vendors do not give us the modulus, so actually
|
|
* set up a signature to get the signaure length.
|
|
*/
|
|
static int
|
|
pk11_backupGetSignLength(SECKEYPrivateKey *key)
|
|
{
|
|
PK11SlotInfo *slot = key->pkcs11Slot;
|
|
CK_MECHANISM mech = {0, NULL, 0 };
|
|
PRBool owner = PR_TRUE;
|
|
CK_SESSION_HANDLE session;
|
|
CK_ULONG len;
|
|
CK_RV crv;
|
|
unsigned char h_data[20] = { 0 };
|
|
unsigned char buf[20]; /* obviously to small */
|
|
CK_ULONG smallLen = sizeof(buf);
|
|
|
|
mech.mechanism = PK11_MapSignKeyType(key->keyType);
|
|
|
|
session = pk11_GetNewSession(slot,&owner);
|
|
if (!owner || !(slot->isThreadSafe)) PK11_EnterSlotMonitor(slot);
|
|
crv = PK11_GETTAB(slot)->C_SignInit(session,&mech,key->pkcs11ID);
|
|
if (crv != CKR_OK) {
|
|
if (!owner || !(slot->isThreadSafe)) PK11_ExitSlotMonitor(slot);
|
|
pk11_CloseSession(slot,session,owner);
|
|
PORT_SetError( PK11_MapError(crv) );
|
|
return -1;
|
|
}
|
|
len = 0;
|
|
crv = PK11_GETTAB(slot)->C_Sign(session,h_data,sizeof(h_data),
|
|
NULL, &len);
|
|
/* now call C_Sign with too small a buffer to clear the session state */
|
|
(void) PK11_GETTAB(slot)->
|
|
C_Sign(session,h_data,sizeof(h_data),buf,&smallLen);
|
|
|
|
if (!owner || !(slot->isThreadSafe)) PK11_ExitSlotMonitor(slot);
|
|
pk11_CloseSession(slot,session,owner);
|
|
if (crv != CKR_OK) {
|
|
PORT_SetError( PK11_MapError(crv) );
|
|
return -1;
|
|
}
|
|
return len;
|
|
}
|
|
|
|
/*
|
|
* get the length of a signature object based on the key
|
|
*/
|
|
int
|
|
PK11_SignatureLen(SECKEYPrivateKey *key)
|
|
{
|
|
int val;
|
|
SECItem attributeItem = {siBuffer, NULL, 0};
|
|
SECStatus rv;
|
|
int length;
|
|
|
|
switch (key->keyType) {
|
|
case rsaKey:
|
|
val = PK11_GetPrivateModulusLen(key);
|
|
if (val == -1) {
|
|
return pk11_backupGetSignLength(key);
|
|
}
|
|
return (unsigned long) val;
|
|
|
|
case fortezzaKey:
|
|
return 40;
|
|
|
|
case dsaKey:
|
|
rv = PK11_ReadAttribute(key->pkcs11Slot, key->pkcs11ID, CKA_SUBPRIME,
|
|
NULL, &attributeItem);
|
|
if (rv == SECSuccess) {
|
|
length = attributeItem.len;
|
|
if ((length > 0) && attributeItem.data[0] == 0) {
|
|
length--;
|
|
}
|
|
PORT_Free(attributeItem.data);
|
|
return length*2;
|
|
}
|
|
return pk11_backupGetSignLength(key);
|
|
|
|
case ecKey:
|
|
rv = PK11_ReadAttribute(key->pkcs11Slot, key->pkcs11ID, CKA_EC_PARAMS,
|
|
NULL, &attributeItem);
|
|
if (rv == SECSuccess) {
|
|
length = SECKEY_ECParamsToBasePointOrderLen(&attributeItem);
|
|
PORT_Free(attributeItem.data);
|
|
if (length != 0) {
|
|
length = ((length + 7)/8) * 2;
|
|
return length;
|
|
}
|
|
}
|
|
return pk11_backupGetSignLength(key);
|
|
default:
|
|
break;
|
|
}
|
|
PORT_SetError( SEC_ERROR_INVALID_KEY );
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* copy a key (or any other object) on a token
|
|
*/
|
|
CK_OBJECT_HANDLE
|
|
PK11_CopyKey(PK11SlotInfo *slot, CK_OBJECT_HANDLE srcObject)
|
|
{
|
|
CK_OBJECT_HANDLE destObject;
|
|
CK_RV crv;
|
|
|
|
PK11_EnterSlotMonitor(slot);
|
|
crv = PK11_GETTAB(slot)->C_CopyObject(slot->session,srcObject,NULL,0,
|
|
&destObject);
|
|
PK11_ExitSlotMonitor(slot);
|
|
if (crv == CKR_OK) return destObject;
|
|
PORT_SetError( PK11_MapError(crv) );
|
|
return CK_INVALID_HANDLE;
|
|
}
|
|
|
|
PRBool
|
|
pk11_FindAttrInTemplate(CK_ATTRIBUTE *attr, unsigned int numAttrs,
|
|
CK_ATTRIBUTE_TYPE target)
|
|
{
|
|
for (; numAttrs > 0; ++attr, --numAttrs) {
|
|
if (attr->type == target)
|
|
return PR_TRUE;
|
|
}
|
|
return PR_FALSE;
|
|
}
|
|
|
|
/*
|
|
* Recover the Signed data. We need this because our old verify can't
|
|
* figure out which hash algorithm to use until we decryptted this.
|
|
*/
|
|
SECStatus
|
|
PK11_VerifyRecover(SECKEYPublicKey *key, const SECItem *sig,
|
|
SECItem *dsig, void *wincx)
|
|
{
|
|
PK11SlotInfo *slot = key->pkcs11Slot;
|
|
CK_OBJECT_HANDLE id = key->pkcs11ID;
|
|
CK_MECHANISM mech = {0, NULL, 0 };
|
|
PRBool owner = PR_TRUE;
|
|
CK_SESSION_HANDLE session;
|
|
CK_ULONG len;
|
|
CK_RV crv;
|
|
|
|
mech.mechanism = PK11_MapSignKeyType(key->keyType);
|
|
|
|
if (slot == NULL) {
|
|
slot = PK11_GetBestSlotWithAttributes(mech.mechanism,
|
|
CKF_VERIFY_RECOVER,0,wincx);
|
|
if (slot == NULL) {
|
|
PORT_SetError( SEC_ERROR_NO_MODULE );
|
|
return SECFailure;
|
|
}
|
|
id = PK11_ImportPublicKey(slot,key,PR_FALSE);
|
|
} else {
|
|
PK11_ReferenceSlot(slot);
|
|
}
|
|
|
|
if (id == CK_INVALID_HANDLE) {
|
|
PK11_FreeSlot(slot);
|
|
PORT_SetError( SEC_ERROR_BAD_KEY );
|
|
return SECFailure;
|
|
}
|
|
|
|
session = pk11_GetNewSession(slot,&owner);
|
|
if (!owner || !(slot->isThreadSafe)) PK11_EnterSlotMonitor(slot);
|
|
crv = PK11_GETTAB(slot)->C_VerifyRecoverInit(session,&mech,id);
|
|
if (crv != CKR_OK) {
|
|
if (!owner || !(slot->isThreadSafe)) PK11_ExitSlotMonitor(slot);
|
|
pk11_CloseSession(slot,session,owner);
|
|
PORT_SetError( PK11_MapError(crv) );
|
|
PK11_FreeSlot(slot);
|
|
return SECFailure;
|
|
}
|
|
len = dsig->len;
|
|
crv = PK11_GETTAB(slot)->C_VerifyRecover(session,sig->data,
|
|
sig->len, dsig->data, &len);
|
|
if (!owner || !(slot->isThreadSafe)) PK11_ExitSlotMonitor(slot);
|
|
pk11_CloseSession(slot,session,owner);
|
|
dsig->len = len;
|
|
if (crv != CKR_OK) {
|
|
PORT_SetError( PK11_MapError(crv) );
|
|
PK11_FreeSlot(slot);
|
|
return SECFailure;
|
|
}
|
|
PK11_FreeSlot(slot);
|
|
return SECSuccess;
|
|
}
|
|
|
|
/*
|
|
* verify a signature from its hash.
|
|
*/
|
|
SECStatus
|
|
PK11_Verify(SECKEYPublicKey *key, const SECItem *sig, const SECItem *hash,
|
|
void *wincx)
|
|
{
|
|
PK11SlotInfo *slot = key->pkcs11Slot;
|
|
CK_OBJECT_HANDLE id = key->pkcs11ID;
|
|
CK_MECHANISM mech = {0, NULL, 0 };
|
|
PRBool owner = PR_TRUE;
|
|
CK_SESSION_HANDLE session;
|
|
CK_RV crv;
|
|
|
|
mech.mechanism = PK11_MapSignKeyType(key->keyType);
|
|
|
|
if (slot == NULL) {
|
|
unsigned int length = 0;
|
|
if ((mech.mechanism == CKM_DSA) &&
|
|
/* 129 is 1024 bits translated to bytes and
|
|
* padded with an optional '0' to maintain a
|
|
* positive sign */
|
|
(key->u.dsa.params.prime.len > 129)) {
|
|
/* we need to get a slot that not only can do DSA, but can do DSA2
|
|
* key lengths */
|
|
length = key->u.dsa.params.prime.len;
|
|
if (key->u.dsa.params.prime.data[0] == 0) {
|
|
length --;
|
|
}
|
|
/* convert keysize to bits for slot lookup */
|
|
length *= 8;
|
|
}
|
|
slot = PK11_GetBestSlotWithAttributes(mech.mechanism,
|
|
CKF_VERIFY,length,wincx);
|
|
if (slot == NULL) {
|
|
PORT_SetError( SEC_ERROR_NO_MODULE );
|
|
return SECFailure;
|
|
}
|
|
id = PK11_ImportPublicKey(slot,key,PR_FALSE);
|
|
|
|
} else {
|
|
PK11_ReferenceSlot(slot);
|
|
}
|
|
|
|
if (id == CK_INVALID_HANDLE) {
|
|
PK11_FreeSlot(slot);
|
|
PORT_SetError( SEC_ERROR_BAD_KEY );
|
|
return SECFailure;
|
|
}
|
|
|
|
session = pk11_GetNewSession(slot,&owner);
|
|
if (!owner || !(slot->isThreadSafe)) PK11_EnterSlotMonitor(slot);
|
|
crv = PK11_GETTAB(slot)->C_VerifyInit(session,&mech,id);
|
|
if (crv != CKR_OK) {
|
|
if (!owner || !(slot->isThreadSafe)) PK11_ExitSlotMonitor(slot);
|
|
pk11_CloseSession(slot,session,owner);
|
|
PK11_FreeSlot(slot);
|
|
PORT_SetError( PK11_MapError(crv) );
|
|
return SECFailure;
|
|
}
|
|
crv = PK11_GETTAB(slot)->C_Verify(session,hash->data,
|
|
hash->len, sig->data, sig->len);
|
|
if (!owner || !(slot->isThreadSafe)) PK11_ExitSlotMonitor(slot);
|
|
pk11_CloseSession(slot,session,owner);
|
|
PK11_FreeSlot(slot);
|
|
if (crv != CKR_OK) {
|
|
PORT_SetError( PK11_MapError(crv) );
|
|
return SECFailure;
|
|
}
|
|
return SECSuccess;
|
|
}
|
|
|
|
/*
|
|
* sign a hash. The algorithm is determined by the key.
|
|
*/
|
|
SECStatus
|
|
PK11_Sign(SECKEYPrivateKey *key, SECItem *sig, const SECItem *hash)
|
|
{
|
|
PK11SlotInfo *slot = key->pkcs11Slot;
|
|
CK_MECHANISM mech = {0, NULL, 0 };
|
|
PRBool owner = PR_TRUE;
|
|
CK_SESSION_HANDLE session;
|
|
PRBool haslock = PR_FALSE;
|
|
CK_ULONG len;
|
|
CK_RV crv;
|
|
|
|
mech.mechanism = PK11_MapSignKeyType(key->keyType);
|
|
|
|
if (SECKEY_HAS_ATTRIBUTE_SET(key,CKA_PRIVATE)) {
|
|
PK11_HandlePasswordCheck(slot, key->wincx);
|
|
}
|
|
|
|
session = pk11_GetNewSession(slot,&owner);
|
|
haslock = (!owner || !(slot->isThreadSafe));
|
|
if (haslock) PK11_EnterSlotMonitor(slot);
|
|
crv = PK11_GETTAB(slot)->C_SignInit(session,&mech,key->pkcs11ID);
|
|
if (crv != CKR_OK) {
|
|
if (haslock) PK11_ExitSlotMonitor(slot);
|
|
pk11_CloseSession(slot,session,owner);
|
|
PORT_SetError( PK11_MapError(crv) );
|
|
return SECFailure;
|
|
}
|
|
|
|
/* PKCS11 2.20 says if CKA_ALWAYS_AUTHENTICATE then
|
|
* do C_Login with CKU_CONTEXT_SPECIFIC
|
|
* between C_SignInit and C_Sign */
|
|
if (SECKEY_HAS_ATTRIBUTE_SET_LOCK(key, CKA_ALWAYS_AUTHENTICATE, haslock)) {
|
|
PK11_DoPassword(slot, session, PR_FALSE, key->wincx, haslock, PR_TRUE);
|
|
}
|
|
|
|
len = sig->len;
|
|
crv = PK11_GETTAB(slot)->C_Sign(session,hash->data,
|
|
hash->len, sig->data, &len);
|
|
if (haslock) PK11_ExitSlotMonitor(slot);
|
|
pk11_CloseSession(slot,session,owner);
|
|
sig->len = len;
|
|
if (crv != CKR_OK) {
|
|
PORT_SetError( PK11_MapError(crv) );
|
|
return SECFailure;
|
|
}
|
|
return SECSuccess;
|
|
}
|
|
|
|
/*
|
|
* sign data with a MAC key.
|
|
*/
|
|
SECStatus
|
|
PK11_SignWithSymKey(PK11SymKey *symKey, CK_MECHANISM_TYPE mechanism,
|
|
SECItem *param, SECItem *sig, const SECItem *data)
|
|
{
|
|
PK11SlotInfo *slot = symKey->slot;
|
|
CK_MECHANISM mech = {0, NULL, 0 };
|
|
PRBool owner = PR_TRUE;
|
|
CK_SESSION_HANDLE session;
|
|
PRBool haslock = PR_FALSE;
|
|
CK_ULONG len;
|
|
CK_RV crv;
|
|
|
|
mech.mechanism = mechanism;
|
|
if (param) {
|
|
mech.pParameter = param->data;
|
|
mech.ulParameterLen = param->len;
|
|
}
|
|
|
|
session = pk11_GetNewSession(slot,&owner);
|
|
haslock = (!owner || !(slot->isThreadSafe));
|
|
if (haslock) PK11_EnterSlotMonitor(slot);
|
|
crv = PK11_GETTAB(slot)->C_SignInit(session,&mech,symKey->objectID);
|
|
if (crv != CKR_OK) {
|
|
if (haslock) PK11_ExitSlotMonitor(slot);
|
|
pk11_CloseSession(slot,session,owner);
|
|
PORT_SetError( PK11_MapError(crv) );
|
|
return SECFailure;
|
|
}
|
|
|
|
len = sig->len;
|
|
crv = PK11_GETTAB(slot)->C_Sign(session,data->data,
|
|
data->len, sig->data, &len);
|
|
if (haslock) PK11_ExitSlotMonitor(slot);
|
|
pk11_CloseSession(slot,session,owner);
|
|
sig->len = len;
|
|
if (crv != CKR_OK) {
|
|
PORT_SetError( PK11_MapError(crv) );
|
|
return SECFailure;
|
|
}
|
|
return SECSuccess;
|
|
}
|
|
|
|
SECStatus
|
|
PK11_Decrypt(PK11SymKey *symKey,
|
|
CK_MECHANISM_TYPE mechanism, SECItem *param,
|
|
unsigned char *out, unsigned int *outLen,
|
|
unsigned int maxLen,
|
|
const unsigned char *enc, unsigned encLen)
|
|
{
|
|
PK11SlotInfo *slot = symKey->slot;
|
|
CK_MECHANISM mech = {0, NULL, 0 };
|
|
CK_ULONG len = maxLen;
|
|
PRBool owner = PR_TRUE;
|
|
CK_SESSION_HANDLE session;
|
|
PRBool haslock = PR_FALSE;
|
|
CK_RV crv;
|
|
|
|
mech.mechanism = mechanism;
|
|
if (param) {
|
|
mech.pParameter = param->data;
|
|
mech.ulParameterLen = param->len;
|
|
}
|
|
|
|
session = pk11_GetNewSession(slot, &owner);
|
|
haslock = (!owner || !slot->isThreadSafe);
|
|
if (haslock) PK11_EnterSlotMonitor(slot);
|
|
crv = PK11_GETTAB(slot)->C_DecryptInit(session, &mech, symKey->objectID);
|
|
if (crv != CKR_OK) {
|
|
if (haslock) PK11_ExitSlotMonitor(slot);
|
|
pk11_CloseSession(slot, session, owner);
|
|
PORT_SetError( PK11_MapError(crv) );
|
|
return SECFailure;
|
|
}
|
|
|
|
crv = PK11_GETTAB(slot)->C_Decrypt(session, (unsigned char *)enc, encLen,
|
|
out, &len);
|
|
if (haslock) PK11_ExitSlotMonitor(slot);
|
|
pk11_CloseSession(slot, session, owner);
|
|
*outLen = len;
|
|
if (crv != CKR_OK) {
|
|
PORT_SetError( PK11_MapError(crv) );
|
|
return SECFailure;
|
|
}
|
|
return SECSuccess;
|
|
}
|
|
|
|
SECStatus
|
|
PK11_Encrypt(PK11SymKey *symKey,
|
|
CK_MECHANISM_TYPE mechanism, SECItem *param,
|
|
unsigned char *out, unsigned int *outLen,
|
|
unsigned int maxLen,
|
|
const unsigned char *data, unsigned int dataLen)
|
|
{
|
|
PK11SlotInfo *slot = symKey->slot;
|
|
CK_MECHANISM mech = {0, NULL, 0 };
|
|
CK_ULONG len = maxLen;
|
|
PRBool owner = PR_TRUE;
|
|
CK_SESSION_HANDLE session;
|
|
PRBool haslock = PR_FALSE;
|
|
CK_RV crv;
|
|
|
|
mech.mechanism = mechanism;
|
|
if (param) {
|
|
mech.pParameter = param->data;
|
|
mech.ulParameterLen = param->len;
|
|
}
|
|
|
|
session = pk11_GetNewSession(slot, &owner);
|
|
haslock = (!owner || !slot->isThreadSafe);
|
|
if (haslock) PK11_EnterSlotMonitor(slot);
|
|
crv = PK11_GETTAB(slot)->C_EncryptInit(session, &mech, symKey->objectID);
|
|
if (crv != CKR_OK) {
|
|
if (haslock) PK11_ExitSlotMonitor(slot);
|
|
pk11_CloseSession(slot,session,owner);
|
|
PORT_SetError( PK11_MapError(crv) );
|
|
return SECFailure;
|
|
}
|
|
crv = PK11_GETTAB(slot)->C_Encrypt(session, (unsigned char *)data,
|
|
dataLen, out, &len);
|
|
if (haslock) PK11_ExitSlotMonitor(slot);
|
|
pk11_CloseSession(slot,session,owner);
|
|
*outLen = len;
|
|
if (crv != CKR_OK) {
|
|
PORT_SetError( PK11_MapError(crv) );
|
|
return SECFailure;
|
|
}
|
|
return SECSuccess;
|
|
}
|
|
|
|
static SECStatus
|
|
pk11_PrivDecryptRaw(SECKEYPrivateKey *key,
|
|
unsigned char *data, unsigned *outLen, unsigned int maxLen,
|
|
const unsigned char *enc, unsigned encLen,
|
|
CK_MECHANISM_PTR mech)
|
|
{
|
|
PK11SlotInfo *slot = key->pkcs11Slot;
|
|
CK_ULONG out = maxLen;
|
|
PRBool owner = PR_TRUE;
|
|
CK_SESSION_HANDLE session;
|
|
PRBool haslock = PR_FALSE;
|
|
CK_RV crv;
|
|
|
|
if (key->keyType != rsaKey) {
|
|
PORT_SetError( SEC_ERROR_INVALID_KEY );
|
|
return SECFailure;
|
|
}
|
|
|
|
/* Why do we do a PK11_handle check here? for simple
|
|
* decryption? .. because the user may have asked for 'ask always'
|
|
* and this is a private key operation. In practice, thought, it's mute
|
|
* since only servers wind up using this function */
|
|
if (SECKEY_HAS_ATTRIBUTE_SET(key,CKA_PRIVATE)) {
|
|
PK11_HandlePasswordCheck(slot, key->wincx);
|
|
}
|
|
session = pk11_GetNewSession(slot,&owner);
|
|
haslock = (!owner || !(slot->isThreadSafe));
|
|
if (haslock) PK11_EnterSlotMonitor(slot);
|
|
crv = PK11_GETTAB(slot)->C_DecryptInit(session, mech, key->pkcs11ID);
|
|
if (crv != CKR_OK) {
|
|
if (haslock) PK11_ExitSlotMonitor(slot);
|
|
pk11_CloseSession(slot,session,owner);
|
|
PORT_SetError( PK11_MapError(crv) );
|
|
return SECFailure;
|
|
}
|
|
|
|
/* PKCS11 2.20 says if CKA_ALWAYS_AUTHENTICATE then
|
|
* do C_Login with CKU_CONTEXT_SPECIFIC
|
|
* between C_DecryptInit and C_Decrypt
|
|
* ... But see note above about servers */
|
|
if (SECKEY_HAS_ATTRIBUTE_SET_LOCK(key, CKA_ALWAYS_AUTHENTICATE, haslock)) {
|
|
PK11_DoPassword(slot, session, PR_FALSE, key->wincx, haslock, PR_TRUE);
|
|
}
|
|
|
|
crv = PK11_GETTAB(slot)->C_Decrypt(session, (unsigned char *)enc, encLen,
|
|
data, &out);
|
|
if (haslock) PK11_ExitSlotMonitor(slot);
|
|
pk11_CloseSession(slot,session,owner);
|
|
*outLen = out;
|
|
if (crv != CKR_OK) {
|
|
PORT_SetError( PK11_MapError(crv) );
|
|
return SECFailure;
|
|
}
|
|
return SECSuccess;
|
|
}
|
|
|
|
SECStatus
|
|
PK11_PubDecryptRaw(SECKEYPrivateKey *key,
|
|
unsigned char *data, unsigned *outLen, unsigned int maxLen,
|
|
const unsigned char *enc, unsigned encLen)
|
|
{
|
|
CK_MECHANISM mech = {CKM_RSA_X_509, NULL, 0 };
|
|
return pk11_PrivDecryptRaw(key, data, outLen, maxLen, enc, encLen, &mech);
|
|
}
|
|
|
|
SECStatus
|
|
PK11_PrivDecryptPKCS1(SECKEYPrivateKey *key,
|
|
unsigned char *data, unsigned *outLen, unsigned int maxLen,
|
|
const unsigned char *enc, unsigned encLen)
|
|
{
|
|
CK_MECHANISM mech = {CKM_RSA_PKCS, NULL, 0 };
|
|
return pk11_PrivDecryptRaw(key, data, outLen, maxLen, enc, encLen, &mech);
|
|
}
|
|
|
|
static SECStatus
|
|
pk11_PubEncryptRaw(SECKEYPublicKey *key,
|
|
unsigned char *out, unsigned int *outLen,
|
|
unsigned int maxLen,
|
|
const unsigned char *data, unsigned dataLen,
|
|
CK_MECHANISM_PTR mech, void *wincx)
|
|
{
|
|
PK11SlotInfo *slot;
|
|
CK_OBJECT_HANDLE id;
|
|
CK_ULONG len = maxLen;
|
|
PRBool owner = PR_TRUE;
|
|
CK_SESSION_HANDLE session;
|
|
CK_RV crv;
|
|
|
|
slot = PK11_GetBestSlotWithAttributes(mech->mechanism,CKF_ENCRYPT,0,wincx);
|
|
if (slot == NULL) {
|
|
PORT_SetError( SEC_ERROR_NO_MODULE );
|
|
return SECFailure;
|
|
}
|
|
|
|
id = PK11_ImportPublicKey(slot,key,PR_FALSE);
|
|
|
|
if (id == CK_INVALID_HANDLE) {
|
|
PK11_FreeSlot(slot);
|
|
PORT_SetError( SEC_ERROR_BAD_KEY );
|
|
return SECFailure;
|
|
}
|
|
|
|
session = pk11_GetNewSession(slot,&owner);
|
|
if (!owner || !(slot->isThreadSafe)) PK11_EnterSlotMonitor(slot);
|
|
crv = PK11_GETTAB(slot)->C_EncryptInit(session, mech, id);
|
|
if (crv != CKR_OK) {
|
|
if (!owner || !(slot->isThreadSafe)) PK11_ExitSlotMonitor(slot);
|
|
pk11_CloseSession(slot,session,owner);
|
|
PK11_FreeSlot(slot);
|
|
PORT_SetError( PK11_MapError(crv) );
|
|
return SECFailure;
|
|
}
|
|
crv = PK11_GETTAB(slot)->C_Encrypt(session,(unsigned char *)data,dataLen,
|
|
out,&len);
|
|
if (!owner || !(slot->isThreadSafe)) PK11_ExitSlotMonitor(slot);
|
|
pk11_CloseSession(slot,session,owner);
|
|
PK11_FreeSlot(slot);
|
|
*outLen = len;
|
|
if (crv != CKR_OK) {
|
|
PORT_SetError( PK11_MapError(crv) );
|
|
return SECFailure;
|
|
}
|
|
return SECSuccess;
|
|
}
|
|
|
|
SECStatus
|
|
PK11_PubEncryptRaw(SECKEYPublicKey *key,
|
|
unsigned char *enc,
|
|
const unsigned char *data, unsigned dataLen,
|
|
void *wincx)
|
|
{
|
|
CK_MECHANISM mech = {CKM_RSA_X_509, NULL, 0 };
|
|
unsigned int outLen;
|
|
if (!key || key->keyType != rsaKey) {
|
|
PORT_SetError(SEC_ERROR_BAD_KEY);
|
|
return SECFailure;
|
|
}
|
|
outLen = SECKEY_PublicKeyStrength(key);
|
|
return pk11_PubEncryptRaw(key, enc, &outLen, outLen, data, dataLen, &mech,
|
|
wincx);
|
|
}
|
|
|
|
SECStatus
|
|
PK11_PubEncryptPKCS1(SECKEYPublicKey *key,
|
|
unsigned char *enc,
|
|
const unsigned char *data, unsigned dataLen,
|
|
void *wincx)
|
|
{
|
|
CK_MECHANISM mech = {CKM_RSA_PKCS, NULL, 0 };
|
|
unsigned int outLen;
|
|
if (!key || key->keyType != rsaKey) {
|
|
PORT_SetError(SEC_ERROR_BAD_KEY);
|
|
return SECFailure;
|
|
}
|
|
outLen = SECKEY_PublicKeyStrength(key);
|
|
return pk11_PubEncryptRaw(key, enc, &outLen, outLen, data, dataLen, &mech,
|
|
wincx);
|
|
}
|
|
|
|
SECStatus
|
|
PK11_PrivDecrypt(SECKEYPrivateKey *key,
|
|
CK_MECHANISM_TYPE mechanism, SECItem *param,
|
|
unsigned char *out, unsigned int *outLen,
|
|
unsigned int maxLen,
|
|
const unsigned char *enc, unsigned encLen)
|
|
{
|
|
CK_MECHANISM mech = { mechanism, NULL, 0 };
|
|
if (param) {
|
|
mech.pParameter = param->data;
|
|
mech.ulParameterLen = param->len;
|
|
}
|
|
return pk11_PrivDecryptRaw(key, out, outLen, maxLen, enc, encLen, &mech);
|
|
}
|
|
|
|
SECStatus
|
|
PK11_PubEncrypt(SECKEYPublicKey *key,
|
|
CK_MECHANISM_TYPE mechanism, SECItem *param,
|
|
unsigned char *out, unsigned int *outLen,
|
|
unsigned int maxLen,
|
|
const unsigned char *data, unsigned dataLen,
|
|
void *wincx)
|
|
{
|
|
CK_MECHANISM mech = { mechanism, NULL, 0 };
|
|
if (param) {
|
|
mech.pParameter = param->data;
|
|
mech.ulParameterLen = param->len;
|
|
}
|
|
return pk11_PubEncryptRaw(key, out, outLen, maxLen, data, dataLen, &mech,
|
|
wincx);
|
|
}
|
|
|
|
SECKEYPrivateKey *
|
|
PK11_UnwrapPrivKey(PK11SlotInfo *slot, PK11SymKey *wrappingKey,
|
|
CK_MECHANISM_TYPE wrapType, SECItem *param,
|
|
SECItem *wrappedKey, SECItem *label,
|
|
SECItem *idValue, PRBool perm, PRBool sensitive,
|
|
CK_KEY_TYPE keyType, CK_ATTRIBUTE_TYPE *usage,
|
|
int usageCount, void *wincx)
|
|
{
|
|
CK_BBOOL cktrue = CK_TRUE;
|
|
CK_BBOOL ckfalse = CK_FALSE;
|
|
CK_OBJECT_CLASS keyClass = CKO_PRIVATE_KEY;
|
|
CK_ATTRIBUTE keyTemplate[15] ;
|
|
int templateCount = 0;
|
|
CK_OBJECT_HANDLE privKeyID;
|
|
CK_MECHANISM mechanism;
|
|
CK_ATTRIBUTE *attrs = keyTemplate;
|
|
SECItem *param_free = NULL, *ck_id = NULL;
|
|
CK_RV crv;
|
|
CK_SESSION_HANDLE rwsession;
|
|
PK11SymKey *newKey = NULL;
|
|
int i;
|
|
|
|
if(!slot || !wrappedKey || !idValue) {
|
|
/* SET AN ERROR!!! */
|
|
return NULL;
|
|
}
|
|
|
|
ck_id = PK11_MakeIDFromPubKey(idValue);
|
|
if(!ck_id) {
|
|
return NULL;
|
|
}
|
|
|
|
PK11_SETATTRS(attrs, CKA_TOKEN, perm ? &cktrue : &ckfalse,
|
|
sizeof(cktrue)); attrs++;
|
|
PK11_SETATTRS(attrs, CKA_CLASS, &keyClass, sizeof(keyClass)); attrs++;
|
|
PK11_SETATTRS(attrs, CKA_KEY_TYPE, &keyType, sizeof(keyType)); attrs++;
|
|
PK11_SETATTRS(attrs, CKA_PRIVATE, sensitive ? &cktrue : &ckfalse,
|
|
sizeof(cktrue)); attrs++;
|
|
PK11_SETATTRS(attrs, CKA_SENSITIVE, sensitive ? &cktrue : &ckfalse,
|
|
sizeof(cktrue)); attrs++;
|
|
if (label && label->data) {
|
|
PK11_SETATTRS(attrs, CKA_LABEL, label->data, label->len); attrs++;
|
|
}
|
|
PK11_SETATTRS(attrs, CKA_ID, ck_id->data, ck_id->len); attrs++;
|
|
for (i=0; i < usageCount; i++) {
|
|
PK11_SETATTRS(attrs, usage[i], &cktrue, sizeof(cktrue)); attrs++;
|
|
}
|
|
|
|
if (PK11_IsInternal(slot)) {
|
|
PK11_SETATTRS(attrs, CKA_NETSCAPE_DB, idValue->data,
|
|
idValue->len); attrs++;
|
|
}
|
|
|
|
templateCount = attrs - keyTemplate;
|
|
PR_ASSERT(templateCount <= (sizeof(keyTemplate) / sizeof(CK_ATTRIBUTE)) );
|
|
|
|
mechanism.mechanism = wrapType;
|
|
if(!param) 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 (wrappingKey->slot != slot) {
|
|
newKey = pk11_CopyToSlot(slot,wrapType,CKA_UNWRAP,wrappingKey);
|
|
} else {
|
|
newKey = PK11_ReferenceSymKey(wrappingKey);
|
|
}
|
|
|
|
if (newKey) {
|
|
if (perm) {
|
|
/* Get RW Session will either lock the monitor if necessary,
|
|
* or return a thread safe session handle, or fail. */
|
|
rwsession = PK11_GetRWSession(slot);
|
|
} else {
|
|
rwsession = slot->session;
|
|
if (rwsession != CK_INVALID_SESSION)
|
|
PK11_EnterSlotMonitor(slot);
|
|
}
|
|
/* This is a lot a work to deal with fussy PKCS #11 modules
|
|
* that can't bother to return BAD_DATA when presented with an
|
|
* invalid session! */
|
|
if (rwsession == CK_INVALID_SESSION) {
|
|
PORT_SetError(SEC_ERROR_BAD_DATA);
|
|
goto loser;
|
|
}
|
|
crv = PK11_GETTAB(slot)->C_UnwrapKey(rwsession, &mechanism,
|
|
newKey->objectID,
|
|
wrappedKey->data,
|
|
wrappedKey->len, keyTemplate,
|
|
templateCount, &privKeyID);
|
|
|
|
if (perm) {
|
|
PK11_RestoreROSession(slot, rwsession);
|
|
} else {
|
|
PK11_ExitSlotMonitor(slot);
|
|
}
|
|
PK11_FreeSymKey(newKey);
|
|
newKey = NULL;
|
|
} else {
|
|
crv = CKR_FUNCTION_NOT_SUPPORTED;
|
|
}
|
|
|
|
if (ck_id) {
|
|
SECITEM_FreeItem(ck_id, PR_TRUE);
|
|
ck_id = NULL;
|
|
}
|
|
|
|
if (crv != CKR_OK) {
|
|
/* we couldn't unwrap the key, use the internal module to do the
|
|
* unwrap, then load the new key into the token */
|
|
PK11SlotInfo *int_slot = PK11_GetInternalSlot();
|
|
|
|
if (int_slot && (slot != int_slot)) {
|
|
SECKEYPrivateKey *privKey = PK11_UnwrapPrivKey(int_slot,
|
|
wrappingKey, wrapType, param, wrappedKey, label,
|
|
idValue, PR_FALSE, PR_FALSE,
|
|
keyType, usage, usageCount, wincx);
|
|
if (privKey) {
|
|
SECKEYPrivateKey *newPrivKey = PK11_LoadPrivKey(slot,privKey,
|
|
NULL,perm,sensitive);
|
|
SECKEY_DestroyPrivateKey(privKey);
|
|
PK11_FreeSlot(int_slot);
|
|
return newPrivKey;
|
|
}
|
|
}
|
|
if (int_slot) PK11_FreeSlot(int_slot);
|
|
PORT_SetError( PK11_MapError(crv) );
|
|
return NULL;
|
|
}
|
|
return PK11_MakePrivKey(slot, nullKey, PR_FALSE, privKeyID, wincx);
|
|
|
|
loser:
|
|
if (newKey) {
|
|
PK11_FreeSymKey(newKey);
|
|
}
|
|
if (ck_id) {
|
|
SECITEM_FreeItem(ck_id, PR_TRUE);
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
/*
|
|
* Now we're going to wrap a SECKEYPrivateKey with a PK11SymKey
|
|
* The strategy is to get both keys to reside in the same slot,
|
|
* one that can perform the desired crypto mechanism and then
|
|
* call C_WrapKey after all the setup has taken place.
|
|
*/
|
|
SECStatus
|
|
PK11_WrapPrivKey(PK11SlotInfo *slot, PK11SymKey *wrappingKey,
|
|
SECKEYPrivateKey *privKey, CK_MECHANISM_TYPE wrapType,
|
|
SECItem *param, SECItem *wrappedKey, void *wincx)
|
|
{
|
|
PK11SlotInfo *privSlot = privKey->pkcs11Slot; /* The slot where
|
|
* the private key
|
|
* we are going to
|
|
* wrap lives.
|
|
*/
|
|
PK11SymKey *newSymKey = NULL;
|
|
SECKEYPrivateKey *newPrivKey = NULL;
|
|
SECItem *param_free = NULL;
|
|
CK_ULONG len = wrappedKey->len;
|
|
CK_MECHANISM mech;
|
|
CK_RV crv;
|
|
|
|
if (!privSlot || !PK11_DoesMechanism(privSlot, wrapType)) {
|
|
/* Figure out a slot that does the mechanism and try to import
|
|
* the private key onto that slot.
|
|
*/
|
|
PK11SlotInfo *int_slot = PK11_GetInternalSlot();
|
|
|
|
privSlot = int_slot; /* The private key has a new home */
|
|
newPrivKey = PK11_LoadPrivKey(privSlot,privKey,NULL,PR_FALSE,PR_FALSE);
|
|
/* newPrivKey has allocated its own reference to the slot, so it's
|
|
* safe until we destroy newPrivkey.
|
|
*/
|
|
PK11_FreeSlot(int_slot);
|
|
if (newPrivKey == NULL) {
|
|
return SECFailure;
|
|
}
|
|
privKey = newPrivKey;
|
|
}
|
|
|
|
if (privSlot != wrappingKey->slot) {
|
|
newSymKey = pk11_CopyToSlot (privSlot, wrapType, CKA_WRAP,
|
|
wrappingKey);
|
|
wrappingKey = newSymKey;
|
|
}
|
|
|
|
if (wrappingKey == NULL) {
|
|
if (newPrivKey) {
|
|
SECKEY_DestroyPrivateKey(newPrivKey);
|
|
}
|
|
return SECFailure;
|
|
}
|
|
mech.mechanism = wrapType;
|
|
if (!param) {
|
|
param = param_free = PK11_ParamFromIV(wrapType, NULL);
|
|
}
|
|
if (param) {
|
|
mech.pParameter = param->data;
|
|
mech.ulParameterLen = param->len;
|
|
} else {
|
|
mech.pParameter = NULL;
|
|
mech.ulParameterLen = 0;
|
|
}
|
|
|
|
PK11_EnterSlotMonitor(privSlot);
|
|
crv = PK11_GETTAB(privSlot)->C_WrapKey(privSlot->session, &mech,
|
|
wrappingKey->objectID,
|
|
privKey->pkcs11ID,
|
|
wrappedKey->data, &len);
|
|
PK11_ExitSlotMonitor(privSlot);
|
|
|
|
if (newSymKey) {
|
|
PK11_FreeSymKey(newSymKey);
|
|
}
|
|
if (newPrivKey) {
|
|
SECKEY_DestroyPrivateKey(newPrivKey);
|
|
}
|
|
if (param_free) {
|
|
SECITEM_FreeItem(param_free,PR_TRUE);
|
|
}
|
|
|
|
if (crv != CKR_OK) {
|
|
PORT_SetError( PK11_MapError(crv) );
|
|
return SECFailure;
|
|
}
|
|
|
|
wrappedKey->len = len;
|
|
return SECSuccess;
|
|
}
|
|
|
|
#if 0
|
|
/*
|
|
* Sample code relating to linked list returned by PK11_FindGenericObjects
|
|
*/
|
|
|
|
/*
|
|
* You can walk the list with the following code:
|
|
*/
|
|
firstObj = PK11_FindGenericObjects(slot, objClass);
|
|
for (thisObj=firstObj;
|
|
thisObj;
|
|
thisObj=PK11_GetNextGenericObject(thisObj)) {
|
|
/* operate on thisObj */
|
|
}
|
|
/*
|
|
* If you want a particular object from the list...
|
|
*/
|
|
firstObj = PK11_FindGenericObjects(slot, objClass);
|
|
for (thisObj=firstObj;
|
|
thisObj;
|
|
thisObj=PK11_GetNextGenericObject(thisObj)) {
|
|
if (isMyObj(thisObj)) {
|
|
if ( thisObj == firstObj) {
|
|
/* NOTE: firstObj could be NULL at this point */
|
|
firstObj = PK11_GetNextGenericObject(thsObj);
|
|
}
|
|
PK11_UnlinkGenericObject(thisObj);
|
|
myObj = thisObj;
|
|
break;
|
|
}
|
|
}
|
|
|
|
PK11_DestroyGenericObjects(firstObj);
|
|
|
|
/* use myObj */
|
|
|
|
PK11_DestroyGenericObject(myObj);
|
|
#endif /* sample code */
|
|
|
|
/*
|
|
* return a linked, non-circular list of generic objects.
|
|
* If you are only interested
|
|
* in one object, just use the first object in the list. To find the
|
|
* rest of the list use PK11_GetNextGenericObject() to return the next object.
|
|
*/
|
|
PK11GenericObject *
|
|
PK11_FindGenericObjects(PK11SlotInfo *slot, CK_OBJECT_CLASS objClass)
|
|
{
|
|
CK_ATTRIBUTE template[1];
|
|
CK_ATTRIBUTE *attrs = template;
|
|
CK_OBJECT_HANDLE *objectIDs = NULL;
|
|
PK11GenericObject *lastObj = NULL, *obj;
|
|
PK11GenericObject *firstObj = NULL;
|
|
int i, count = 0;
|
|
|
|
|
|
PK11_SETATTRS(attrs, CKA_CLASS, &objClass, sizeof(objClass)); attrs++;
|
|
|
|
objectIDs = pk11_FindObjectsByTemplate(slot,template,1,&count);
|
|
if (objectIDs == NULL) {
|
|
return NULL;
|
|
}
|
|
|
|
/* where we connect our object once we've created it.. */
|
|
for (i=0; i < count; i++) {
|
|
obj = PORT_New(PK11GenericObject);
|
|
if ( !obj ) {
|
|
if (firstObj) {
|
|
PK11_DestroyGenericObjects(firstObj);
|
|
}
|
|
PORT_Free(objectIDs);
|
|
return NULL;
|
|
}
|
|
/* initialize it */
|
|
obj->slot = PK11_ReferenceSlot(slot);
|
|
obj->objectID = objectIDs[i];
|
|
obj->next = NULL;
|
|
obj->prev = NULL;
|
|
|
|
/* link it in */
|
|
if (firstObj == NULL) {
|
|
firstObj = obj;
|
|
} else {
|
|
PK11_LinkGenericObject(lastObj, obj);
|
|
}
|
|
lastObj = obj;
|
|
}
|
|
PORT_Free(objectIDs);
|
|
return firstObj;
|
|
}
|
|
|
|
/*
|
|
* get the Next Object in the list.
|
|
*/
|
|
PK11GenericObject *
|
|
PK11_GetNextGenericObject(PK11GenericObject *object)
|
|
{
|
|
return object->next;
|
|
}
|
|
|
|
PK11GenericObject *
|
|
PK11_GetPrevGenericObject(PK11GenericObject *object)
|
|
{
|
|
return object->prev;
|
|
}
|
|
|
|
/*
|
|
* Link a single object into a new list.
|
|
* if the object is already in another list, remove it first.
|
|
*/
|
|
SECStatus
|
|
PK11_LinkGenericObject(PK11GenericObject *list, PK11GenericObject *object)
|
|
{
|
|
PK11_UnlinkGenericObject(object);
|
|
object->prev = list;
|
|
object->next = list->next;
|
|
list->next = object;
|
|
if (object->next != NULL) {
|
|
object->next->prev = object;
|
|
}
|
|
return SECSuccess;
|
|
}
|
|
|
|
/*
|
|
* remove an object from the list. If the object isn't already in
|
|
* a list unlink becomes a noop.
|
|
*/
|
|
SECStatus
|
|
PK11_UnlinkGenericObject(PK11GenericObject *object)
|
|
{
|
|
if (object->prev != NULL) {
|
|
object->prev->next = object->next;
|
|
}
|
|
if (object->next != NULL) {
|
|
object->next->prev = object->prev;
|
|
}
|
|
|
|
object->next = NULL;
|
|
object->prev = NULL;
|
|
return SECSuccess;
|
|
}
|
|
|
|
/*
|
|
* This function removes a single object from the list and destroys it.
|
|
* For an already unlinked object there is no difference between
|
|
* PK11_DestroyGenericObject and PK11_DestroyGenericObjects
|
|
*/
|
|
SECStatus
|
|
PK11_DestroyGenericObject(PK11GenericObject *object)
|
|
{
|
|
if (object == NULL) {
|
|
return SECSuccess;
|
|
}
|
|
|
|
PK11_UnlinkGenericObject(object);
|
|
if (object->slot) {
|
|
PK11_FreeSlot(object->slot);
|
|
}
|
|
PORT_Free(object);
|
|
return SECSuccess;
|
|
}
|
|
|
|
/*
|
|
* walk down a link list of generic objects destroying them.
|
|
* This will destroy all objects in a list that the object is linked into.
|
|
* (the list is traversed in both directions).
|
|
*/
|
|
SECStatus
|
|
PK11_DestroyGenericObjects(PK11GenericObject *objects)
|
|
{
|
|
PK11GenericObject *nextObject;
|
|
PK11GenericObject *prevObject;
|
|
|
|
if (objects == NULL) {
|
|
return SECSuccess;
|
|
}
|
|
|
|
nextObject = objects->next;
|
|
prevObject = objects->prev;
|
|
|
|
/* delete all the objects after it in the list */
|
|
for (; objects; objects = nextObject) {
|
|
nextObject = objects->next;
|
|
PK11_DestroyGenericObject(objects);
|
|
}
|
|
/* delete all the objects before it in the list */
|
|
for (objects = prevObject; objects; objects = prevObject) {
|
|
prevObject = objects->prev;
|
|
PK11_DestroyGenericObject(objects);
|
|
}
|
|
return SECSuccess;
|
|
}
|
|
|
|
|
|
/*
|
|
* Hand Create a new object and return the Generic object for our new object.
|
|
*/
|
|
PK11GenericObject *
|
|
PK11_CreateGenericObject(PK11SlotInfo *slot, const CK_ATTRIBUTE *pTemplate,
|
|
int count, PRBool token)
|
|
{
|
|
CK_OBJECT_HANDLE objectID;
|
|
PK11GenericObject *obj;
|
|
CK_RV crv;
|
|
|
|
PK11_EnterSlotMonitor(slot);
|
|
crv = PK11_CreateNewObject(slot, slot->session, pTemplate, count,
|
|
token, &objectID);
|
|
PK11_ExitSlotMonitor(slot);
|
|
if (crv != CKR_OK) {
|
|
PORT_SetError(PK11_MapError(crv));
|
|
return NULL;
|
|
}
|
|
|
|
obj = PORT_New(PK11GenericObject);
|
|
if ( !obj ) {
|
|
/* error set by PORT_New */
|
|
return NULL;
|
|
}
|
|
|
|
/* initialize it */
|
|
obj->slot = PK11_ReferenceSlot(slot);
|
|
obj->objectID = objectID;
|
|
obj->next = NULL;
|
|
obj->prev = NULL;
|
|
return obj;
|
|
}
|
|
|
|
/*
|
|
* Change an attribute on a raw object
|
|
*/
|
|
SECStatus
|
|
PK11_WriteRawAttribute(PK11ObjectType objType, void *objSpec,
|
|
CK_ATTRIBUTE_TYPE attrType, SECItem *item)
|
|
{
|
|
PK11SlotInfo *slot = NULL;
|
|
CK_OBJECT_HANDLE handle;
|
|
CK_ATTRIBUTE setTemplate;
|
|
CK_RV crv;
|
|
CK_SESSION_HANDLE rwsession;
|
|
|
|
switch (objType) {
|
|
case PK11_TypeGeneric:
|
|
slot = ((PK11GenericObject *)objSpec)->slot;
|
|
handle = ((PK11GenericObject *)objSpec)->objectID;
|
|
break;
|
|
case PK11_TypePrivKey:
|
|
slot = ((SECKEYPrivateKey *)objSpec)->pkcs11Slot;
|
|
handle = ((SECKEYPrivateKey *)objSpec)->pkcs11ID;
|
|
break;
|
|
case PK11_TypePubKey:
|
|
slot = ((SECKEYPublicKey *)objSpec)->pkcs11Slot;
|
|
handle = ((SECKEYPublicKey *)objSpec)->pkcs11ID;
|
|
break;
|
|
case PK11_TypeSymKey:
|
|
slot = ((PK11SymKey *)objSpec)->slot;
|
|
handle = ((PK11SymKey *)objSpec)->objectID;
|
|
break;
|
|
case PK11_TypeCert: /* don't handle cert case for now */
|
|
default:
|
|
break;
|
|
}
|
|
if (slot == NULL) {
|
|
PORT_SetError(SEC_ERROR_UNKNOWN_OBJECT_TYPE);
|
|
return SECFailure;
|
|
}
|
|
|
|
PK11_SETATTRS(&setTemplate, attrType, (CK_CHAR *) item->data, item->len);
|
|
rwsession = PK11_GetRWSession(slot);
|
|
if (rwsession == CK_INVALID_SESSION) {
|
|
PORT_SetError(SEC_ERROR_BAD_DATA);
|
|
return SECFailure;
|
|
}
|
|
crv = PK11_GETTAB(slot)->C_SetAttributeValue(rwsession, handle,
|
|
&setTemplate, 1);
|
|
PK11_RestoreROSession(slot, rwsession);
|
|
if (crv != CKR_OK) {
|
|
PORT_SetError(PK11_MapError(crv));
|
|
return SECFailure;
|
|
}
|
|
return SECSuccess;
|
|
}
|
|
|
|
|
|
SECStatus
|
|
PK11_ReadRawAttribute(PK11ObjectType objType, void *objSpec,
|
|
CK_ATTRIBUTE_TYPE attrType, SECItem *item)
|
|
{
|
|
PK11SlotInfo *slot = NULL;
|
|
CK_OBJECT_HANDLE handle;
|
|
|
|
switch (objType) {
|
|
case PK11_TypeGeneric:
|
|
slot = ((PK11GenericObject *)objSpec)->slot;
|
|
handle = ((PK11GenericObject *)objSpec)->objectID;
|
|
break;
|
|
case PK11_TypePrivKey:
|
|
slot = ((SECKEYPrivateKey *)objSpec)->pkcs11Slot;
|
|
handle = ((SECKEYPrivateKey *)objSpec)->pkcs11ID;
|
|
break;
|
|
case PK11_TypePubKey:
|
|
slot = ((SECKEYPublicKey *)objSpec)->pkcs11Slot;
|
|
handle = ((SECKEYPublicKey *)objSpec)->pkcs11ID;
|
|
break;
|
|
case PK11_TypeSymKey:
|
|
slot = ((PK11SymKey *)objSpec)->slot;
|
|
handle = ((PK11SymKey *)objSpec)->objectID;
|
|
break;
|
|
case PK11_TypeCert: /* don't handle cert case for now */
|
|
default:
|
|
break;
|
|
}
|
|
if (slot == NULL) {
|
|
PORT_SetError(SEC_ERROR_UNKNOWN_OBJECT_TYPE);
|
|
return SECFailure;
|
|
}
|
|
|
|
return PK11_ReadAttribute(slot, handle, attrType, NULL, item);
|
|
}
|
|
|
|
|
|
/*
|
|
* return the object handle that matches the template
|
|
*/
|
|
CK_OBJECT_HANDLE
|
|
pk11_FindObjectByTemplate(PK11SlotInfo *slot,CK_ATTRIBUTE *theTemplate,int tsize)
|
|
{
|
|
CK_OBJECT_HANDLE object;
|
|
CK_RV crv = CKR_SESSION_HANDLE_INVALID;
|
|
CK_ULONG objectCount;
|
|
|
|
/*
|
|
* issue the find
|
|
*/
|
|
PK11_EnterSlotMonitor(slot);
|
|
if (slot->session != CK_INVALID_SESSION) {
|
|
crv = PK11_GETTAB(slot)->C_FindObjectsInit(slot->session,
|
|
theTemplate, tsize);
|
|
}
|
|
if (crv != CKR_OK) {
|
|
PK11_ExitSlotMonitor(slot);
|
|
PORT_SetError( PK11_MapError(crv) );
|
|
return CK_INVALID_HANDLE;
|
|
}
|
|
|
|
crv=PK11_GETTAB(slot)->C_FindObjects(slot->session,&object,1,&objectCount);
|
|
PK11_GETTAB(slot)->C_FindObjectsFinal(slot->session);
|
|
PK11_ExitSlotMonitor(slot);
|
|
if ((crv != CKR_OK) || (objectCount < 1)) {
|
|
/* shouldn't use SSL_ERROR... here */
|
|
PORT_SetError( crv != CKR_OK ? PK11_MapError(crv) :
|
|
SSL_ERROR_NO_CERTIFICATE);
|
|
return CK_INVALID_HANDLE;
|
|
}
|
|
|
|
/* blow up if the PKCS #11 module returns us and invalid object handle */
|
|
PORT_Assert(object != CK_INVALID_HANDLE);
|
|
return object;
|
|
}
|
|
|
|
/*
|
|
* return all the object handles that matches the template
|
|
*/
|
|
CK_OBJECT_HANDLE *
|
|
pk11_FindObjectsByTemplate(PK11SlotInfo *slot, CK_ATTRIBUTE *findTemplate,
|
|
int templCount, int *object_count)
|
|
{
|
|
CK_OBJECT_HANDLE *objID = NULL;
|
|
CK_ULONG returned_count = 0;
|
|
CK_RV crv = CKR_SESSION_HANDLE_INVALID;
|
|
|
|
PK11_EnterSlotMonitor(slot);
|
|
if (slot->session != CK_INVALID_SESSION) {
|
|
crv = PK11_GETTAB(slot)->C_FindObjectsInit(slot->session,
|
|
findTemplate, templCount);
|
|
}
|
|
if (crv != CKR_OK) {
|
|
PK11_ExitSlotMonitor(slot);
|
|
PORT_SetError( PK11_MapError(crv) );
|
|
*object_count = -1;
|
|
return NULL;
|
|
}
|
|
|
|
|
|
/*
|
|
* collect all the Matching Objects
|
|
*/
|
|
do {
|
|
CK_OBJECT_HANDLE *oldObjID = objID;
|
|
|
|
if (objID == NULL) {
|
|
objID = (CK_OBJECT_HANDLE *) PORT_Alloc(sizeof(CK_OBJECT_HANDLE)*
|
|
(*object_count+ PK11_SEARCH_CHUNKSIZE));
|
|
} else {
|
|
objID = (CK_OBJECT_HANDLE *) PORT_Realloc(objID,
|
|
sizeof(CK_OBJECT_HANDLE)*(*object_count+PK11_SEARCH_CHUNKSIZE));
|
|
}
|
|
|
|
if (objID == NULL) {
|
|
if (oldObjID) PORT_Free(oldObjID);
|
|
break;
|
|
}
|
|
crv = PK11_GETTAB(slot)->C_FindObjects(slot->session,
|
|
&objID[*object_count],PK11_SEARCH_CHUNKSIZE,&returned_count);
|
|
if (crv != CKR_OK) {
|
|
PORT_SetError( PK11_MapError(crv) );
|
|
PORT_Free(objID);
|
|
objID = NULL;
|
|
break;
|
|
}
|
|
*object_count += returned_count;
|
|
} while (returned_count == PK11_SEARCH_CHUNKSIZE);
|
|
|
|
PK11_GETTAB(slot)->C_FindObjectsFinal(slot->session);
|
|
PK11_ExitSlotMonitor(slot);
|
|
|
|
if (objID && (*object_count == 0)) {
|
|
PORT_Free(objID);
|
|
return NULL;
|
|
}
|
|
if (objID == NULL) *object_count = -1;
|
|
return objID;
|
|
}
|
|
/*
|
|
* given a PKCS #11 object, match it's peer based on the KeyID. searchID
|
|
* is typically a privateKey or a certificate while the peer is the opposite
|
|
*/
|
|
CK_OBJECT_HANDLE
|
|
PK11_MatchItem(PK11SlotInfo *slot, CK_OBJECT_HANDLE searchID,
|
|
CK_OBJECT_CLASS matchclass)
|
|
{
|
|
CK_ATTRIBUTE theTemplate[] = {
|
|
{ CKA_ID, NULL, 0 },
|
|
{ CKA_CLASS, NULL, 0 }
|
|
};
|
|
/* if you change the array, change the variable below as well */
|
|
CK_ATTRIBUTE *keyclass = &theTemplate[1];
|
|
int tsize = sizeof(theTemplate)/sizeof(theTemplate[0]);
|
|
/* if you change the array, change the variable below as well */
|
|
CK_OBJECT_HANDLE peerID;
|
|
PLArenaPool *arena;
|
|
CK_RV crv;
|
|
|
|
/* now we need to create space for the public key */
|
|
arena = PORT_NewArena( DER_DEFAULT_CHUNKSIZE);
|
|
if (arena == NULL) return CK_INVALID_HANDLE;
|
|
|
|
crv = PK11_GetAttributes(arena,slot,searchID,theTemplate,tsize);
|
|
if (crv != CKR_OK) {
|
|
PORT_FreeArena(arena,PR_FALSE);
|
|
PORT_SetError( PK11_MapError(crv) );
|
|
return CK_INVALID_HANDLE;
|
|
}
|
|
|
|
if ((theTemplate[0].ulValueLen == 0) || (theTemplate[0].ulValueLen == -1)) {
|
|
PORT_FreeArena(arena,PR_FALSE);
|
|
if (matchclass == CKO_CERTIFICATE)
|
|
PORT_SetError(SEC_ERROR_BAD_KEY);
|
|
else
|
|
PORT_SetError(SEC_ERROR_NO_KEY);
|
|
return CK_INVALID_HANDLE;
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
* issue the find
|
|
*/
|
|
*(CK_OBJECT_CLASS *)(keyclass->pValue) = matchclass;
|
|
|
|
peerID = pk11_FindObjectByTemplate(slot,theTemplate,tsize);
|
|
PORT_FreeArena(arena,PR_FALSE);
|
|
|
|
return peerID;
|
|
}
|
|
|
|
/*
|
|
* count the number of objects that match the template.
|
|
*/
|
|
int
|
|
PK11_NumberObjectsFor(PK11SlotInfo *slot, CK_ATTRIBUTE *findTemplate,
|
|
int templCount)
|
|
{
|
|
CK_OBJECT_HANDLE objID[PK11_SEARCH_CHUNKSIZE];
|
|
int object_count = 0;
|
|
CK_ULONG returned_count = 0;
|
|
CK_RV crv = CKR_SESSION_HANDLE_INVALID;
|
|
|
|
PK11_EnterSlotMonitor(slot);
|
|
if (slot->session != CK_INVALID_SESSION) {
|
|
crv = PK11_GETTAB(slot)->C_FindObjectsInit(slot->session,
|
|
findTemplate, templCount);
|
|
}
|
|
if (crv != CKR_OK) {
|
|
PK11_ExitSlotMonitor(slot);
|
|
PORT_SetError( PK11_MapError(crv) );
|
|
return object_count;
|
|
}
|
|
|
|
/*
|
|
* collect all the Matching Objects
|
|
*/
|
|
do {
|
|
crv = PK11_GETTAB(slot)->C_FindObjects(slot->session, objID,
|
|
PK11_SEARCH_CHUNKSIZE,
|
|
&returned_count);
|
|
if (crv != CKR_OK) {
|
|
PORT_SetError( PK11_MapError(crv) );
|
|
break;
|
|
}
|
|
object_count += returned_count;
|
|
} while (returned_count == PK11_SEARCH_CHUNKSIZE);
|
|
|
|
PK11_GETTAB(slot)->C_FindObjectsFinal(slot->session);
|
|
PK11_ExitSlotMonitor(slot);
|
|
return object_count;
|
|
}
|
|
|
|
/*
|
|
* Traverse all the objects in a given slot.
|
|
*/
|
|
SECStatus
|
|
PK11_TraverseSlot(PK11SlotInfo *slot, void *arg)
|
|
{
|
|
int i;
|
|
CK_OBJECT_HANDLE *objID = NULL;
|
|
int object_count = 0;
|
|
pk11TraverseSlot *slotcb = (pk11TraverseSlot*) arg;
|
|
|
|
objID = pk11_FindObjectsByTemplate(slot,slotcb->findTemplate,
|
|
slotcb->templateCount,&object_count);
|
|
|
|
/*Actually this isn't a failure... there just were no objs to be found*/
|
|
if (object_count == 0) {
|
|
return SECSuccess;
|
|
}
|
|
|
|
if (objID == NULL) {
|
|
return SECFailure;
|
|
}
|
|
|
|
for (i=0; i < object_count; i++) {
|
|
(*slotcb->callback)(slot,objID[i],slotcb->callbackArg);
|
|
}
|
|
PORT_Free(objID);
|
|
return SECSuccess;
|
|
}
|
|
|
|
/*
|
|
* Traverse all the objects in all slots.
|
|
*/
|
|
SECStatus
|
|
pk11_TraverseAllSlots( SECStatus (*callback)(PK11SlotInfo *,void *),
|
|
void *arg, PRBool forceLogin, void *wincx) {
|
|
PK11SlotList *list;
|
|
PK11SlotListElement *le;
|
|
SECStatus rv;
|
|
|
|
/* get them all! */
|
|
list = PK11_GetAllTokens(CKM_INVALID_MECHANISM,PR_FALSE,PR_FALSE,wincx);
|
|
if (list == NULL) return SECFailure;
|
|
|
|
/* look at each slot and authenticate as necessary */
|
|
for (le = list->head ; le; le = le->next) {
|
|
if (forceLogin) {
|
|
rv = pk11_AuthenticateUnfriendly(le->slot, PR_FALSE, wincx);
|
|
if (rv != SECSuccess) {
|
|
continue;
|
|
}
|
|
}
|
|
if (callback) {
|
|
(*callback)(le->slot,arg);
|
|
}
|
|
}
|
|
|
|
PK11_FreeSlotList(list);
|
|
|
|
return SECSuccess;
|
|
}
|
|
|
|
CK_OBJECT_HANDLE *
|
|
PK11_FindObjectsFromNickname(char *nickname,PK11SlotInfo **slotptr,
|
|
CK_OBJECT_CLASS objclass, int *returnCount, void *wincx)
|
|
{
|
|
char *tokenName;
|
|
char *delimit;
|
|
PK11SlotInfo *slot;
|
|
CK_OBJECT_HANDLE *objID;
|
|
CK_ATTRIBUTE findTemplate[] = {
|
|
{ CKA_LABEL, NULL, 0},
|
|
{ CKA_CLASS, NULL, 0},
|
|
};
|
|
int findCount = sizeof(findTemplate)/sizeof(findTemplate[0]);
|
|
SECStatus rv;
|
|
PK11_SETATTRS(&findTemplate[1], CKA_CLASS, &objclass, sizeof(objclass));
|
|
|
|
*slotptr = slot = NULL;
|
|
*returnCount = 0;
|
|
/* first find the slot associated with this nickname */
|
|
if ((delimit = PORT_Strchr(nickname,':')) != NULL) {
|
|
int len = delimit - nickname;
|
|
tokenName = (char*)PORT_Alloc(len+1);
|
|
PORT_Memcpy(tokenName,nickname,len);
|
|
tokenName[len] = 0;
|
|
|
|
slot = *slotptr = PK11_FindSlotByName(tokenName);
|
|
PORT_Free(tokenName);
|
|
/* if we couldn't find a slot, assume the nickname is an internal cert
|
|
* with no proceding slot name */
|
|
if (slot == NULL) {
|
|
slot = *slotptr = PK11_GetInternalKeySlot();
|
|
} else {
|
|
nickname = delimit+1;
|
|
}
|
|
} else {
|
|
*slotptr = slot = PK11_GetInternalKeySlot();
|
|
}
|
|
if (slot == NULL) {
|
|
return CK_INVALID_HANDLE;
|
|
}
|
|
|
|
rv = pk11_AuthenticateUnfriendly(slot, PR_TRUE, wincx);
|
|
if (rv != SECSuccess) {
|
|
PK11_FreeSlot(slot);
|
|
*slotptr = NULL;
|
|
return CK_INVALID_HANDLE;
|
|
}
|
|
|
|
findTemplate[0].pValue = nickname;
|
|
findTemplate[0].ulValueLen = PORT_Strlen(nickname);
|
|
objID = pk11_FindObjectsByTemplate(slot,findTemplate,findCount,returnCount);
|
|
if (objID == NULL) {
|
|
/* PKCS #11 isn't clear on whether or not the NULL is
|
|
* stored in the template.... try the find again with the
|
|
* full null terminated string. */
|
|
findTemplate[0].ulValueLen += 1;
|
|
objID = pk11_FindObjectsByTemplate(slot,findTemplate,findCount,
|
|
returnCount);
|
|
if (objID == NULL) {
|
|
/* Well that's the best we can do. It's just not here */
|
|
/* what about faked nicknames? */
|
|
PK11_FreeSlot(slot);
|
|
*slotptr = NULL;
|
|
*returnCount = 0;
|
|
}
|
|
}
|
|
|
|
return objID;
|
|
}
|
|
|
|
SECItem *
|
|
pk11_GetLowLevelKeyFromHandle(PK11SlotInfo *slot, CK_OBJECT_HANDLE handle)
|
|
{
|
|
CK_ATTRIBUTE theTemplate[] = {
|
|
{ CKA_ID, NULL, 0 },
|
|
};
|
|
int tsize = sizeof(theTemplate)/sizeof(theTemplate[0]);
|
|
CK_RV crv;
|
|
SECItem *item;
|
|
|
|
item = SECITEM_AllocItem(NULL, NULL, 0);
|
|
|
|
if (item == NULL) {
|
|
return NULL;
|
|
}
|
|
|
|
crv = PK11_GetAttributes(NULL,slot,handle,theTemplate,tsize);
|
|
if (crv != CKR_OK) {
|
|
SECITEM_FreeItem(item,PR_TRUE);
|
|
PORT_SetError( PK11_MapError(crv) );
|
|
return NULL;
|
|
}
|
|
|
|
item->data = (unsigned char*) theTemplate[0].pValue;
|
|
item->len =theTemplate[0].ulValueLen;
|
|
|
|
return item;
|
|
}
|
|
|