зеркало из https://github.com/mozilla/gecko-dev.git
2055 строки
56 KiB
C
2055 строки
56 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;
|
|
|
|
if (size == 0u) return NULL;
|
|
|
|
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)
|
|
{
|
|
CK_MECHANISM_TYPE mech = PK11_MapSignKeyType(key->keyType);
|
|
return PK11_VerifyWithMechanism(key, mech, NULL, sig, hash, wincx);
|
|
}
|
|
|
|
/*
|
|
* Verify a signature from its hash using the given algorithm.
|
|
*/
|
|
SECStatus
|
|
PK11_VerifyWithMechanism(SECKEYPublicKey *key, CK_MECHANISM_TYPE mechanism,
|
|
const SECItem *param, 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 = mechanism;
|
|
if (param) {
|
|
mech.pParameter = param->data;
|
|
mech.ulParameterLen = param->len;
|
|
}
|
|
|
|
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)
|
|
{
|
|
CK_MECHANISM_TYPE mech = PK11_MapSignKeyType(key->keyType);
|
|
return PK11_SignWithMechanism(key, mech, NULL, sig, hash);
|
|
}
|
|
|
|
/*
|
|
* Sign a hash using the given algorithm.
|
|
*/
|
|
SECStatus
|
|
PK11_SignWithMechanism(SECKEYPrivateKey *key, CK_MECHANISM_TYPE mechanism,
|
|
const SECItem *param, 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 = mechanism;
|
|
if (param) {
|
|
mech.pParameter = param->data;
|
|
mech.ulParameterLen = param->len;
|
|
}
|
|
|
|
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 = 0;
|
|
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 = 0;
|
|
|
|
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;
|
|
PORTCheapArenaPool tmpArena;
|
|
CK_RV crv;
|
|
|
|
/* now we need to create space for the public key */
|
|
PORT_InitCheapArena(&tmpArena, DER_DEFAULT_CHUNKSIZE);
|
|
|
|
crv = PK11_GetAttributes(&tmpArena.arena,slot,searchID,theTemplate,tsize);
|
|
if (crv != CKR_OK) {
|
|
PORT_DestroyCheapArena(&tmpArena);
|
|
PORT_SetError( PK11_MapError(crv) );
|
|
return CK_INVALID_HANDLE;
|
|
}
|
|
|
|
if ((theTemplate[0].ulValueLen == 0) || (theTemplate[0].ulValueLen == -1)) {
|
|
PORT_DestroyCheapArena(&tmpArena);
|
|
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_DestroyCheapArena(&tmpArena);
|
|
|
|
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;
|
|
}
|
|
|