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