mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-06 00:55:37 +00:00
e35607b9c4
r=julien
3477 lines
96 KiB
C
3477 lines
96 KiB
C
/* ***** BEGIN LICENSE BLOCK *****
|
|
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
|
*
|
|
* The contents of this file are subject to the Mozilla Public License Version
|
|
* 1.1 (the "License"); you may not use this file except in compliance with
|
|
* the License. You may obtain a copy of the License at
|
|
* http://www.mozilla.org/MPL/
|
|
*
|
|
* Software distributed under the License is distributed on an "AS IS" basis,
|
|
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
|
* for the specific language governing rights and limitations under the
|
|
* License.
|
|
*
|
|
* The Original Code is the Netscape security libraries.
|
|
*
|
|
* The Initial Developer of the Original Code is
|
|
* Netscape Communications Corporation.
|
|
* Portions created by the Initial Developer are Copyright (C) 1994-2000
|
|
* the Initial Developer. All Rights Reserved.
|
|
*
|
|
* Contributor(s):
|
|
* Dr Vipul Gupta <vipul.gupta@sun.com>, Sun Microsystems Laboratories
|
|
*
|
|
* Alternatively, the contents of this file may be used under the terms of
|
|
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
|
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
|
* in which case the provisions of the GPL or the LGPL are applicable instead
|
|
* of those above. If you wish to allow use of your version of this file only
|
|
* under the terms of either the GPL or the LGPL, and not to allow others to
|
|
* use your version of this file under the terms of the MPL, indicate your
|
|
* decision by deleting the provisions above and replace them with the notice
|
|
* and other provisions required by the GPL or the LGPL. If you do not delete
|
|
* the provisions above, a recipient may use your version of this file under
|
|
* the terms of any one of the MPL, the GPL or the LGPL.
|
|
*
|
|
* ***** END LICENSE BLOCK ***** */
|
|
/*
|
|
* Internal PKCS #11 functions. Should only be called by pkcs11.c
|
|
*/
|
|
#include "pkcs11.h"
|
|
#include "pkcs11i.h"
|
|
#include "pcertt.h"
|
|
#include "lowkeyi.h"
|
|
#include "pcert.h"
|
|
#include "secasn1.h"
|
|
#include "blapi.h"
|
|
#include "secerr.h"
|
|
#include "prnetdb.h" /* for PR_ntohl */
|
|
|
|
/*
|
|
* ******************** Attribute Utilities *******************************
|
|
*/
|
|
|
|
/*
|
|
* create a new attribute with type, value, and length. Space is allocated
|
|
* to hold value.
|
|
*/
|
|
static SFTKAttribute *
|
|
sftk_NewAttribute(SFTKObject *object,
|
|
CK_ATTRIBUTE_TYPE type, CK_VOID_PTR value, CK_ULONG len)
|
|
{
|
|
SFTKAttribute *attribute;
|
|
|
|
SFTKSessionObject *so = sftk_narrowToSessionObject(object);
|
|
int index;
|
|
|
|
if (so == NULL) {
|
|
/* allocate new attribute in a buffer */
|
|
PORT_Assert(0);
|
|
}
|
|
/*
|
|
* We attempt to keep down contention on Malloc and Arena locks by
|
|
* limiting the number of these calls on high traversed paths. This
|
|
* is done for attributes by 'allocating' them from a pool already
|
|
* allocated by the parent object.
|
|
*/
|
|
PZ_Lock(so->attributeLock);
|
|
index = so->nextAttr++;
|
|
PZ_Unlock(so->attributeLock);
|
|
PORT_Assert(index < MAX_OBJS_ATTRS);
|
|
if (index >= MAX_OBJS_ATTRS) return NULL;
|
|
|
|
attribute = &so->attrList[index];
|
|
attribute->attrib.type = type;
|
|
attribute->freeAttr = PR_FALSE;
|
|
attribute->freeData = PR_FALSE;
|
|
if (value) {
|
|
if (len <= ATTR_SPACE) {
|
|
attribute->attrib.pValue = attribute->space;
|
|
} else {
|
|
attribute->attrib.pValue = PORT_Alloc(len);
|
|
attribute->freeData = PR_TRUE;
|
|
}
|
|
if (attribute->attrib.pValue == NULL) {
|
|
return NULL;
|
|
}
|
|
PORT_Memcpy(attribute->attrib.pValue,value,len);
|
|
attribute->attrib.ulValueLen = len;
|
|
} else {
|
|
attribute->attrib.pValue = NULL;
|
|
attribute->attrib.ulValueLen = 0;
|
|
}
|
|
attribute->attrib.type = type;
|
|
attribute->handle = type;
|
|
attribute->next = attribute->prev = NULL;
|
|
return attribute;
|
|
}
|
|
|
|
static SFTKAttribute *
|
|
sftk_NewTokenAttribute(CK_ATTRIBUTE_TYPE type, CK_VOID_PTR value,
|
|
CK_ULONG len, PRBool copy)
|
|
{
|
|
SFTKAttribute *attribute;
|
|
|
|
attribute = (SFTKAttribute*)PORT_Alloc(sizeof(SFTKAttribute));
|
|
|
|
if (attribute == NULL) return NULL;
|
|
attribute->attrib.type = type;
|
|
attribute->handle = type;
|
|
attribute->next = attribute->prev = NULL;
|
|
attribute->freeAttr = PR_TRUE;
|
|
attribute->freeData = PR_FALSE;
|
|
attribute->attrib.type = type;
|
|
if (!copy) {
|
|
attribute->attrib.pValue = value;
|
|
attribute->attrib.ulValueLen = len;
|
|
return attribute;
|
|
}
|
|
|
|
if (value) {
|
|
if (len <= ATTR_SPACE) {
|
|
attribute->attrib.pValue = attribute->space;
|
|
} else {
|
|
attribute->attrib.pValue = PORT_Alloc(len);
|
|
attribute->freeData = PR_TRUE;
|
|
}
|
|
if (attribute->attrib.pValue == NULL) {
|
|
PORT_Free(attribute);
|
|
return NULL;
|
|
}
|
|
PORT_Memcpy(attribute->attrib.pValue,value,len);
|
|
attribute->attrib.ulValueLen = len;
|
|
} else {
|
|
attribute->attrib.pValue = NULL;
|
|
attribute->attrib.ulValueLen = 0;
|
|
}
|
|
return attribute;
|
|
}
|
|
|
|
static SFTKAttribute *
|
|
sftk_NewTokenAttributeSigned(CK_ATTRIBUTE_TYPE type, CK_VOID_PTR value,
|
|
CK_ULONG len, PRBool copy)
|
|
{
|
|
unsigned char * dval = (unsigned char *)value;
|
|
if (*dval == 0) {
|
|
dval++;
|
|
len--;
|
|
}
|
|
return sftk_NewTokenAttribute(type,dval,len,copy);
|
|
}
|
|
|
|
/*
|
|
* Free up all the memory associated with an attribute. Reference count
|
|
* must be zero to call this.
|
|
*/
|
|
static void
|
|
sftk_DestroyAttribute(SFTKAttribute *attribute)
|
|
{
|
|
if (attribute->freeData) {
|
|
if (attribute->attrib.pValue) {
|
|
/* clear out the data in the attribute value... it may have been
|
|
* sensitive data */
|
|
PORT_Memset(attribute->attrib.pValue, 0,
|
|
attribute->attrib.ulValueLen);
|
|
}
|
|
PORT_Free(attribute->attrib.pValue);
|
|
}
|
|
PORT_Free(attribute);
|
|
}
|
|
|
|
/*
|
|
* release a reference to an attribute structure
|
|
*/
|
|
void
|
|
sftk_FreeAttribute(SFTKAttribute *attribute)
|
|
{
|
|
if (attribute->freeAttr) {
|
|
sftk_DestroyAttribute(attribute);
|
|
return;
|
|
}
|
|
}
|
|
|
|
#define SFTK_DEF_ATTRIBUTE(value,len) \
|
|
{ NULL, NULL, PR_FALSE, PR_FALSE, 0, { 0, value, len } }
|
|
|
|
#define SFTK_CLONE_ATTR(type, staticAttr) \
|
|
sftk_NewTokenAttribute( type, staticAttr.attrib.pValue, \
|
|
staticAttr.attrib.ulValueLen, PR_FALSE)
|
|
|
|
CK_BBOOL sftk_staticTrueValue = CK_TRUE;
|
|
CK_BBOOL sftk_staticFalseValue = CK_FALSE;
|
|
static const SFTKAttribute sftk_StaticTrueAttr =
|
|
SFTK_DEF_ATTRIBUTE(&sftk_staticTrueValue,sizeof(sftk_staticTrueValue));
|
|
static const SFTKAttribute sftk_StaticFalseAttr =
|
|
SFTK_DEF_ATTRIBUTE(&sftk_staticFalseValue,sizeof(sftk_staticFalseValue));
|
|
static const SFTKAttribute sftk_StaticNullAttr = SFTK_DEF_ATTRIBUTE(NULL,0);
|
|
char sftk_StaticOneValue = 1;
|
|
static const SFTKAttribute sftk_StaticOneAttr =
|
|
SFTK_DEF_ATTRIBUTE(&sftk_StaticOneValue,sizeof(sftk_StaticOneValue));
|
|
|
|
CK_CERTIFICATE_TYPE sftk_staticX509Value = CKC_X_509;
|
|
static const SFTKAttribute sftk_StaticX509Attr =
|
|
SFTK_DEF_ATTRIBUTE(&sftk_staticX509Value, sizeof(sftk_staticX509Value));
|
|
CK_TRUST sftk_staticTrustedValue = CKT_NETSCAPE_TRUSTED;
|
|
CK_TRUST sftk_staticTrustedDelegatorValue = CKT_NETSCAPE_TRUSTED_DELEGATOR;
|
|
CK_TRUST sftk_staticValidDelegatorValue = CKT_NETSCAPE_VALID_DELEGATOR;
|
|
CK_TRUST sftk_staticUnTrustedValue = CKT_NETSCAPE_UNTRUSTED;
|
|
CK_TRUST sftk_staticTrustUnknownValue = CKT_NETSCAPE_TRUST_UNKNOWN;
|
|
CK_TRUST sftk_staticValidPeerValue = CKT_NETSCAPE_VALID;
|
|
CK_TRUST sftk_staticMustVerifyValue = CKT_NETSCAPE_MUST_VERIFY;
|
|
static const SFTKAttribute sftk_StaticTrustedAttr =
|
|
SFTK_DEF_ATTRIBUTE(&sftk_staticTrustedValue,
|
|
sizeof(sftk_staticTrustedValue));
|
|
static const SFTKAttribute sftk_StaticTrustedDelegatorAttr =
|
|
SFTK_DEF_ATTRIBUTE(&sftk_staticTrustedDelegatorValue,
|
|
sizeof(sftk_staticTrustedDelegatorValue));
|
|
static const SFTKAttribute sftk_StaticValidDelegatorAttr =
|
|
SFTK_DEF_ATTRIBUTE(&sftk_staticValidDelegatorValue,
|
|
sizeof(sftk_staticValidDelegatorValue));
|
|
static const SFTKAttribute sftk_StaticUnTrustedAttr =
|
|
SFTK_DEF_ATTRIBUTE(&sftk_staticUnTrustedValue,
|
|
sizeof(sftk_staticUnTrustedValue));
|
|
static const SFTKAttribute sftk_StaticTrustUnknownAttr =
|
|
SFTK_DEF_ATTRIBUTE(&sftk_staticTrustUnknownValue,
|
|
sizeof(sftk_staticTrustUnknownValue));
|
|
static const SFTKAttribute sftk_StaticValidPeerAttr =
|
|
SFTK_DEF_ATTRIBUTE(&sftk_staticValidPeerValue,
|
|
sizeof(sftk_staticValidPeerValue));
|
|
static const SFTKAttribute sftk_StaticMustVerifyAttr =
|
|
SFTK_DEF_ATTRIBUTE(&sftk_staticMustVerifyValue,
|
|
sizeof(sftk_staticMustVerifyValue));
|
|
|
|
/*
|
|
* helper functions which get the database and call the underlying
|
|
* low level database function.
|
|
*/
|
|
static char *
|
|
sftk_FindKeyNicknameByPublicKey(SFTKSlot *slot, SECItem *dbKey)
|
|
{
|
|
NSSLOWKEYDBHandle *keyHandle;
|
|
char * label;
|
|
|
|
keyHandle = sftk_getKeyDB(slot);
|
|
if (!keyHandle) {
|
|
return NULL;
|
|
}
|
|
|
|
label = nsslowkey_FindKeyNicknameByPublicKey(keyHandle, dbKey,
|
|
slot->password);
|
|
sftk_freeKeyDB(keyHandle);
|
|
return label;
|
|
}
|
|
|
|
|
|
NSSLOWKEYPrivateKey *
|
|
sftk_FindKeyByPublicKey(SFTKSlot *slot, SECItem *dbKey)
|
|
{
|
|
NSSLOWKEYPrivateKey *privKey;
|
|
NSSLOWKEYDBHandle *keyHandle;
|
|
|
|
keyHandle = sftk_getKeyDB(slot);
|
|
if (keyHandle == NULL) {
|
|
return NULL;
|
|
}
|
|
privKey = nsslowkey_FindKeyByPublicKey(keyHandle, dbKey, slot->password);
|
|
sftk_freeKeyDB(keyHandle);
|
|
if (privKey == NULL) {
|
|
return NULL;
|
|
}
|
|
return privKey;
|
|
}
|
|
|
|
static certDBEntrySMime *
|
|
sftk_getSMime(SFTKTokenObject *object)
|
|
{
|
|
certDBEntrySMime *entry;
|
|
NSSLOWCERTCertDBHandle *certHandle;
|
|
|
|
if (object->obj.objclass != CKO_NETSCAPE_SMIME) {
|
|
return NULL;
|
|
}
|
|
if (object->obj.objectInfo) {
|
|
return (certDBEntrySMime *)object->obj.objectInfo;
|
|
}
|
|
|
|
certHandle = sftk_getCertDB(object->obj.slot);
|
|
if (!certHandle) {
|
|
return NULL;
|
|
}
|
|
entry = nsslowcert_ReadDBSMimeEntry(certHandle, (char *)object->dbKey.data);
|
|
object->obj.objectInfo = (void *)entry;
|
|
object->obj.infoFree = (SFTKFree) nsslowcert_DestroyDBEntry;
|
|
sftk_freeCertDB(certHandle);
|
|
return entry;
|
|
}
|
|
|
|
static certDBEntryRevocation *
|
|
sftk_getCrl(SFTKTokenObject *object)
|
|
{
|
|
certDBEntryRevocation *crl;
|
|
PRBool isKrl;
|
|
NSSLOWCERTCertDBHandle *certHandle;
|
|
|
|
if (object->obj.objclass != CKO_NETSCAPE_CRL) {
|
|
return NULL;
|
|
}
|
|
if (object->obj.objectInfo) {
|
|
return (certDBEntryRevocation *)object->obj.objectInfo;
|
|
}
|
|
|
|
isKrl = (PRBool) (object->obj.handle == SFTK_TOKEN_KRL_HANDLE);
|
|
certHandle = sftk_getCertDB(object->obj.slot);
|
|
if (!certHandle) {
|
|
return NULL;
|
|
}
|
|
|
|
crl = nsslowcert_FindCrlByKey(certHandle, &object->dbKey, isKrl);
|
|
object->obj.objectInfo = (void *)crl;
|
|
object->obj.infoFree = (SFTKFree) nsslowcert_DestroyDBEntry;
|
|
sftk_freeCertDB(certHandle);
|
|
return crl;
|
|
}
|
|
|
|
static NSSLOWCERTCertificate *
|
|
sftk_getCert(SFTKTokenObject *object, NSSLOWCERTCertDBHandle *certHandle)
|
|
{
|
|
NSSLOWCERTCertificate *cert;
|
|
CK_OBJECT_CLASS objClass = object->obj.objclass;
|
|
|
|
if ((objClass != CKO_CERTIFICATE) && (objClass != CKO_NETSCAPE_TRUST)) {
|
|
return NULL;
|
|
}
|
|
if (objClass == CKO_CERTIFICATE && object->obj.objectInfo) {
|
|
return (NSSLOWCERTCertificate *)object->obj.objectInfo;
|
|
}
|
|
cert = nsslowcert_FindCertByKey(certHandle, &object->dbKey);
|
|
if (objClass == CKO_CERTIFICATE) {
|
|
object->obj.objectInfo = (void *)cert;
|
|
object->obj.infoFree = (SFTKFree) nsslowcert_DestroyCertificate ;
|
|
}
|
|
return cert;
|
|
}
|
|
|
|
static NSSLOWCERTTrust *
|
|
sftk_getTrust(SFTKTokenObject *object)
|
|
{
|
|
NSSLOWCERTTrust *trust;
|
|
NSSLOWCERTCertDBHandle *certHandle;
|
|
|
|
if (object->obj.objclass != CKO_NETSCAPE_TRUST) {
|
|
return NULL;
|
|
}
|
|
if (object->obj.objectInfo) {
|
|
return (NSSLOWCERTTrust *)object->obj.objectInfo;
|
|
}
|
|
certHandle = sftk_getCertDB(object->obj.slot);
|
|
if (!certHandle) {
|
|
return NULL;
|
|
}
|
|
trust = nsslowcert_FindTrustByKey(certHandle, &object->dbKey);
|
|
object->obj.objectInfo = (void *)trust;
|
|
object->obj.infoFree = (SFTKFree) nsslowcert_DestroyTrust ;
|
|
sftk_freeCertDB(certHandle);
|
|
return trust;
|
|
}
|
|
|
|
static NSSLOWKEYPublicKey *
|
|
sftk_GetPublicKey(SFTKTokenObject *object)
|
|
{
|
|
NSSLOWKEYPublicKey *pubKey;
|
|
NSSLOWKEYPrivateKey *privKey;
|
|
|
|
if (object->obj.objclass != CKO_PUBLIC_KEY) {
|
|
return NULL;
|
|
}
|
|
if (object->obj.objectInfo) {
|
|
return (NSSLOWKEYPublicKey *)object->obj.objectInfo;
|
|
}
|
|
privKey = sftk_FindKeyByPublicKey(object->obj.slot, &object->dbKey);
|
|
if (privKey == NULL) {
|
|
return NULL;
|
|
}
|
|
pubKey = nsslowkey_ConvertToPublicKey(privKey);
|
|
nsslowkey_DestroyPrivateKey(privKey);
|
|
object->obj.objectInfo = (void *) pubKey;
|
|
object->obj.infoFree = (SFTKFree) nsslowkey_DestroyPublicKey ;
|
|
return pubKey;
|
|
}
|
|
|
|
/*
|
|
* we need two versions of sftk_GetPrivateKey. One version that takes the
|
|
* DB handle so we can pass the handle we have already acquired in,
|
|
* rather than going through the 'getKeyDB' code again,
|
|
* which may fail the second time and another which just aquires
|
|
* the key handle from the slot (where we don't already have a key handle.
|
|
* This version does the former.
|
|
*/
|
|
static NSSLOWKEYPrivateKey *
|
|
sftk_GetPrivateKeyWithDB(SFTKTokenObject *object, NSSLOWKEYDBHandle *keyHandle)
|
|
{
|
|
NSSLOWKEYPrivateKey *privKey;
|
|
|
|
if ((object->obj.objclass != CKO_PRIVATE_KEY) &&
|
|
(object->obj.objclass != CKO_SECRET_KEY)) {
|
|
return NULL;
|
|
}
|
|
if (object->obj.objectInfo) {
|
|
return (NSSLOWKEYPrivateKey *)object->obj.objectInfo;
|
|
}
|
|
privKey = nsslowkey_FindKeyByPublicKey(keyHandle, &object->dbKey,
|
|
object->obj.slot->password);
|
|
if (privKey == NULL) {
|
|
return NULL;
|
|
}
|
|
object->obj.objectInfo = (void *) privKey;
|
|
object->obj.infoFree = (SFTKFree) nsslowkey_DestroyPrivateKey ;
|
|
return privKey;
|
|
}
|
|
|
|
/* this version does the latter */
|
|
static NSSLOWKEYPrivateKey *
|
|
sftk_GetPrivateKey(SFTKTokenObject *object)
|
|
{
|
|
NSSLOWKEYDBHandle *keyHandle;
|
|
NSSLOWKEYPrivateKey *privKey;
|
|
|
|
keyHandle = sftk_getKeyDB(object->obj.slot);
|
|
if (!keyHandle) {
|
|
return NULL;
|
|
}
|
|
privKey = sftk_GetPrivateKeyWithDB(object, keyHandle);
|
|
sftk_freeKeyDB(keyHandle);
|
|
return privKey;
|
|
}
|
|
|
|
/* sftk_GetPubItem returns data associated with the public key.
|
|
* one only needs to free the public key. This comment is here
|
|
* because this sematic would be non-obvious otherwise. All callers
|
|
* should include this comment.
|
|
*/
|
|
static SECItem *
|
|
sftk_GetPubItem(NSSLOWKEYPublicKey *pubKey) {
|
|
SECItem *pubItem = NULL;
|
|
/* get value to compare from the cert's public key */
|
|
switch ( pubKey->keyType ) {
|
|
case NSSLOWKEYRSAKey:
|
|
pubItem = &pubKey->u.rsa.modulus;
|
|
break;
|
|
case NSSLOWKEYDSAKey:
|
|
pubItem = &pubKey->u.dsa.publicValue;
|
|
break;
|
|
case NSSLOWKEYDHKey:
|
|
pubItem = &pubKey->u.dh.publicValue;
|
|
break;
|
|
#ifdef NSS_ENABLE_ECC
|
|
case NSSLOWKEYECKey:
|
|
pubItem = &pubKey->u.ec.publicValue;
|
|
break;
|
|
#endif /* NSS_ENABLE_ECC */
|
|
default:
|
|
break;
|
|
}
|
|
return pubItem;
|
|
}
|
|
|
|
static const SEC_ASN1Template sftk_SerialTemplate[] = {
|
|
{ SEC_ASN1_INTEGER, offsetof(NSSLOWCERTCertificate,serialNumber) },
|
|
{ 0 }
|
|
};
|
|
|
|
static SFTKAttribute *
|
|
sftk_FindRSAPublicKeyAttribute(NSSLOWKEYPublicKey *key, CK_ATTRIBUTE_TYPE type)
|
|
{
|
|
unsigned char hash[SHA1_LENGTH];
|
|
CK_KEY_TYPE keyType = CKK_RSA;
|
|
|
|
switch (type) {
|
|
case CKA_KEY_TYPE:
|
|
return sftk_NewTokenAttribute(type,&keyType,sizeof(keyType), PR_TRUE);
|
|
case CKA_ID:
|
|
SHA1_HashBuf(hash,key->u.rsa.modulus.data,key->u.rsa.modulus.len);
|
|
return sftk_NewTokenAttribute(type,hash,SHA1_LENGTH, PR_TRUE);
|
|
case CKA_DERIVE:
|
|
return SFTK_CLONE_ATTR(type,sftk_StaticFalseAttr);
|
|
case CKA_ENCRYPT:
|
|
case CKA_VERIFY:
|
|
case CKA_VERIFY_RECOVER:
|
|
case CKA_WRAP:
|
|
return SFTK_CLONE_ATTR(type,sftk_StaticTrueAttr);
|
|
case CKA_MODULUS:
|
|
return sftk_NewTokenAttributeSigned(type,key->u.rsa.modulus.data,
|
|
key->u.rsa.modulus.len, PR_FALSE);
|
|
case CKA_PUBLIC_EXPONENT:
|
|
return sftk_NewTokenAttributeSigned(type,key->u.rsa.publicExponent.data,
|
|
key->u.rsa.publicExponent.len, PR_FALSE);
|
|
default:
|
|
break;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
static SFTKAttribute *
|
|
sftk_FindDSAPublicKeyAttribute(NSSLOWKEYPublicKey *key, CK_ATTRIBUTE_TYPE type)
|
|
{
|
|
unsigned char hash[SHA1_LENGTH];
|
|
CK_KEY_TYPE keyType = CKK_DSA;
|
|
|
|
switch (type) {
|
|
case CKA_KEY_TYPE:
|
|
return sftk_NewTokenAttribute(type,&keyType,sizeof(keyType), PR_TRUE);
|
|
case CKA_ID:
|
|
SHA1_HashBuf(hash,key->u.dsa.publicValue.data,
|
|
key->u.dsa.publicValue.len);
|
|
return sftk_NewTokenAttribute(type,hash,SHA1_LENGTH, PR_TRUE);
|
|
case CKA_DERIVE:
|
|
case CKA_ENCRYPT:
|
|
case CKA_VERIFY_RECOVER:
|
|
case CKA_WRAP:
|
|
return SFTK_CLONE_ATTR(type,sftk_StaticFalseAttr);
|
|
case CKA_VERIFY:
|
|
return SFTK_CLONE_ATTR(type,sftk_StaticTrueAttr);
|
|
case CKA_VALUE:
|
|
return sftk_NewTokenAttributeSigned(type,key->u.dsa.publicValue.data,
|
|
key->u.dsa.publicValue.len, PR_FALSE);
|
|
case CKA_PRIME:
|
|
return sftk_NewTokenAttributeSigned(type,key->u.dsa.params.prime.data,
|
|
key->u.dsa.params.prime.len, PR_FALSE);
|
|
case CKA_SUBPRIME:
|
|
return sftk_NewTokenAttributeSigned(type,
|
|
key->u.dsa.params.subPrime.data,
|
|
key->u.dsa.params.subPrime.len, PR_FALSE);
|
|
case CKA_BASE:
|
|
return sftk_NewTokenAttributeSigned(type,key->u.dsa.params.base.data,
|
|
key->u.dsa.params.base.len, PR_FALSE);
|
|
default:
|
|
break;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
static SFTKAttribute *
|
|
sftk_FindDHPublicKeyAttribute(NSSLOWKEYPublicKey *key, CK_ATTRIBUTE_TYPE type)
|
|
{
|
|
unsigned char hash[SHA1_LENGTH];
|
|
CK_KEY_TYPE keyType = CKK_DH;
|
|
|
|
switch (type) {
|
|
case CKA_KEY_TYPE:
|
|
return sftk_NewTokenAttribute(type,&keyType,sizeof(keyType), PR_TRUE);
|
|
case CKA_ID:
|
|
SHA1_HashBuf(hash,key->u.dh.publicValue.data,key->u.dh.publicValue.len);
|
|
return sftk_NewTokenAttribute(type,hash,SHA1_LENGTH, PR_TRUE);
|
|
case CKA_DERIVE:
|
|
return SFTK_CLONE_ATTR(type,sftk_StaticTrueAttr);
|
|
case CKA_ENCRYPT:
|
|
case CKA_VERIFY:
|
|
case CKA_VERIFY_RECOVER:
|
|
case CKA_WRAP:
|
|
return SFTK_CLONE_ATTR(type,sftk_StaticFalseAttr);
|
|
case CKA_VALUE:
|
|
return sftk_NewTokenAttributeSigned(type,key->u.dh.publicValue.data,
|
|
key->u.dh.publicValue.len, PR_FALSE);
|
|
case CKA_PRIME:
|
|
return sftk_NewTokenAttributeSigned(type,key->u.dh.prime.data,
|
|
key->u.dh.prime.len, PR_FALSE);
|
|
case CKA_BASE:
|
|
return sftk_NewTokenAttributeSigned(type,key->u.dh.base.data,
|
|
key->u.dh.base.len, PR_FALSE);
|
|
default:
|
|
break;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
#ifdef NSS_ENABLE_ECC
|
|
static SFTKAttribute *
|
|
sftk_FindECPublicKeyAttribute(NSSLOWKEYPublicKey *key, CK_ATTRIBUTE_TYPE type)
|
|
{
|
|
unsigned char hash[SHA1_LENGTH];
|
|
CK_KEY_TYPE keyType = CKK_EC;
|
|
|
|
switch (type) {
|
|
case CKA_KEY_TYPE:
|
|
return sftk_NewTokenAttribute(type,&keyType,sizeof(keyType), PR_TRUE);
|
|
case CKA_ID:
|
|
SHA1_HashBuf(hash, key->u.ec.publicValue.data,
|
|
key->u.ec.publicValue.len);
|
|
return sftk_NewTokenAttribute(type,hash,SHA1_LENGTH, PR_TRUE);
|
|
case CKA_DERIVE:
|
|
case CKA_VERIFY:
|
|
return SFTK_CLONE_ATTR(type,sftk_StaticTrueAttr);
|
|
case CKA_ENCRYPT:
|
|
case CKA_VERIFY_RECOVER:
|
|
case CKA_WRAP:
|
|
return SFTK_CLONE_ATTR(type,sftk_StaticFalseAttr);
|
|
case CKA_EC_PARAMS:
|
|
/* XXX Why is the last arg PR_FALSE? */
|
|
return sftk_NewTokenAttributeSigned(type,
|
|
key->u.ec.ecParams.DEREncoding.data,
|
|
key->u.ec.ecParams.DEREncoding.len,
|
|
PR_FALSE);
|
|
case CKA_EC_POINT:
|
|
/* XXX Why is the last arg PR_FALSE? */
|
|
return sftk_NewTokenAttributeSigned(type,key->u.ec.publicValue.data,
|
|
key->u.ec.publicValue.len, PR_FALSE);
|
|
default:
|
|
break;
|
|
}
|
|
return NULL;
|
|
}
|
|
#endif /* NSS_ENABLE_ECC */
|
|
|
|
|
|
static SFTKAttribute *
|
|
sftk_FindPublicKeyAttribute(SFTKTokenObject *object, CK_ATTRIBUTE_TYPE type)
|
|
{
|
|
NSSLOWKEYPublicKey *key;
|
|
SFTKAttribute *att = NULL;
|
|
char *label;
|
|
|
|
switch (type) {
|
|
case CKA_PRIVATE:
|
|
case CKA_SENSITIVE:
|
|
case CKA_ALWAYS_SENSITIVE:
|
|
case CKA_NEVER_EXTRACTABLE:
|
|
return SFTK_CLONE_ATTR(type,sftk_StaticFalseAttr);
|
|
case CKA_MODIFIABLE:
|
|
case CKA_EXTRACTABLE:
|
|
return SFTK_CLONE_ATTR(type,sftk_StaticTrueAttr);
|
|
case CKA_LABEL:
|
|
label = sftk_FindKeyNicknameByPublicKey(object->obj.slot,
|
|
&object->dbKey);
|
|
if (label == NULL) {
|
|
return SFTK_CLONE_ATTR(type,sftk_StaticOneAttr);
|
|
}
|
|
att = sftk_NewTokenAttribute(type,label,PORT_Strlen(label), PR_TRUE);
|
|
PORT_Free(label);
|
|
return att;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
key = sftk_GetPublicKey(object);
|
|
if (key == NULL) {
|
|
return NULL;
|
|
}
|
|
|
|
switch (key->keyType) {
|
|
case NSSLOWKEYRSAKey:
|
|
return sftk_FindRSAPublicKeyAttribute(key,type);
|
|
case NSSLOWKEYDSAKey:
|
|
return sftk_FindDSAPublicKeyAttribute(key,type);
|
|
case NSSLOWKEYDHKey:
|
|
return sftk_FindDHPublicKeyAttribute(key,type);
|
|
#ifdef NSS_ENABLE_ECC
|
|
case NSSLOWKEYECKey:
|
|
return sftk_FindECPublicKeyAttribute(key,type);
|
|
#endif /* NSS_ENABLE_ECC */
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
static SFTKAttribute *
|
|
sftk_FindSecretKeyAttribute(SFTKTokenObject *object, CK_ATTRIBUTE_TYPE type)
|
|
{
|
|
NSSLOWKEYPrivateKey *key;
|
|
char *label;
|
|
unsigned char *keyString;
|
|
SFTKAttribute *att;
|
|
int keyTypeLen;
|
|
CK_ULONG keyLen;
|
|
CK_KEY_TYPE keyType;
|
|
PRUint32 keyTypeStorage;
|
|
|
|
switch (type) {
|
|
case CKA_PRIVATE:
|
|
case CKA_SENSITIVE:
|
|
case CKA_ALWAYS_SENSITIVE:
|
|
case CKA_EXTRACTABLE:
|
|
case CKA_DERIVE:
|
|
case CKA_ENCRYPT:
|
|
case CKA_DECRYPT:
|
|
case CKA_SIGN:
|
|
case CKA_VERIFY:
|
|
case CKA_WRAP:
|
|
case CKA_UNWRAP:
|
|
case CKA_MODIFIABLE:
|
|
return SFTK_CLONE_ATTR(type,sftk_StaticTrueAttr);
|
|
case CKA_NEVER_EXTRACTABLE:
|
|
return SFTK_CLONE_ATTR(type,sftk_StaticFalseAttr);
|
|
case CKA_LABEL:
|
|
label = sftk_FindKeyNicknameByPublicKey(object->obj.slot,
|
|
&object->dbKey);
|
|
if (label == NULL) {
|
|
return SFTK_CLONE_ATTR(type,sftk_StaticNullAttr);
|
|
}
|
|
att = sftk_NewTokenAttribute(type,label,PORT_Strlen(label), PR_TRUE);
|
|
PORT_Free(label);
|
|
return att;
|
|
case CKA_KEY_TYPE:
|
|
case CKA_VALUE_LEN:
|
|
case CKA_VALUE:
|
|
break;
|
|
default:
|
|
return NULL;
|
|
}
|
|
|
|
key = sftk_GetPrivateKey(object);
|
|
if (key == NULL) {
|
|
return NULL;
|
|
}
|
|
switch (type) {
|
|
case CKA_KEY_TYPE:
|
|
/* handle legacy databases. In legacy databases key_type was stored
|
|
* in host order, with any leading zeros stripped off. Only key types
|
|
* under 0x1f (AES) were stored. We assume that any values which are
|
|
* either 1 byte long (big endian), or have byte[0] between 0 and
|
|
* 0x7f and bytes[1]-bytes[3] equal to '0' (little endian). All other
|
|
* values are assumed to be from the new database, which is always 4
|
|
* bytes in network order */
|
|
keyType=0;
|
|
keyString = key->u.rsa.coefficient.data;
|
|
keyTypeLen = key->u.rsa.coefficient.len;
|
|
|
|
|
|
/*
|
|
* Because of various endian and word lengths The database may have
|
|
* stored the keyType value in one of the following formats:
|
|
* (kt) <= 0x1f
|
|
* length data
|
|
* Big Endian, pre-3.9, all lengths: 1 (kt)
|
|
* Little Endian, pre-3.9, 32 bits: 4 (kt) 0 0 0
|
|
* Little Endian, pre-3.9, 64 bits: 8 (kt) 0 0 0 0 0 0 0
|
|
* All platforms, 3.9, 32 bits: 4 0 0 0 (kt)
|
|
* Big Endian, 3.9, 64 bits: 8 0 0 0 (kt) 0 0 0 0
|
|
* Little Endian, 3.9, 64 bits: 8 0 0 0 0 0 0 0 (kt)
|
|
* All platforms, >= 3.9.1, all lengths: 4 (a) k1 k2 k3
|
|
* where (a) is 0 or >= 0x80. currently (a) can only be 0.
|
|
*/
|
|
/*
|
|
* this key was written on a 64 bit platform with a using NSS 3.9
|
|
* or earlier. Reduce the 64 bit possibilities above. We were are
|
|
* through, we will only have:
|
|
*
|
|
* Big Endian, pre-3.9, all lengths: 1 (kt)
|
|
* Little Endian, pre-3.9, all lengths: 4 (kt) 0 0 0
|
|
* All platforms, 3.9, all lengths: 4 0 0 0 (kt)
|
|
* All platforms, => 3.9.1, all lengths: 4 (a) k1 k2 k3
|
|
*/
|
|
if (keyTypeLen == 8) {
|
|
keyTypeStorage = *(PRUint32 *) keyString;
|
|
if (keyTypeStorage == 0) {
|
|
keyString += sizeof(PRUint32);
|
|
}
|
|
keyTypeLen = 4;
|
|
}
|
|
/*
|
|
* Now Handle:
|
|
*
|
|
* All platforms, 3.9, all lengths: 4 0 0 0 (kt)
|
|
* All platforms, => 3.9.1, all lengths: 4 (a) k1 k2 k3
|
|
*
|
|
* NOTE: if kt == 0 or ak1k2k3 == 0, the test fails and
|
|
* we handle it as:
|
|
*
|
|
* Little Endian, pre-3.9, all lengths: 4 (kt) 0 0 0
|
|
*/
|
|
if (keyTypeLen == sizeof(keyTypeStorage) &&
|
|
(((keyString[0] & 0x80) == 0x80) ||
|
|
!((keyString[1] == 0) && (keyString[2] == 0)
|
|
&& (keyString[3] == 0))) ) {
|
|
PORT_Memcpy(&keyTypeStorage, keyString, sizeof(keyTypeStorage));
|
|
keyType = (CK_KEY_TYPE) PR_ntohl(keyTypeStorage);
|
|
} else {
|
|
/*
|
|
* Now Handle:
|
|
*
|
|
* Big Endian, pre-3.9, all lengths: 1 (kt)
|
|
* Little Endian, pre-3.9, all lengths: 4 (kt) 0 0 0
|
|
* -- KeyType == 0 all other cases ---: 4 0 0 0 0
|
|
*/
|
|
keyType = (CK_KEY_TYPE) keyString[0] ;
|
|
}
|
|
return sftk_NewTokenAttribute(type,&keyType,sizeof(keyType),PR_TRUE);
|
|
case CKA_VALUE:
|
|
return sftk_NewTokenAttribute(type,key->u.rsa.privateExponent.data,
|
|
key->u.rsa.privateExponent.len, PR_FALSE);
|
|
case CKA_VALUE_LEN:
|
|
keyLen=key->u.rsa.privateExponent.len;
|
|
return sftk_NewTokenAttribute(type, &keyLen, sizeof(CK_ULONG), PR_TRUE);
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
static SFTKAttribute *
|
|
sftk_FindRSAPrivateKeyAttribute(NSSLOWKEYPrivateKey *key,
|
|
CK_ATTRIBUTE_TYPE type)
|
|
{
|
|
unsigned char hash[SHA1_LENGTH];
|
|
CK_KEY_TYPE keyType = CKK_RSA;
|
|
|
|
switch (type) {
|
|
case CKA_KEY_TYPE:
|
|
return sftk_NewTokenAttribute(type,&keyType,sizeof(keyType), PR_TRUE);
|
|
case CKA_ID:
|
|
SHA1_HashBuf(hash,key->u.rsa.modulus.data,key->u.rsa.modulus.len);
|
|
return sftk_NewTokenAttribute(type,hash,SHA1_LENGTH, PR_TRUE);
|
|
case CKA_DERIVE:
|
|
return SFTK_CLONE_ATTR(type,sftk_StaticFalseAttr);
|
|
case CKA_DECRYPT:
|
|
case CKA_SIGN:
|
|
case CKA_SIGN_RECOVER:
|
|
case CKA_UNWRAP:
|
|
return SFTK_CLONE_ATTR(type,sftk_StaticTrueAttr);
|
|
case CKA_MODULUS:
|
|
return sftk_NewTokenAttributeSigned(type,key->u.rsa.modulus.data,
|
|
key->u.rsa.modulus.len, PR_FALSE);
|
|
case CKA_PUBLIC_EXPONENT:
|
|
return sftk_NewTokenAttributeSigned(type,key->u.rsa.publicExponent.data,
|
|
key->u.rsa.publicExponent.len, PR_FALSE);
|
|
case CKA_PRIVATE_EXPONENT:
|
|
return sftk_NewTokenAttributeSigned(type,
|
|
key->u.rsa.privateExponent.data,
|
|
key->u.rsa.privateExponent.len, PR_FALSE);
|
|
case CKA_PRIME_1:
|
|
return sftk_NewTokenAttributeSigned(type, key->u.rsa.prime1.data,
|
|
key->u.rsa.prime1.len, PR_FALSE);
|
|
case CKA_PRIME_2:
|
|
return sftk_NewTokenAttributeSigned(type, key->u.rsa.prime2.data,
|
|
key->u.rsa.prime2.len, PR_FALSE);
|
|
case CKA_EXPONENT_1:
|
|
return sftk_NewTokenAttributeSigned(type, key->u.rsa.exponent1.data,
|
|
key->u.rsa.exponent1.len, PR_FALSE);
|
|
case CKA_EXPONENT_2:
|
|
return sftk_NewTokenAttributeSigned(type, key->u.rsa.exponent2.data,
|
|
key->u.rsa.exponent2.len, PR_FALSE);
|
|
case CKA_COEFFICIENT:
|
|
return sftk_NewTokenAttributeSigned(type, key->u.rsa.coefficient.data,
|
|
key->u.rsa.coefficient.len, PR_FALSE);
|
|
default:
|
|
break;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
static SFTKAttribute *
|
|
sftk_FindDSAPrivateKeyAttribute(NSSLOWKEYPrivateKey *key,
|
|
CK_ATTRIBUTE_TYPE type)
|
|
{
|
|
unsigned char hash[SHA1_LENGTH];
|
|
CK_KEY_TYPE keyType = CKK_DSA;
|
|
|
|
switch (type) {
|
|
case CKA_KEY_TYPE:
|
|
return sftk_NewTokenAttribute(type,&keyType,sizeof(keyType), PR_TRUE);
|
|
case CKA_ID:
|
|
SHA1_HashBuf(hash,key->u.dsa.publicValue.data,
|
|
key->u.dsa.publicValue.len);
|
|
return sftk_NewTokenAttribute(type,hash,SHA1_LENGTH, PR_TRUE);
|
|
case CKA_DERIVE:
|
|
case CKA_DECRYPT:
|
|
case CKA_SIGN_RECOVER:
|
|
case CKA_UNWRAP:
|
|
return SFTK_CLONE_ATTR(type,sftk_StaticFalseAttr);
|
|
case CKA_SIGN:
|
|
return SFTK_CLONE_ATTR(type,sftk_StaticTrueAttr);
|
|
case CKA_VALUE:
|
|
return sftk_NewTokenAttributeSigned(type, key->u.dsa.privateValue.data,
|
|
key->u.dsa.privateValue.len, PR_FALSE);
|
|
case CKA_PRIME:
|
|
return sftk_NewTokenAttributeSigned(type,key->u.dsa.params.prime.data,
|
|
key->u.dsa.params.prime.len, PR_FALSE);
|
|
case CKA_SUBPRIME:
|
|
return sftk_NewTokenAttributeSigned(type,
|
|
key->u.dsa.params.subPrime.data,
|
|
key->u.dsa.params.subPrime.len, PR_FALSE);
|
|
case CKA_BASE:
|
|
return sftk_NewTokenAttributeSigned(type,key->u.dsa.params.base.data,
|
|
key->u.dsa.params.base.len, PR_FALSE);
|
|
default:
|
|
break;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
static SFTKAttribute *
|
|
sftk_FindDHPrivateKeyAttribute(NSSLOWKEYPrivateKey *key, CK_ATTRIBUTE_TYPE type)
|
|
{
|
|
unsigned char hash[SHA1_LENGTH];
|
|
CK_KEY_TYPE keyType = CKK_DH;
|
|
|
|
switch (type) {
|
|
case CKA_KEY_TYPE:
|
|
return sftk_NewTokenAttribute(type,&keyType,sizeof(keyType), PR_TRUE);
|
|
case CKA_ID:
|
|
SHA1_HashBuf(hash,key->u.dh.publicValue.data,key->u.dh.publicValue.len);
|
|
return sftk_NewTokenAttribute(type,hash,SHA1_LENGTH, PR_TRUE);
|
|
case CKA_DERIVE:
|
|
return SFTK_CLONE_ATTR(type,sftk_StaticTrueAttr);
|
|
case CKA_DECRYPT:
|
|
case CKA_SIGN:
|
|
case CKA_SIGN_RECOVER:
|
|
case CKA_UNWRAP:
|
|
return SFTK_CLONE_ATTR(type,sftk_StaticFalseAttr);
|
|
case CKA_VALUE:
|
|
return sftk_NewTokenAttributeSigned(type,key->u.dh.privateValue.data,
|
|
key->u.dh.privateValue.len, PR_FALSE);
|
|
case CKA_PRIME:
|
|
return sftk_NewTokenAttributeSigned(type,key->u.dh.prime.data,
|
|
key->u.dh.prime.len, PR_FALSE);
|
|
case CKA_BASE:
|
|
return sftk_NewTokenAttributeSigned(type,key->u.dh.base.data,
|
|
key->u.dh.base.len, PR_FALSE);
|
|
default:
|
|
break;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
#ifdef NSS_ENABLE_ECC
|
|
static SFTKAttribute *
|
|
sftk_FindECPrivateKeyAttribute(NSSLOWKEYPrivateKey *key, CK_ATTRIBUTE_TYPE type)
|
|
{
|
|
unsigned char hash[SHA1_LENGTH];
|
|
CK_KEY_TYPE keyType = CKK_EC;
|
|
|
|
switch (type) {
|
|
case CKA_KEY_TYPE:
|
|
return sftk_NewTokenAttribute(type,&keyType,sizeof(keyType), PR_TRUE);
|
|
case CKA_ID:
|
|
SHA1_HashBuf(hash,key->u.ec.publicValue.data,key->u.ec.publicValue.len);
|
|
return sftk_NewTokenAttribute(type,hash,SHA1_LENGTH, PR_TRUE);
|
|
case CKA_DERIVE:
|
|
case CKA_SIGN:
|
|
return SFTK_CLONE_ATTR(type,sftk_StaticTrueAttr);
|
|
case CKA_DECRYPT:
|
|
case CKA_SIGN_RECOVER:
|
|
case CKA_UNWRAP:
|
|
return SFTK_CLONE_ATTR(type,sftk_StaticFalseAttr);
|
|
case CKA_VALUE:
|
|
return sftk_NewTokenAttributeSigned(type, key->u.ec.privateValue.data,
|
|
key->u.ec.privateValue.len, PR_FALSE);
|
|
case CKA_EC_PARAMS:
|
|
/* XXX Why is the last arg PR_FALSE? */
|
|
return sftk_NewTokenAttributeSigned(type,
|
|
key->u.ec.ecParams.DEREncoding.data,
|
|
key->u.ec.ecParams.DEREncoding.len,
|
|
PR_FALSE);
|
|
default:
|
|
break;
|
|
}
|
|
return NULL;
|
|
}
|
|
#endif /* NSS_ENABLE_ECC */
|
|
|
|
static SFTKAttribute *
|
|
sftk_FindPrivateKeyAttribute(SFTKTokenObject *object, CK_ATTRIBUTE_TYPE type)
|
|
{
|
|
NSSLOWKEYPrivateKey *key;
|
|
char *label;
|
|
SFTKAttribute *att;
|
|
|
|
switch (type) {
|
|
case CKA_PRIVATE:
|
|
case CKA_SENSITIVE:
|
|
case CKA_ALWAYS_SENSITIVE:
|
|
case CKA_EXTRACTABLE:
|
|
case CKA_MODIFIABLE:
|
|
return SFTK_CLONE_ATTR(type,sftk_StaticTrueAttr);
|
|
case CKA_NEVER_EXTRACTABLE:
|
|
return SFTK_CLONE_ATTR(type,sftk_StaticFalseAttr);
|
|
case CKA_SUBJECT:
|
|
return SFTK_CLONE_ATTR(type,sftk_StaticNullAttr);
|
|
case CKA_LABEL:
|
|
label = sftk_FindKeyNicknameByPublicKey(object->obj.slot,
|
|
&object->dbKey);
|
|
if (label == NULL) {
|
|
return SFTK_CLONE_ATTR(type,sftk_StaticNullAttr);
|
|
}
|
|
att = sftk_NewTokenAttribute(type,label,PORT_Strlen(label), PR_TRUE);
|
|
PORT_Free(label);
|
|
return att;
|
|
default:
|
|
break;
|
|
}
|
|
key = sftk_GetPrivateKey(object);
|
|
if (key == NULL) {
|
|
return NULL;
|
|
}
|
|
switch (key->keyType) {
|
|
case NSSLOWKEYRSAKey:
|
|
return sftk_FindRSAPrivateKeyAttribute(key,type);
|
|
case NSSLOWKEYDSAKey:
|
|
return sftk_FindDSAPrivateKeyAttribute(key,type);
|
|
case NSSLOWKEYDHKey:
|
|
return sftk_FindDHPrivateKeyAttribute(key,type);
|
|
#ifdef NSS_ENABLE_ECC
|
|
case NSSLOWKEYECKey:
|
|
return sftk_FindECPrivateKeyAttribute(key,type);
|
|
#endif /* NSS_ENABLE_ECC */
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
static SFTKAttribute *
|
|
sftk_FindSMIMEAttribute(SFTKTokenObject *object, CK_ATTRIBUTE_TYPE type)
|
|
{
|
|
certDBEntrySMime *entry;
|
|
switch (type) {
|
|
case CKA_PRIVATE:
|
|
case CKA_MODIFIABLE:
|
|
return SFTK_CLONE_ATTR(type,sftk_StaticFalseAttr);
|
|
case CKA_NETSCAPE_EMAIL:
|
|
return sftk_NewTokenAttribute(type,object->dbKey.data,
|
|
object->dbKey.len-1, PR_FALSE);
|
|
case CKA_NETSCAPE_SMIME_TIMESTAMP:
|
|
case CKA_SUBJECT:
|
|
case CKA_VALUE:
|
|
break;
|
|
default:
|
|
return NULL;
|
|
}
|
|
entry = sftk_getSMime(object);
|
|
if (entry == NULL) {
|
|
return NULL;
|
|
}
|
|
switch (type) {
|
|
case CKA_NETSCAPE_SMIME_TIMESTAMP:
|
|
return sftk_NewTokenAttribute(type,entry->optionsDate.data,
|
|
entry->optionsDate.len, PR_FALSE);
|
|
case CKA_SUBJECT:
|
|
return sftk_NewTokenAttribute(type,entry->subjectName.data,
|
|
entry->subjectName.len, PR_FALSE);
|
|
case CKA_VALUE:
|
|
return sftk_NewTokenAttribute(type,entry->smimeOptions.data,
|
|
entry->smimeOptions.len, PR_FALSE);
|
|
default:
|
|
break;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
static SFTKAttribute *
|
|
sftk_FindTrustAttribute(SFTKTokenObject *object, CK_ATTRIBUTE_TYPE type)
|
|
{
|
|
NSSLOWCERTTrust *trust;
|
|
unsigned char hash[SHA1_LENGTH];
|
|
unsigned int trustFlags;
|
|
|
|
switch (type) {
|
|
case CKA_PRIVATE:
|
|
return SFTK_CLONE_ATTR(type,sftk_StaticFalseAttr);
|
|
case CKA_MODIFIABLE:
|
|
return SFTK_CLONE_ATTR(type,sftk_StaticTrueAttr);
|
|
case CKA_CERT_SHA1_HASH:
|
|
case CKA_CERT_MD5_HASH:
|
|
case CKA_TRUST_CLIENT_AUTH:
|
|
case CKA_TRUST_SERVER_AUTH:
|
|
case CKA_TRUST_EMAIL_PROTECTION:
|
|
case CKA_TRUST_CODE_SIGNING:
|
|
case CKA_TRUST_STEP_UP_APPROVED:
|
|
break;
|
|
default:
|
|
return NULL;
|
|
}
|
|
trust = sftk_getTrust(object);
|
|
if (trust == NULL) {
|
|
return NULL;
|
|
}
|
|
switch (type) {
|
|
case CKA_CERT_SHA1_HASH:
|
|
SHA1_HashBuf(hash,trust->derCert->data,trust->derCert->len);
|
|
return sftk_NewTokenAttribute(type, hash, SHA1_LENGTH, PR_TRUE);
|
|
case CKA_CERT_MD5_HASH:
|
|
MD5_HashBuf(hash,trust->derCert->data,trust->derCert->len);
|
|
return sftk_NewTokenAttribute(type, hash, MD5_LENGTH, PR_TRUE);
|
|
case CKA_TRUST_CLIENT_AUTH:
|
|
trustFlags = trust->trust->sslFlags & CERTDB_TRUSTED_CLIENT_CA ?
|
|
trust->trust->sslFlags | CERTDB_TRUSTED_CA : 0 ;
|
|
goto trust;
|
|
case CKA_TRUST_SERVER_AUTH:
|
|
trustFlags = trust->trust->sslFlags;
|
|
goto trust;
|
|
case CKA_TRUST_EMAIL_PROTECTION:
|
|
trustFlags = trust->trust->emailFlags;
|
|
goto trust;
|
|
case CKA_TRUST_CODE_SIGNING:
|
|
trustFlags = trust->trust->objectSigningFlags;
|
|
trust:
|
|
if (trustFlags & CERTDB_TRUSTED_CA ) {
|
|
return SFTK_CLONE_ATTR(type,sftk_StaticTrustedDelegatorAttr);
|
|
}
|
|
if (trustFlags & CERTDB_TRUSTED) {
|
|
return SFTK_CLONE_ATTR(type,sftk_StaticTrustedAttr);
|
|
}
|
|
if (trustFlags & CERTDB_NOT_TRUSTED) {
|
|
return SFTK_CLONE_ATTR(type,sftk_StaticUnTrustedAttr);
|
|
}
|
|
if (trustFlags & CERTDB_TRUSTED_UNKNOWN) {
|
|
return SFTK_CLONE_ATTR(type,sftk_StaticTrustUnknownAttr);
|
|
}
|
|
if (trustFlags & CERTDB_VALID_CA) {
|
|
return SFTK_CLONE_ATTR(type,sftk_StaticValidDelegatorAttr);
|
|
}
|
|
if (trustFlags & CERTDB_VALID_PEER) {
|
|
return SFTK_CLONE_ATTR(type,sftk_StaticValidPeerAttr);
|
|
}
|
|
return SFTK_CLONE_ATTR(type,sftk_StaticMustVerifyAttr);
|
|
case CKA_TRUST_STEP_UP_APPROVED:
|
|
if (trust->trust->sslFlags & CERTDB_GOVT_APPROVED_CA) {
|
|
return SFTK_CLONE_ATTR(type,sftk_StaticTrueAttr);
|
|
} else {
|
|
return SFTK_CLONE_ATTR(type,sftk_StaticFalseAttr);
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
|
|
#ifdef notdef
|
|
switch (type) {
|
|
case CKA_ISSUER:
|
|
cert = sftk_getCertObject(object);
|
|
if (cert == NULL) break;
|
|
attr = sftk_NewTokenAttribute(type,cert->derIssuer.data,
|
|
cert->derIssuer.len, PR_FALSE);
|
|
|
|
case CKA_SERIAL_NUMBER:
|
|
cert = sftk_getCertObject(object);
|
|
if (cert == NULL) break;
|
|
item = SEC_ASN1EncodeItem(NULL,NULL,cert,sftk_SerialTemplate);
|
|
if (item == NULL) break;
|
|
attr = sftk_NewTokenAttribute(type, item->data, item->len, PR_TRUE);
|
|
SECITEM_FreeItem(item,PR_TRUE);
|
|
}
|
|
if (cert) {
|
|
NSSLOWCERTDestroyCertificate(cert);
|
|
return attr;
|
|
}
|
|
#endif
|
|
return NULL;
|
|
}
|
|
|
|
static SFTKAttribute *
|
|
sftk_FindCrlAttribute(SFTKTokenObject *object, CK_ATTRIBUTE_TYPE type)
|
|
{
|
|
certDBEntryRevocation *crl;
|
|
|
|
switch (type) {
|
|
case CKA_PRIVATE:
|
|
case CKA_MODIFIABLE:
|
|
return SFTK_CLONE_ATTR(type,sftk_StaticFalseAttr);
|
|
case CKA_NETSCAPE_KRL:
|
|
return ((object->obj.handle == SFTK_TOKEN_KRL_HANDLE)
|
|
? SFTK_CLONE_ATTR(type,sftk_StaticTrueAttr)
|
|
: SFTK_CLONE_ATTR(type,sftk_StaticFalseAttr));
|
|
case CKA_SUBJECT:
|
|
return sftk_NewTokenAttribute(type,object->dbKey.data,
|
|
object->dbKey.len, PR_FALSE);
|
|
case CKA_NETSCAPE_URL:
|
|
case CKA_VALUE:
|
|
break;
|
|
default:
|
|
PORT_SetError(SEC_ERROR_INVALID_ARGS);
|
|
return NULL;
|
|
}
|
|
crl = sftk_getCrl(object);
|
|
if (!crl) {
|
|
return NULL;
|
|
}
|
|
switch (type) {
|
|
case CKA_NETSCAPE_URL:
|
|
if (crl->url == NULL) {
|
|
return SFTK_CLONE_ATTR(type,sftk_StaticNullAttr);
|
|
}
|
|
return sftk_NewTokenAttribute(type, crl->url,
|
|
PORT_Strlen(crl->url)+1, PR_TRUE);
|
|
case CKA_VALUE:
|
|
return sftk_NewTokenAttribute(type, crl->derCrl.data,
|
|
crl->derCrl.len, PR_FALSE);
|
|
default:
|
|
break;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
static SFTKAttribute *
|
|
sftk_FindCertAttribute(SFTKTokenObject *object, CK_ATTRIBUTE_TYPE type)
|
|
{
|
|
NSSLOWCERTCertificate *cert;
|
|
NSSLOWCERTCertDBHandle *certHandle;
|
|
NSSLOWKEYPublicKey *pubKey;
|
|
unsigned char hash[SHA1_LENGTH];
|
|
SECItem *item;
|
|
|
|
switch (type) {
|
|
case CKA_PRIVATE:
|
|
return SFTK_CLONE_ATTR(type,sftk_StaticFalseAttr);
|
|
case CKA_MODIFIABLE:
|
|
return SFTK_CLONE_ATTR(type,sftk_StaticTrueAttr);
|
|
case CKA_CERTIFICATE_TYPE:
|
|
/* hardcoding X.509 into here */
|
|
return SFTK_CLONE_ATTR(type,sftk_StaticX509Attr);
|
|
case CKA_VALUE:
|
|
case CKA_ID:
|
|
case CKA_LABEL:
|
|
case CKA_SUBJECT:
|
|
case CKA_ISSUER:
|
|
case CKA_SERIAL_NUMBER:
|
|
case CKA_NETSCAPE_EMAIL:
|
|
break;
|
|
default:
|
|
return NULL;
|
|
}
|
|
|
|
certHandle = sftk_getCertDB(object->obj.slot);
|
|
if (certHandle == NULL) {
|
|
return NULL;
|
|
}
|
|
|
|
cert = sftk_getCert(object, certHandle);
|
|
sftk_freeCertDB(certHandle);
|
|
if (cert == NULL) {
|
|
return NULL;
|
|
}
|
|
switch (type) {
|
|
case CKA_VALUE:
|
|
return sftk_NewTokenAttribute(type,cert->derCert.data,
|
|
cert->derCert.len,PR_FALSE);
|
|
case CKA_ID:
|
|
if (((cert->trust->sslFlags & CERTDB_USER) == 0) &&
|
|
((cert->trust->emailFlags & CERTDB_USER) == 0) &&
|
|
((cert->trust->objectSigningFlags & CERTDB_USER) == 0)) {
|
|
return SFTK_CLONE_ATTR(type,sftk_StaticNullAttr);
|
|
}
|
|
pubKey = nsslowcert_ExtractPublicKey(cert);
|
|
if (pubKey == NULL) break;
|
|
item = sftk_GetPubItem(pubKey);
|
|
if (item == NULL) {
|
|
nsslowkey_DestroyPublicKey(pubKey);
|
|
break;
|
|
}
|
|
SHA1_HashBuf(hash,item->data,item->len);
|
|
/* item is imbedded in pubKey, just free the key */
|
|
nsslowkey_DestroyPublicKey(pubKey);
|
|
return sftk_NewTokenAttribute(type, hash, SHA1_LENGTH, PR_TRUE);
|
|
case CKA_LABEL:
|
|
return cert->nickname
|
|
? sftk_NewTokenAttribute(type, cert->nickname,
|
|
PORT_Strlen(cert->nickname), PR_FALSE)
|
|
: SFTK_CLONE_ATTR(type,sftk_StaticNullAttr);
|
|
case CKA_SUBJECT:
|
|
return sftk_NewTokenAttribute(type,cert->derSubject.data,
|
|
cert->derSubject.len, PR_FALSE);
|
|
case CKA_ISSUER:
|
|
return sftk_NewTokenAttribute(type,cert->derIssuer.data,
|
|
cert->derIssuer.len, PR_FALSE);
|
|
case CKA_SERIAL_NUMBER:
|
|
return sftk_NewTokenAttribute(type,cert->derSN.data,
|
|
cert->derSN.len, PR_FALSE);
|
|
case CKA_NETSCAPE_EMAIL:
|
|
return (cert->emailAddr && cert->emailAddr[0])
|
|
? sftk_NewTokenAttribute(type, cert->emailAddr,
|
|
PORT_Strlen(cert->emailAddr), PR_FALSE)
|
|
: SFTK_CLONE_ATTR(type,sftk_StaticNullAttr);
|
|
default:
|
|
break;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
static SFTKAttribute *
|
|
sftk_FindTokenAttribute(SFTKTokenObject *object,CK_ATTRIBUTE_TYPE type)
|
|
{
|
|
/* handle the common ones */
|
|
switch (type) {
|
|
case CKA_CLASS:
|
|
return sftk_NewTokenAttribute(type,&object->obj.objclass,
|
|
sizeof(object->obj.objclass),PR_FALSE);
|
|
case CKA_TOKEN:
|
|
return SFTK_CLONE_ATTR(type,sftk_StaticTrueAttr);
|
|
case CKA_LABEL:
|
|
if ( (object->obj.objclass == CKO_CERTIFICATE)
|
|
|| (object->obj.objclass == CKO_PRIVATE_KEY)
|
|
|| (object->obj.objclass == CKO_PUBLIC_KEY)
|
|
|| (object->obj.objclass == CKO_SECRET_KEY)) {
|
|
break;
|
|
}
|
|
return SFTK_CLONE_ATTR(type,sftk_StaticNullAttr);
|
|
default:
|
|
break;
|
|
}
|
|
switch (object->obj.objclass) {
|
|
case CKO_CERTIFICATE:
|
|
return sftk_FindCertAttribute(object,type);
|
|
case CKO_NETSCAPE_CRL:
|
|
return sftk_FindCrlAttribute(object,type);
|
|
case CKO_NETSCAPE_TRUST:
|
|
return sftk_FindTrustAttribute(object,type);
|
|
case CKO_NETSCAPE_SMIME:
|
|
return sftk_FindSMIMEAttribute(object,type);
|
|
case CKO_PUBLIC_KEY:
|
|
return sftk_FindPublicKeyAttribute(object,type);
|
|
case CKO_PRIVATE_KEY:
|
|
return sftk_FindPrivateKeyAttribute(object,type);
|
|
case CKO_SECRET_KEY:
|
|
return sftk_FindSecretKeyAttribute(object,type);
|
|
default:
|
|
break;
|
|
}
|
|
PORT_Assert(0);
|
|
return NULL;
|
|
}
|
|
|
|
/*
|
|
* look up and attribute structure from a type and Object structure.
|
|
* The returned attribute is referenced and needs to be freed when
|
|
* it is no longer needed.
|
|
*/
|
|
SFTKAttribute *
|
|
sftk_FindAttribute(SFTKObject *object,CK_ATTRIBUTE_TYPE type)
|
|
{
|
|
SFTKAttribute *attribute;
|
|
SFTKSessionObject *sessObject = sftk_narrowToSessionObject(object);
|
|
|
|
if (sessObject == NULL) {
|
|
return sftk_FindTokenAttribute(sftk_narrowToTokenObject(object),type);
|
|
}
|
|
|
|
PZ_Lock(sessObject->attributeLock);
|
|
sftkqueue_find(attribute,type,sessObject->head, sessObject->hashSize);
|
|
PZ_Unlock(sessObject->attributeLock);
|
|
|
|
return(attribute);
|
|
}
|
|
|
|
/*
|
|
* Take a buffer and it's length and return it's true size in bits;
|
|
*/
|
|
unsigned int
|
|
sftk_GetLengthInBits(unsigned char *buf, unsigned int bufLen)
|
|
{
|
|
unsigned int size = bufLen * 8;
|
|
unsigned int i;
|
|
|
|
/* Get the real length in bytes */
|
|
for (i=0; i < bufLen; i++) {
|
|
unsigned char c = *buf++;
|
|
if (c != 0) {
|
|
unsigned char m;
|
|
for (m=0x80; m > 0 ; m = m >> 1) {
|
|
if ((c & m) != 0) {
|
|
break;
|
|
}
|
|
size--;
|
|
}
|
|
break;
|
|
}
|
|
size-=8;
|
|
}
|
|
return size;
|
|
}
|
|
|
|
/*
|
|
* Constrain a big num attribute. to size and padding
|
|
* minLength means length of the object must be greater than equal to minLength
|
|
* maxLength means length of the object must be less than equal to maxLength
|
|
* minMultiple means that object length mod minMultiple must equal 0.
|
|
* all input sizes are in bits.
|
|
* if any constraint is '0' that constraint is not checked.
|
|
*/
|
|
CK_RV
|
|
sftk_ConstrainAttribute(SFTKObject *object, CK_ATTRIBUTE_TYPE type,
|
|
int minLength, int maxLength, int minMultiple)
|
|
{
|
|
SFTKAttribute *attribute;
|
|
int size;
|
|
unsigned char *ptr;
|
|
|
|
attribute = sftk_FindAttribute(object, type);
|
|
if (!attribute) {
|
|
return CKR_TEMPLATE_INCOMPLETE;
|
|
}
|
|
ptr = (unsigned char *) attribute->attrib.pValue;
|
|
if (ptr == NULL) {
|
|
sftk_FreeAttribute(attribute);
|
|
return CKR_ATTRIBUTE_VALUE_INVALID;
|
|
}
|
|
size = sftk_GetLengthInBits(ptr, attribute->attrib.ulValueLen);
|
|
sftk_FreeAttribute(attribute);
|
|
|
|
if ((minLength != 0) && (size < minLength)) {
|
|
return CKR_ATTRIBUTE_VALUE_INVALID;
|
|
}
|
|
if ((maxLength != 0) && (size > maxLength)) {
|
|
return CKR_ATTRIBUTE_VALUE_INVALID;
|
|
}
|
|
if ((minMultiple != 0) && ((size % minMultiple) != 0)) {
|
|
return CKR_ATTRIBUTE_VALUE_INVALID;
|
|
}
|
|
return CKR_OK;
|
|
}
|
|
|
|
PRBool
|
|
sftk_hasAttributeToken(SFTKTokenObject *object)
|
|
{
|
|
return PR_FALSE;
|
|
}
|
|
|
|
/*
|
|
* return true if object has attribute
|
|
*/
|
|
PRBool
|
|
sftk_hasAttribute(SFTKObject *object,CK_ATTRIBUTE_TYPE type)
|
|
{
|
|
SFTKAttribute *attribute;
|
|
SFTKSessionObject *sessObject = sftk_narrowToSessionObject(object);
|
|
|
|
if (sessObject == NULL) {
|
|
return sftk_hasAttributeToken(sftk_narrowToTokenObject(object));
|
|
}
|
|
|
|
PZ_Lock(sessObject->attributeLock);
|
|
sftkqueue_find(attribute,type,sessObject->head, sessObject->hashSize);
|
|
PZ_Unlock(sessObject->attributeLock);
|
|
|
|
return (PRBool)(attribute != NULL);
|
|
}
|
|
|
|
/*
|
|
* add an attribute to an object
|
|
*/
|
|
static void
|
|
sftk_AddAttribute(SFTKObject *object,SFTKAttribute *attribute)
|
|
{
|
|
SFTKSessionObject *sessObject = sftk_narrowToSessionObject(object);
|
|
|
|
if (sessObject == NULL) return;
|
|
PZ_Lock(sessObject->attributeLock);
|
|
sftkqueue_add(attribute,attribute->handle,
|
|
sessObject->head, sessObject->hashSize);
|
|
PZ_Unlock(sessObject->attributeLock);
|
|
}
|
|
|
|
/*
|
|
* copy an unsigned attribute into a SECItem. Secitem is allocated in
|
|
* the specified arena.
|
|
*/
|
|
CK_RV
|
|
sftk_Attribute2SSecItem(PLArenaPool *arena,SECItem *item,SFTKObject *object,
|
|
CK_ATTRIBUTE_TYPE type)
|
|
{
|
|
SFTKAttribute *attribute;
|
|
|
|
item->data = NULL;
|
|
|
|
attribute = sftk_FindAttribute(object, type);
|
|
if (attribute == NULL) return CKR_TEMPLATE_INCOMPLETE;
|
|
|
|
(void)SECITEM_AllocItem(arena, item, attribute->attrib.ulValueLen);
|
|
if (item->data == NULL) {
|
|
sftk_FreeAttribute(attribute);
|
|
return CKR_HOST_MEMORY;
|
|
}
|
|
PORT_Memcpy(item->data, attribute->attrib.pValue, item->len);
|
|
sftk_FreeAttribute(attribute);
|
|
return CKR_OK;
|
|
}
|
|
|
|
|
|
/*
|
|
* delete an attribute from an object
|
|
*/
|
|
static void
|
|
sftk_DeleteAttribute(SFTKObject *object, SFTKAttribute *attribute)
|
|
{
|
|
SFTKSessionObject *sessObject = sftk_narrowToSessionObject(object);
|
|
|
|
if (sessObject == NULL) {
|
|
return ;
|
|
}
|
|
PZ_Lock(sessObject->attributeLock);
|
|
if (sftkqueue_is_queued(attribute,attribute->handle,
|
|
sessObject->head, sessObject->hashSize)) {
|
|
sftkqueue_delete(attribute,attribute->handle,
|
|
sessObject->head, sessObject->hashSize);
|
|
}
|
|
PZ_Unlock(sessObject->attributeLock);
|
|
sftk_FreeAttribute(attribute);
|
|
}
|
|
|
|
/*
|
|
* this is only valid for CK_BBOOL type attributes. Return the state
|
|
* of that attribute.
|
|
*/
|
|
PRBool
|
|
sftk_isTrue(SFTKObject *object,CK_ATTRIBUTE_TYPE type)
|
|
{
|
|
SFTKAttribute *attribute;
|
|
PRBool tok = PR_FALSE;
|
|
|
|
attribute=sftk_FindAttribute(object,type);
|
|
if (attribute == NULL) { return PR_FALSE; }
|
|
tok = (PRBool)(*(CK_BBOOL *)attribute->attrib.pValue);
|
|
sftk_FreeAttribute(attribute);
|
|
|
|
return tok;
|
|
}
|
|
|
|
/*
|
|
* force an attribute to null.
|
|
* this is for sensitive keys which are stored in the database, we don't
|
|
* want to keep this info around in memory in the clear.
|
|
*/
|
|
void
|
|
sftk_nullAttribute(SFTKObject *object,CK_ATTRIBUTE_TYPE type)
|
|
{
|
|
SFTKAttribute *attribute;
|
|
|
|
attribute=sftk_FindAttribute(object,type);
|
|
if (attribute == NULL) return;
|
|
|
|
if (attribute->attrib.pValue != NULL) {
|
|
PORT_Memset(attribute->attrib.pValue,0,attribute->attrib.ulValueLen);
|
|
if (attribute->freeData) {
|
|
PORT_Free(attribute->attrib.pValue);
|
|
}
|
|
attribute->freeData = PR_FALSE;
|
|
attribute->attrib.pValue = NULL;
|
|
attribute->attrib.ulValueLen = 0;
|
|
}
|
|
sftk_FreeAttribute(attribute);
|
|
}
|
|
|
|
static CK_RV
|
|
sftk_SetCertAttribute(SFTKTokenObject *to, CK_ATTRIBUTE_TYPE type,
|
|
void *value, unsigned int len)
|
|
{
|
|
NSSLOWCERTCertificate *cert;
|
|
NSSLOWCERTCertDBHandle *certHandle;
|
|
char *nickname = NULL;
|
|
SECStatus rv;
|
|
CK_RV crv;
|
|
|
|
/* we can't change the EMAIL values, but let the
|
|
* upper layers feel better about the fact we tried to set these */
|
|
if (type == CKA_NETSCAPE_EMAIL) {
|
|
return CKR_OK;
|
|
}
|
|
|
|
certHandle = sftk_getCertDB(to->obj.slot);
|
|
if (certHandle == NULL) {
|
|
crv = CKR_TOKEN_WRITE_PROTECTED;
|
|
goto done;
|
|
}
|
|
|
|
if ((type != CKA_LABEL) && (type != CKA_ID)) {
|
|
crv = CKR_ATTRIBUTE_READ_ONLY;
|
|
goto done;
|
|
}
|
|
|
|
cert = sftk_getCert(to, certHandle);
|
|
if (cert == NULL) {
|
|
crv = CKR_OBJECT_HANDLE_INVALID;
|
|
goto done;
|
|
}
|
|
|
|
/* if the app is trying to set CKA_ID, it's probably because it just
|
|
* imported the key. Look to see if we need to set the CERTDB_USER bits.
|
|
*/
|
|
if (type == CKA_ID) {
|
|
if (((cert->trust->sslFlags & CERTDB_USER) == 0) &&
|
|
((cert->trust->emailFlags & CERTDB_USER) == 0) &&
|
|
((cert->trust->objectSigningFlags & CERTDB_USER) == 0)) {
|
|
SFTKSlot *slot = to->obj.slot;
|
|
NSSLOWKEYDBHandle *keyHandle;
|
|
|
|
keyHandle = sftk_getKeyDB(slot);
|
|
if (keyHandle) {
|
|
if (nsslowkey_KeyForCertExists(keyHandle, cert)) {
|
|
NSSLOWCERTCertTrust trust = *cert->trust;
|
|
trust.sslFlags |= CERTDB_USER;
|
|
trust.emailFlags |= CERTDB_USER;
|
|
trust.objectSigningFlags |= CERTDB_USER;
|
|
nsslowcert_ChangeCertTrust(certHandle,cert,&trust);
|
|
}
|
|
sftk_freeKeyDB(keyHandle);
|
|
}
|
|
}
|
|
crv = CKR_OK;
|
|
goto done;
|
|
}
|
|
|
|
/* must be CKA_LABEL */
|
|
if (value != NULL) {
|
|
nickname = PORT_ZAlloc(len+1);
|
|
if (nickname == NULL) {
|
|
crv = CKR_HOST_MEMORY;
|
|
goto done;
|
|
}
|
|
PORT_Memcpy(nickname,value,len);
|
|
nickname[len] = 0;
|
|
}
|
|
rv = nsslowcert_AddPermNickname(certHandle, cert, nickname);
|
|
crv = (rv == SECSuccess) ? CKR_OK : CKR_DEVICE_ERROR;
|
|
|
|
done:
|
|
if (nickname) {
|
|
PORT_Free(nickname);
|
|
}
|
|
if (certHandle) {
|
|
sftk_freeCertDB(certHandle);
|
|
}
|
|
return crv;
|
|
}
|
|
|
|
static CK_RV
|
|
sftk_SetPrivateKeyAttribute(SFTKTokenObject *to, CK_ATTRIBUTE_TYPE type,
|
|
void *value, unsigned int len)
|
|
{
|
|
NSSLOWKEYPrivateKey *privKey;
|
|
NSSLOWKEYDBHandle *keyHandle;
|
|
char *nickname = NULL;
|
|
SECStatus rv;
|
|
CK_RV crv;
|
|
|
|
/* we can't change the ID and we don't store the subject, but let the
|
|
* upper layers feel better about the fact we tried to set these */
|
|
if ((type == CKA_ID) || (type == CKA_SUBJECT)) {
|
|
return CKR_OK;
|
|
}
|
|
|
|
keyHandle = sftk_getKeyDB(to->obj.slot);
|
|
if (keyHandle == NULL) {
|
|
crv = CKR_TOKEN_WRITE_PROTECTED;
|
|
goto done;
|
|
}
|
|
if (type != CKA_LABEL) {
|
|
crv = CKR_ATTRIBUTE_READ_ONLY;
|
|
goto done;
|
|
}
|
|
|
|
privKey = sftk_GetPrivateKeyWithDB(to, keyHandle);
|
|
if (privKey == NULL) {
|
|
crv = CKR_OBJECT_HANDLE_INVALID;
|
|
goto done;
|
|
}
|
|
if (value != NULL) {
|
|
nickname = PORT_ZAlloc(len+1);
|
|
if (nickname == NULL) {
|
|
crv = CKR_HOST_MEMORY;
|
|
goto done;
|
|
}
|
|
PORT_Memcpy(nickname,value,len);
|
|
nickname[len] = 0;
|
|
}
|
|
rv = nsslowkey_UpdateNickname(keyHandle, privKey, &to->dbKey,
|
|
nickname, to->obj.slot->password);
|
|
crv = (rv == SECSuccess) ? CKR_OK : CKR_DEVICE_ERROR;
|
|
done:
|
|
if (nickname) {
|
|
PORT_Free(nickname);
|
|
}
|
|
if (keyHandle) {
|
|
sftk_freeKeyDB(keyHandle);
|
|
}
|
|
return crv;
|
|
}
|
|
|
|
static CK_RV
|
|
sftk_SetTrustAttribute(SFTKTokenObject *to, CK_ATTRIBUTE_TYPE type,
|
|
void *value, unsigned int len)
|
|
{
|
|
unsigned int flags;
|
|
CK_TRUST trust;
|
|
NSSLOWCERTCertificate *cert;
|
|
NSSLOWCERTCertDBHandle *certHandle;
|
|
NSSLOWCERTCertTrust dbTrust;
|
|
SECStatus rv;
|
|
CK_RV crv;
|
|
|
|
if (len != sizeof (CK_TRUST)) {
|
|
return CKR_ATTRIBUTE_VALUE_INVALID;
|
|
}
|
|
trust = *(CK_TRUST *)value;
|
|
flags = sftk_MapTrust(trust, (PRBool) (type == CKA_TRUST_SERVER_AUTH));
|
|
|
|
certHandle = sftk_getCertDB(to->obj.slot);
|
|
|
|
if (certHandle == NULL) {
|
|
crv = CKR_TOKEN_WRITE_PROTECTED;
|
|
goto done;
|
|
}
|
|
|
|
cert = sftk_getCert(to, certHandle);
|
|
if (cert == NULL) {
|
|
crv = CKR_OBJECT_HANDLE_INVALID;
|
|
goto done;
|
|
}
|
|
dbTrust = *cert->trust;
|
|
|
|
switch (type) {
|
|
case CKA_TRUST_EMAIL_PROTECTION:
|
|
dbTrust.emailFlags = flags |
|
|
(cert->trust->emailFlags & CERTDB_PRESERVE_TRUST_BITS);
|
|
break;
|
|
case CKA_TRUST_CODE_SIGNING:
|
|
dbTrust.objectSigningFlags = flags |
|
|
(cert->trust->objectSigningFlags & CERTDB_PRESERVE_TRUST_BITS);
|
|
break;
|
|
case CKA_TRUST_CLIENT_AUTH:
|
|
dbTrust.sslFlags = flags | (cert->trust->sslFlags &
|
|
(CERTDB_PRESERVE_TRUST_BITS|CERTDB_TRUSTED_CA));
|
|
break;
|
|
case CKA_TRUST_SERVER_AUTH:
|
|
dbTrust.sslFlags = flags | (cert->trust->sslFlags &
|
|
(CERTDB_PRESERVE_TRUST_BITS|CERTDB_TRUSTED_CLIENT_CA));
|
|
break;
|
|
default:
|
|
crv = CKR_ATTRIBUTE_READ_ONLY;
|
|
goto done;
|
|
}
|
|
|
|
rv = nsslowcert_ChangeCertTrust(certHandle, cert, &dbTrust);
|
|
crv = (rv == SECSuccess) ? CKR_OK : CKR_DEVICE_ERROR;
|
|
done:
|
|
if (certHandle) {
|
|
sftk_freeCertDB(certHandle);
|
|
}
|
|
return crv;
|
|
}
|
|
|
|
static CK_RV
|
|
sftk_forceTokenAttribute(SFTKObject *object,CK_ATTRIBUTE_TYPE type,
|
|
void *value, unsigned int len)
|
|
{
|
|
SFTKAttribute *attribute;
|
|
SFTKTokenObject *to = sftk_narrowToTokenObject(object);
|
|
CK_RV crv = CKR_ATTRIBUTE_READ_ONLY;
|
|
|
|
PORT_Assert(to);
|
|
if (to == NULL) {
|
|
return CKR_DEVICE_ERROR;
|
|
}
|
|
|
|
/* if we are just setting it to the value we already have,
|
|
* allow it to happen. Let label setting go through so
|
|
* we have the opportunity to repair any database corruption. */
|
|
attribute=sftk_FindAttribute(object,type);
|
|
PORT_Assert(attribute);
|
|
if (!attribute) {
|
|
return CKR_ATTRIBUTE_TYPE_INVALID;
|
|
|
|
}
|
|
if ((type != CKA_LABEL) && (attribute->attrib.ulValueLen == len) &&
|
|
PORT_Memcmp(attribute->attrib.pValue,value,len) == 0) {
|
|
sftk_FreeAttribute(attribute);
|
|
return CKR_OK;
|
|
}
|
|
|
|
switch (object->objclass) {
|
|
case CKO_CERTIFICATE:
|
|
/* change NICKNAME, EMAIL, */
|
|
crv = sftk_SetCertAttribute(to,type,value,len);
|
|
break;
|
|
case CKO_NETSCAPE_CRL:
|
|
/* change URL */
|
|
break;
|
|
case CKO_NETSCAPE_TRUST:
|
|
crv = sftk_SetTrustAttribute(to,type,value,len);
|
|
break;
|
|
case CKO_PRIVATE_KEY:
|
|
case CKO_SECRET_KEY:
|
|
crv = sftk_SetPrivateKeyAttribute(to,type,value,len);
|
|
break;
|
|
}
|
|
sftk_FreeAttribute(attribute);
|
|
return crv;
|
|
}
|
|
|
|
/*
|
|
* force an attribute to a spaecif value.
|
|
*/
|
|
CK_RV
|
|
sftk_forceAttribute(SFTKObject *object,CK_ATTRIBUTE_TYPE type, void *value,
|
|
unsigned int len)
|
|
{
|
|
SFTKAttribute *attribute;
|
|
void *att_val = NULL;
|
|
PRBool freeData = PR_FALSE;
|
|
|
|
PORT_Assert(object);
|
|
PORT_Assert(object->refCount);
|
|
PORT_Assert(object->slot);
|
|
if (!object ||
|
|
!object->refCount ||
|
|
!object->slot) {
|
|
return CKR_DEVICE_ERROR;
|
|
}
|
|
if (sftk_isToken(object->handle)) {
|
|
return sftk_forceTokenAttribute(object,type,value,len);
|
|
}
|
|
attribute=sftk_FindAttribute(object,type);
|
|
if (attribute == NULL) return sftk_AddAttributeType(object,type,value,len);
|
|
|
|
|
|
if (value) {
|
|
if (len <= ATTR_SPACE) {
|
|
att_val = attribute->space;
|
|
} else {
|
|
att_val = PORT_Alloc(len);
|
|
freeData = PR_TRUE;
|
|
}
|
|
if (att_val == NULL) {
|
|
return CKR_HOST_MEMORY;
|
|
}
|
|
if (attribute->attrib.pValue == att_val) {
|
|
PORT_Memset(attribute->attrib.pValue,0,
|
|
attribute->attrib.ulValueLen);
|
|
}
|
|
PORT_Memcpy(att_val,value,len);
|
|
}
|
|
if (attribute->attrib.pValue != NULL) {
|
|
if (attribute->attrib.pValue != att_val) {
|
|
PORT_Memset(attribute->attrib.pValue,0,
|
|
attribute->attrib.ulValueLen);
|
|
}
|
|
if (attribute->freeData) {
|
|
PORT_Free(attribute->attrib.pValue);
|
|
}
|
|
attribute->freeData = PR_FALSE;
|
|
attribute->attrib.pValue = NULL;
|
|
attribute->attrib.ulValueLen = 0;
|
|
}
|
|
if (att_val) {
|
|
attribute->attrib.pValue = att_val;
|
|
attribute->attrib.ulValueLen = len;
|
|
attribute->freeData = freeData;
|
|
}
|
|
sftk_FreeAttribute(attribute);
|
|
return CKR_OK;
|
|
}
|
|
|
|
/*
|
|
* return a null terminated string from attribute 'type'. This string
|
|
* is allocated and needs to be freed with PORT_Free() When complete.
|
|
*/
|
|
char *
|
|
sftk_getString(SFTKObject *object,CK_ATTRIBUTE_TYPE type)
|
|
{
|
|
SFTKAttribute *attribute;
|
|
char *label = NULL;
|
|
|
|
attribute=sftk_FindAttribute(object,type);
|
|
if (attribute == NULL) return NULL;
|
|
|
|
if (attribute->attrib.pValue != NULL) {
|
|
label = (char *) PORT_Alloc(attribute->attrib.ulValueLen+1);
|
|
if (label == NULL) {
|
|
sftk_FreeAttribute(attribute);
|
|
return NULL;
|
|
}
|
|
|
|
PORT_Memcpy(label,attribute->attrib.pValue,
|
|
attribute->attrib.ulValueLen);
|
|
label[attribute->attrib.ulValueLen] = 0;
|
|
}
|
|
sftk_FreeAttribute(attribute);
|
|
return label;
|
|
}
|
|
|
|
/*
|
|
* decode when a particular attribute may be modified
|
|
* SFTK_NEVER: This attribute must be set at object creation time and
|
|
* can never be modified.
|
|
* SFTK_ONCOPY: This attribute may be modified only when you copy the
|
|
* object.
|
|
* SFTK_SENSITIVE: The CKA_SENSITIVE attribute can only be changed from
|
|
* CK_FALSE to CK_TRUE.
|
|
* SFTK_ALWAYS: This attribute can always be modified.
|
|
* Some attributes vary their modification type based on the class of the
|
|
* object.
|
|
*/
|
|
SFTKModifyType
|
|
sftk_modifyType(CK_ATTRIBUTE_TYPE type, CK_OBJECT_CLASS inClass)
|
|
{
|
|
/* if we don't know about it, user user defined, always allow modify */
|
|
SFTKModifyType mtype = SFTK_ALWAYS;
|
|
|
|
switch(type) {
|
|
/* NEVER */
|
|
case CKA_CLASS:
|
|
case CKA_CERTIFICATE_TYPE:
|
|
case CKA_KEY_TYPE:
|
|
case CKA_MODULUS:
|
|
case CKA_MODULUS_BITS:
|
|
case CKA_PUBLIC_EXPONENT:
|
|
case CKA_PRIVATE_EXPONENT:
|
|
case CKA_PRIME:
|
|
case CKA_SUBPRIME:
|
|
case CKA_BASE:
|
|
case CKA_PRIME_1:
|
|
case CKA_PRIME_2:
|
|
case CKA_EXPONENT_1:
|
|
case CKA_EXPONENT_2:
|
|
case CKA_COEFFICIENT:
|
|
case CKA_VALUE_LEN:
|
|
case CKA_ALWAYS_SENSITIVE:
|
|
case CKA_NEVER_EXTRACTABLE:
|
|
case CKA_NETSCAPE_DB:
|
|
mtype = SFTK_NEVER;
|
|
break;
|
|
|
|
/* ONCOPY */
|
|
case CKA_TOKEN:
|
|
case CKA_PRIVATE:
|
|
case CKA_MODIFIABLE:
|
|
mtype = SFTK_ONCOPY;
|
|
break;
|
|
|
|
/* SENSITIVE */
|
|
case CKA_SENSITIVE:
|
|
case CKA_EXTRACTABLE:
|
|
mtype = SFTK_SENSITIVE;
|
|
break;
|
|
|
|
/* ALWAYS */
|
|
case CKA_LABEL:
|
|
case CKA_APPLICATION:
|
|
case CKA_ID:
|
|
case CKA_SERIAL_NUMBER:
|
|
case CKA_START_DATE:
|
|
case CKA_END_DATE:
|
|
case CKA_DERIVE:
|
|
case CKA_ENCRYPT:
|
|
case CKA_DECRYPT:
|
|
case CKA_SIGN:
|
|
case CKA_VERIFY:
|
|
case CKA_SIGN_RECOVER:
|
|
case CKA_VERIFY_RECOVER:
|
|
case CKA_WRAP:
|
|
case CKA_UNWRAP:
|
|
mtype = SFTK_ALWAYS;
|
|
break;
|
|
|
|
/* DEPENDS ON CLASS */
|
|
case CKA_VALUE:
|
|
mtype = (inClass == CKO_DATA) ? SFTK_ALWAYS : SFTK_NEVER;
|
|
break;
|
|
|
|
case CKA_SUBJECT:
|
|
mtype = (inClass == CKO_CERTIFICATE) ? SFTK_NEVER : SFTK_ALWAYS;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
return mtype;
|
|
}
|
|
|
|
/* decode if a particular attribute is sensitive (cannot be read
|
|
* back to the user of if the object is set to SENSITIVE) */
|
|
PRBool
|
|
sftk_isSensitive(CK_ATTRIBUTE_TYPE type, CK_OBJECT_CLASS inClass)
|
|
{
|
|
switch(type) {
|
|
/* ALWAYS */
|
|
case CKA_PRIVATE_EXPONENT:
|
|
case CKA_PRIME_1:
|
|
case CKA_PRIME_2:
|
|
case CKA_EXPONENT_1:
|
|
case CKA_EXPONENT_2:
|
|
case CKA_COEFFICIENT:
|
|
return PR_TRUE;
|
|
|
|
/* DEPENDS ON CLASS */
|
|
case CKA_VALUE:
|
|
/* PRIVATE and SECRET KEYS have SENSITIVE values */
|
|
return (PRBool)((inClass == CKO_PRIVATE_KEY) || (inClass == CKO_SECRET_KEY));
|
|
|
|
default:
|
|
break;
|
|
}
|
|
return PR_FALSE;
|
|
}
|
|
|
|
/*
|
|
* copy an attribute into a SECItem. Secitem is allocated in the specified
|
|
* arena.
|
|
*/
|
|
CK_RV
|
|
sftk_Attribute2SecItem(PLArenaPool *arena,SECItem *item,SFTKObject *object,
|
|
CK_ATTRIBUTE_TYPE type)
|
|
{
|
|
int len;
|
|
SFTKAttribute *attribute;
|
|
|
|
attribute = sftk_FindAttribute(object, type);
|
|
if (attribute == NULL) return CKR_TEMPLATE_INCOMPLETE;
|
|
len = attribute->attrib.ulValueLen;
|
|
|
|
if (arena) {
|
|
item->data = (unsigned char *) PORT_ArenaAlloc(arena,len);
|
|
} else {
|
|
item->data = (unsigned char *) PORT_Alloc(len);
|
|
}
|
|
if (item->data == NULL) {
|
|
sftk_FreeAttribute(attribute);
|
|
return CKR_HOST_MEMORY;
|
|
}
|
|
item->len = len;
|
|
PORT_Memcpy(item->data,attribute->attrib.pValue, len);
|
|
sftk_FreeAttribute(attribute);
|
|
return CKR_OK;
|
|
}
|
|
|
|
CK_RV
|
|
sftk_GetULongAttribute(SFTKObject *object, CK_ATTRIBUTE_TYPE type,
|
|
CK_ULONG *longData)
|
|
{
|
|
SFTKAttribute *attribute;
|
|
|
|
attribute = sftk_FindAttribute(object, type);
|
|
if (attribute == NULL) return CKR_TEMPLATE_INCOMPLETE;
|
|
|
|
if (attribute->attrib.ulValueLen != sizeof(CK_ULONG)) {
|
|
return CKR_ATTRIBUTE_VALUE_INVALID;
|
|
}
|
|
|
|
*longData = *(CK_ULONG *)attribute->attrib.pValue;
|
|
sftk_FreeAttribute(attribute);
|
|
return CKR_OK;
|
|
}
|
|
|
|
void
|
|
sftk_DeleteAttributeType(SFTKObject *object,CK_ATTRIBUTE_TYPE type)
|
|
{
|
|
SFTKAttribute *attribute;
|
|
attribute = sftk_FindAttribute(object, type);
|
|
if (attribute == NULL) return ;
|
|
sftk_DeleteAttribute(object,attribute);
|
|
sftk_FreeAttribute(attribute);
|
|
}
|
|
|
|
CK_RV
|
|
sftk_AddAttributeType(SFTKObject *object,CK_ATTRIBUTE_TYPE type,void *valPtr,
|
|
CK_ULONG length)
|
|
{
|
|
SFTKAttribute *attribute;
|
|
attribute = sftk_NewAttribute(object,type,valPtr,length);
|
|
if (attribute == NULL) { return CKR_HOST_MEMORY; }
|
|
sftk_AddAttribute(object,attribute);
|
|
return CKR_OK;
|
|
}
|
|
|
|
/*
|
|
* ******************** Object Utilities *******************************
|
|
*/
|
|
|
|
static SECStatus
|
|
sftk_deleteTokenKeyByHandle(SFTKSlot *slot, CK_OBJECT_HANDLE handle)
|
|
{
|
|
SECItem *item;
|
|
PRBool rem;
|
|
|
|
item = (SECItem *)PL_HashTableLookup(slot->tokenHashTable, (void *)handle);
|
|
rem = PL_HashTableRemove(slot->tokenHashTable,(void *)handle) ;
|
|
if (rem && item) {
|
|
SECITEM_FreeItem(item,PR_TRUE);
|
|
}
|
|
return rem ? SECSuccess : SECFailure;
|
|
}
|
|
|
|
/* must be called holding sftk_tokenKeyLock(slot) */
|
|
static SECStatus
|
|
sftk_addTokenKeyByHandle(SFTKSlot *slot, CK_OBJECT_HANDLE handle, SECItem *key)
|
|
{
|
|
PLHashEntry *entry;
|
|
SECItem *item;
|
|
|
|
/* don't add a new handle in the middle of closing down a slot */
|
|
if (!slot->present) {
|
|
return SECFailure;
|
|
}
|
|
|
|
item = SECITEM_DupItem(key);
|
|
if (item == NULL) {
|
|
return SECFailure;
|
|
}
|
|
entry = PL_HashTableAdd(slot->tokenHashTable,(void *)handle,item);
|
|
if (entry == NULL) {
|
|
SECITEM_FreeItem(item,PR_TRUE);
|
|
return SECFailure;
|
|
}
|
|
return SECSuccess;
|
|
}
|
|
|
|
/* must be called holding sftk_tokenKeyLock(slot) */
|
|
static SECItem *
|
|
sftk_lookupTokenKeyByHandle(SFTKSlot *slot, CK_OBJECT_HANDLE handle)
|
|
{
|
|
return (SECItem *)PL_HashTableLookup(slot->tokenHashTable, (void *)handle);
|
|
}
|
|
|
|
/*
|
|
* use the refLock. This operations should be very rare, so the added
|
|
* contention on the ref lock should be lower than the overhead of adding
|
|
* a new lock. We use separate functions for this just in case I'm wrong.
|
|
*/
|
|
static void
|
|
sftk_tokenKeyLock(SFTKSlot *slot) {
|
|
PZ_Lock(slot->objectLock);
|
|
}
|
|
|
|
static void
|
|
sftk_tokenKeyUnlock(SFTKSlot *slot) {
|
|
PZ_Unlock(slot->objectLock);
|
|
}
|
|
|
|
static PRIntn
|
|
sftk_freeHashItem(PLHashEntry* entry, PRIntn index, void *arg)
|
|
{
|
|
SECItem *item = (SECItem *)entry->value;
|
|
|
|
SECITEM_FreeItem(item, PR_TRUE);
|
|
return HT_ENUMERATE_NEXT;
|
|
}
|
|
|
|
CK_RV
|
|
SFTK_ClearTokenKeyHashTable(SFTKSlot *slot)
|
|
{
|
|
sftk_tokenKeyLock(slot);
|
|
PORT_Assert(!slot->present);
|
|
PL_HashTableEnumerateEntries(slot->tokenHashTable, sftk_freeHashItem, NULL);
|
|
sftk_tokenKeyUnlock(slot);
|
|
return CKR_OK;
|
|
}
|
|
|
|
|
|
/* allocation hooks that allow us to recycle old object structures */
|
|
static SFTKObjectFreeList sessionObjectList = { NULL, NULL, 0 };
|
|
static SFTKObjectFreeList tokenObjectList = { NULL, NULL, 0 };
|
|
|
|
SFTKObject *
|
|
sftk_GetObjectFromList(PRBool *hasLocks, PRBool optimizeSpace,
|
|
SFTKObjectFreeList *list, unsigned int hashSize, PRBool isSessionObject)
|
|
{
|
|
SFTKObject *object;
|
|
int size = 0;
|
|
|
|
if (!optimizeSpace) {
|
|
PZ_Lock(list->lock);
|
|
object = list->head;
|
|
if (object) {
|
|
list->head = object->next;
|
|
list->count--;
|
|
}
|
|
PZ_Unlock(list->lock);
|
|
if (object) {
|
|
object->next = object->prev = NULL;
|
|
*hasLocks = PR_TRUE;
|
|
return object;
|
|
}
|
|
}
|
|
size = isSessionObject ? sizeof(SFTKSessionObject)
|
|
+ hashSize *sizeof(SFTKAttribute *) : sizeof(SFTKTokenObject);
|
|
|
|
object = (SFTKObject*)PORT_ZAlloc(size);
|
|
if (isSessionObject) {
|
|
((SFTKSessionObject *)object)->hashSize = hashSize;
|
|
}
|
|
*hasLocks = PR_FALSE;
|
|
return object;
|
|
}
|
|
|
|
static void
|
|
sftk_PutObjectToList(SFTKObject *object, SFTKObjectFreeList *list,
|
|
PRBool isSessionObject) {
|
|
|
|
/* the code below is equivalent to :
|
|
* optimizeSpace = isSessionObject ? object->optimizeSpace : PR_FALSE;
|
|
* just faster.
|
|
*/
|
|
PRBool optimizeSpace = isSessionObject &&
|
|
((SFTKSessionObject *)object)->optimizeSpace;
|
|
if (!optimizeSpace && (list->count < MAX_OBJECT_LIST_SIZE)) {
|
|
PZ_Lock(list->lock);
|
|
object->next = list->head;
|
|
list->head = object;
|
|
list->count++;
|
|
PZ_Unlock(list->lock);
|
|
return;
|
|
}
|
|
if (isSessionObject) {
|
|
SFTKSessionObject *so = (SFTKSessionObject *)object;
|
|
PZ_DestroyLock(so->attributeLock);
|
|
so->attributeLock = NULL;
|
|
}
|
|
PZ_DestroyLock(object->refLock);
|
|
object->refLock = NULL;
|
|
PORT_Free(object);
|
|
}
|
|
|
|
static SFTKObject *
|
|
sftk_freeObjectData(SFTKObject *object) {
|
|
SFTKObject *next = object->next;
|
|
|
|
PORT_Free(object);
|
|
return next;
|
|
}
|
|
|
|
static void
|
|
sftk_InitFreeList(SFTKObjectFreeList *list)
|
|
{
|
|
list->lock = PZ_NewLock(nssILockObject);
|
|
}
|
|
|
|
void sftk_InitFreeLists(void)
|
|
{
|
|
sftk_InitFreeList(&sessionObjectList);
|
|
sftk_InitFreeList(&tokenObjectList);
|
|
}
|
|
|
|
static void
|
|
sftk_CleanupFreeList(SFTKObjectFreeList *list, PRBool isSessionList)
|
|
{
|
|
SFTKObject *object;
|
|
|
|
if (!list->lock) {
|
|
return;
|
|
}
|
|
PZ_Lock(list->lock);
|
|
for (object= list->head; object != NULL;
|
|
object = sftk_freeObjectData(object)) {
|
|
PZ_DestroyLock(object->refLock);
|
|
if (isSessionList) {
|
|
PZ_DestroyLock(((SFTKSessionObject *)object)->attributeLock);
|
|
}
|
|
}
|
|
list->count = 0;
|
|
list->head = NULL;
|
|
PZ_Unlock(list->lock);
|
|
PZ_DestroyLock(list->lock);
|
|
list->lock = NULL;
|
|
}
|
|
|
|
void
|
|
sftk_CleanupFreeLists(void)
|
|
{
|
|
sftk_CleanupFreeList(&sessionObjectList, PR_TRUE);
|
|
sftk_CleanupFreeList(&tokenObjectList, PR_FALSE);
|
|
}
|
|
|
|
|
|
/*
|
|
* Create a new object
|
|
*/
|
|
SFTKObject *
|
|
sftk_NewObject(SFTKSlot *slot)
|
|
{
|
|
SFTKObject *object;
|
|
SFTKSessionObject *sessObject;
|
|
PRBool hasLocks = PR_FALSE;
|
|
unsigned int i;
|
|
unsigned int hashSize = 0;
|
|
|
|
hashSize = (slot->optimizeSpace) ? SPACE_ATTRIBUTE_HASH_SIZE :
|
|
TIME_ATTRIBUTE_HASH_SIZE;
|
|
|
|
object = sftk_GetObjectFromList(&hasLocks, slot->optimizeSpace,
|
|
&sessionObjectList, hashSize, PR_TRUE);
|
|
if (object == NULL) {
|
|
return NULL;
|
|
}
|
|
sessObject = (SFTKSessionObject *)object;
|
|
sessObject->nextAttr = 0;
|
|
|
|
for (i=0; i < MAX_OBJS_ATTRS; i++) {
|
|
sessObject->attrList[i].attrib.pValue = NULL;
|
|
sessObject->attrList[i].freeData = PR_FALSE;
|
|
}
|
|
sessObject->optimizeSpace = slot->optimizeSpace;
|
|
|
|
object->handle = 0;
|
|
object->next = object->prev = NULL;
|
|
object->slot = slot;
|
|
|
|
object->refCount = 1;
|
|
sessObject->sessionList.next = NULL;
|
|
sessObject->sessionList.prev = NULL;
|
|
sessObject->sessionList.parent = object;
|
|
sessObject->session = NULL;
|
|
sessObject->wasDerived = PR_FALSE;
|
|
if (!hasLocks) object->refLock = PZ_NewLock(nssILockRefLock);
|
|
if (object->refLock == NULL) {
|
|
PORT_Free(object);
|
|
return NULL;
|
|
}
|
|
if (!hasLocks) sessObject->attributeLock = PZ_NewLock(nssILockAttribute);
|
|
if (sessObject->attributeLock == NULL) {
|
|
PZ_DestroyLock(object->refLock);
|
|
PORT_Free(object);
|
|
return NULL;
|
|
}
|
|
for (i=0; i < sessObject->hashSize; i++) {
|
|
sessObject->head[i] = NULL;
|
|
}
|
|
object->objectInfo = NULL;
|
|
object->infoFree = NULL;
|
|
return object;
|
|
}
|
|
|
|
static CK_RV
|
|
sftk_DestroySessionObjectData(SFTKSessionObject *so)
|
|
{
|
|
int i;
|
|
|
|
for (i=0; i < MAX_OBJS_ATTRS; i++) {
|
|
unsigned char *value = so->attrList[i].attrib.pValue;
|
|
if (value) {
|
|
PORT_Memset(value,0,so->attrList[i].attrib.ulValueLen);
|
|
if (so->attrList[i].freeData) {
|
|
PORT_Free(value);
|
|
}
|
|
so->attrList[i].attrib.pValue = NULL;
|
|
so->attrList[i].freeData = PR_FALSE;
|
|
}
|
|
}
|
|
/* PZ_DestroyLock(so->attributeLock);*/
|
|
return CKR_OK;
|
|
}
|
|
|
|
/*
|
|
* free all the data associated with an object. Object reference count must
|
|
* be 'zero'.
|
|
*/
|
|
static CK_RV
|
|
sftk_DestroyObject(SFTKObject *object)
|
|
{
|
|
CK_RV crv = CKR_OK;
|
|
SFTKSessionObject *so = sftk_narrowToSessionObject(object);
|
|
SFTKTokenObject *to = sftk_narrowToTokenObject(object);
|
|
|
|
PORT_Assert(object->refCount == 0);
|
|
|
|
/* delete the database value */
|
|
if (to) {
|
|
if (to->dbKey.data) {
|
|
PORT_Free(to->dbKey.data);
|
|
to->dbKey.data = NULL;
|
|
}
|
|
}
|
|
if (so) {
|
|
sftk_DestroySessionObjectData(so);
|
|
}
|
|
if (object->objectInfo) {
|
|
(*object->infoFree)(object->objectInfo);
|
|
object->objectInfo = NULL;
|
|
object->infoFree = NULL;
|
|
}
|
|
if (so) {
|
|
sftk_PutObjectToList(object,&sessionObjectList,PR_TRUE);
|
|
} else {
|
|
sftk_PutObjectToList(object,&tokenObjectList,PR_FALSE);
|
|
}
|
|
return crv;
|
|
}
|
|
|
|
void
|
|
sftk_ReferenceObject(SFTKObject *object)
|
|
{
|
|
PZ_Lock(object->refLock);
|
|
object->refCount++;
|
|
PZ_Unlock(object->refLock);
|
|
}
|
|
|
|
static SFTKObject *
|
|
sftk_ObjectFromHandleOnSlot(CK_OBJECT_HANDLE handle, SFTKSlot *slot)
|
|
{
|
|
SFTKObject *object;
|
|
PRUint32 index = sftk_hash(handle, slot->tokObjHashSize);
|
|
|
|
if (sftk_isToken(handle)) {
|
|
return sftk_NewTokenObject(slot, NULL, handle);
|
|
}
|
|
|
|
PZ_Lock(slot->objectLock);
|
|
sftkqueue_find2(object, handle, index, slot->tokObjects);
|
|
if (object) {
|
|
sftk_ReferenceObject(object);
|
|
}
|
|
PZ_Unlock(slot->objectLock);
|
|
|
|
return(object);
|
|
}
|
|
/*
|
|
* look up and object structure from a handle. OBJECT_Handles only make
|
|
* sense in terms of a given session. make a reference to that object
|
|
* structure returned.
|
|
*/
|
|
SFTKObject *
|
|
sftk_ObjectFromHandle(CK_OBJECT_HANDLE handle, SFTKSession *session)
|
|
{
|
|
SFTKSlot *slot = sftk_SlotFromSession(session);
|
|
|
|
return sftk_ObjectFromHandleOnSlot(handle,slot);
|
|
}
|
|
|
|
|
|
/*
|
|
* release a reference to an object handle
|
|
*/
|
|
SFTKFreeStatus
|
|
sftk_FreeObject(SFTKObject *object)
|
|
{
|
|
PRBool destroy = PR_FALSE;
|
|
CK_RV crv;
|
|
|
|
PZ_Lock(object->refLock);
|
|
if (object->refCount == 1) destroy = PR_TRUE;
|
|
object->refCount--;
|
|
PZ_Unlock(object->refLock);
|
|
|
|
if (destroy) {
|
|
crv = sftk_DestroyObject(object);
|
|
if (crv != CKR_OK) {
|
|
return SFTK_DestroyFailure;
|
|
}
|
|
return SFTK_Destroyed;
|
|
}
|
|
return SFTK_Busy;
|
|
}
|
|
|
|
/*
|
|
* add an object to a slot and session queue. These two functions
|
|
* adopt the object.
|
|
*/
|
|
void
|
|
sftk_AddSlotObject(SFTKSlot *slot, SFTKObject *object)
|
|
{
|
|
PRUint32 index = sftk_hash(object->handle, slot->tokObjHashSize);
|
|
sftkqueue_init_element(object);
|
|
PZ_Lock(slot->objectLock);
|
|
sftkqueue_add2(object, object->handle, index, slot->tokObjects);
|
|
PZ_Unlock(slot->objectLock);
|
|
}
|
|
|
|
void
|
|
sftk_AddObject(SFTKSession *session, SFTKObject *object)
|
|
{
|
|
SFTKSlot *slot = sftk_SlotFromSession(session);
|
|
SFTKSessionObject *so = sftk_narrowToSessionObject(object);
|
|
|
|
if (so) {
|
|
PZ_Lock(session->objectLock);
|
|
sftkqueue_add(&so->sessionList,0,session->objects,0);
|
|
so->session = session;
|
|
PZ_Unlock(session->objectLock);
|
|
}
|
|
sftk_AddSlotObject(slot,object);
|
|
sftk_ReferenceObject(object);
|
|
}
|
|
|
|
/*
|
|
* add an object to a slot andsession queue
|
|
*/
|
|
CK_RV
|
|
sftk_DeleteObject(SFTKSession *session, SFTKObject *object)
|
|
{
|
|
SFTKSlot *slot = sftk_SlotFromSession(session);
|
|
SFTKSessionObject *so = sftk_narrowToSessionObject(object);
|
|
SFTKTokenObject *to = sftk_narrowToTokenObject(object);
|
|
CK_RV crv = CKR_OK;
|
|
SECStatus rv;
|
|
NSSLOWCERTCertificate *cert;
|
|
NSSLOWCERTCertTrust tmptrust;
|
|
PRBool isKrl;
|
|
PRUint32 index = sftk_hash(object->handle, slot->tokObjHashSize);
|
|
|
|
/* Handle Token case */
|
|
if (so && so->session) {
|
|
SFTKSession *session = so->session;
|
|
PZ_Lock(session->objectLock);
|
|
sftkqueue_delete(&so->sessionList,0,session->objects,0);
|
|
PZ_Unlock(session->objectLock);
|
|
PZ_Lock(slot->objectLock);
|
|
sftkqueue_delete2(object, object->handle, index, slot->tokObjects);
|
|
PZ_Unlock(slot->objectLock);
|
|
sftkqueue_clear_deleted_element(object);
|
|
sftk_FreeObject(object); /* reduce it's reference count */
|
|
} else {
|
|
NSSLOWKEYDBHandle *keyHandle;
|
|
NSSLOWCERTCertDBHandle *certHandle;
|
|
|
|
PORT_Assert(to);
|
|
/* remove the objects from the real data base */
|
|
switch (object->handle & SFTK_TOKEN_TYPE_MASK) {
|
|
case SFTK_TOKEN_TYPE_PRIV:
|
|
case SFTK_TOKEN_TYPE_KEY:
|
|
/* KEYID is the public KEY for DSA and DH, and the MODULUS for
|
|
* RSA */
|
|
keyHandle = sftk_getKeyDB(slot);
|
|
if (!keyHandle) {
|
|
crv = CKR_TOKEN_WRITE_PROTECTED;
|
|
break;
|
|
}
|
|
rv = nsslowkey_DeleteKey(keyHandle, &to->dbKey);
|
|
sftk_freeKeyDB(keyHandle);
|
|
if (rv != SECSuccess) {
|
|
crv = CKR_DEVICE_ERROR;
|
|
}
|
|
break;
|
|
case SFTK_TOKEN_TYPE_PUB:
|
|
break; /* public keys only exist at the behest of the priv key */
|
|
case SFTK_TOKEN_TYPE_CERT:
|
|
certHandle = sftk_getCertDB(slot);
|
|
if (!certHandle) {
|
|
crv = CKR_TOKEN_WRITE_PROTECTED;
|
|
break;
|
|
}
|
|
cert = nsslowcert_FindCertByKey(certHandle,&to->dbKey);
|
|
sftk_freeCertDB(certHandle);
|
|
if (cert == NULL) {
|
|
crv = CKR_DEVICE_ERROR;
|
|
break;
|
|
}
|
|
rv = nsslowcert_DeletePermCertificate(cert);
|
|
if (rv != SECSuccess) {
|
|
crv = CKR_DEVICE_ERROR;
|
|
}
|
|
nsslowcert_DestroyCertificate(cert);
|
|
break;
|
|
case SFTK_TOKEN_TYPE_CRL:
|
|
certHandle = sftk_getCertDB(slot);
|
|
if (!certHandle) {
|
|
crv = CKR_TOKEN_WRITE_PROTECTED;
|
|
break;
|
|
}
|
|
isKrl = (PRBool) (object->handle == SFTK_TOKEN_KRL_HANDLE);
|
|
rv = nsslowcert_DeletePermCRL(certHandle, &to->dbKey, isKrl);
|
|
sftk_freeCertDB(certHandle);
|
|
if (rv == SECFailure) crv = CKR_DEVICE_ERROR;
|
|
break;
|
|
case SFTK_TOKEN_TYPE_TRUST:
|
|
certHandle = sftk_getCertDB(slot);
|
|
if (!certHandle) {
|
|
crv = CKR_TOKEN_WRITE_PROTECTED;
|
|
break;
|
|
}
|
|
cert = nsslowcert_FindCertByKey(certHandle, &to->dbKey);
|
|
if (cert == NULL) {
|
|
sftk_freeCertDB(certHandle);
|
|
crv = CKR_DEVICE_ERROR;
|
|
break;
|
|
}
|
|
tmptrust = *cert->trust;
|
|
tmptrust.sslFlags &= CERTDB_PRESERVE_TRUST_BITS;
|
|
tmptrust.emailFlags &= CERTDB_PRESERVE_TRUST_BITS;
|
|
tmptrust.objectSigningFlags &= CERTDB_PRESERVE_TRUST_BITS;
|
|
tmptrust.sslFlags |= CERTDB_TRUSTED_UNKNOWN;
|
|
tmptrust.emailFlags |= CERTDB_TRUSTED_UNKNOWN;
|
|
tmptrust.objectSigningFlags |= CERTDB_TRUSTED_UNKNOWN;
|
|
rv = nsslowcert_ChangeCertTrust(certHandle, cert, &tmptrust);
|
|
sftk_freeCertDB(certHandle);
|
|
if (rv != SECSuccess) crv = CKR_DEVICE_ERROR;
|
|
nsslowcert_DestroyCertificate(cert);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
sftk_tokenKeyLock(object->slot);
|
|
sftk_deleteTokenKeyByHandle(object->slot,object->handle);
|
|
sftk_tokenKeyUnlock(object->slot);
|
|
}
|
|
return crv;
|
|
}
|
|
|
|
/*
|
|
* Token objects don't explicitly store their attributes, so we need to know
|
|
* what attributes make up a particular token object before we can copy it.
|
|
* below are the tables by object type.
|
|
*/
|
|
static const CK_ATTRIBUTE_TYPE commonAttrs[] = {
|
|
CKA_CLASS, CKA_TOKEN, CKA_PRIVATE, CKA_LABEL, CKA_MODIFIABLE
|
|
};
|
|
static const CK_ULONG commonAttrsCount =
|
|
sizeof(commonAttrs)/sizeof(commonAttrs[0]);
|
|
|
|
static const CK_ATTRIBUTE_TYPE commonKeyAttrs[] = {
|
|
CKA_ID, CKA_START_DATE, CKA_END_DATE, CKA_DERIVE, CKA_LOCAL, CKA_KEY_TYPE
|
|
};
|
|
static const CK_ULONG commonKeyAttrsCount =
|
|
sizeof(commonKeyAttrs)/sizeof(commonKeyAttrs[0]);
|
|
|
|
static const CK_ATTRIBUTE_TYPE secretKeyAttrs[] = {
|
|
CKA_SENSITIVE, CKA_EXTRACTABLE, CKA_ENCRYPT, CKA_DECRYPT, CKA_SIGN,
|
|
CKA_VERIFY, CKA_WRAP, CKA_UNWRAP, CKA_VALUE
|
|
};
|
|
static const CK_ULONG secretKeyAttrsCount =
|
|
sizeof(secretKeyAttrs)/sizeof(secretKeyAttrs[0]);
|
|
|
|
static const CK_ATTRIBUTE_TYPE commonPubKeyAttrs[] = {
|
|
CKA_ENCRYPT, CKA_VERIFY, CKA_VERIFY_RECOVER, CKA_WRAP, CKA_SUBJECT
|
|
};
|
|
static const CK_ULONG commonPubKeyAttrsCount =
|
|
sizeof(commonPubKeyAttrs)/sizeof(commonPubKeyAttrs[0]);
|
|
|
|
static const CK_ATTRIBUTE_TYPE rsaPubKeyAttrs[] = {
|
|
CKA_MODULUS, CKA_PUBLIC_EXPONENT
|
|
};
|
|
static const CK_ULONG rsaPubKeyAttrsCount =
|
|
sizeof(rsaPubKeyAttrs)/sizeof(rsaPubKeyAttrs[0]);
|
|
|
|
static const CK_ATTRIBUTE_TYPE dsaPubKeyAttrs[] = {
|
|
CKA_SUBPRIME, CKA_PRIME, CKA_BASE, CKA_VALUE
|
|
};
|
|
static const CK_ULONG dsaPubKeyAttrsCount =
|
|
sizeof(dsaPubKeyAttrs)/sizeof(dsaPubKeyAttrs[0]);
|
|
|
|
static const CK_ATTRIBUTE_TYPE dhPubKeyAttrs[] = {
|
|
CKA_PRIME, CKA_BASE, CKA_VALUE
|
|
};
|
|
static const CK_ULONG dhPubKeyAttrsCount =
|
|
sizeof(dhPubKeyAttrs)/sizeof(dhPubKeyAttrs[0]);
|
|
#ifdef NSS_ENABLE_ECC
|
|
static const CK_ATTRIBUTE_TYPE ecPubKeyAttrs[] = {
|
|
CKA_EC_PARAMS, CKA_EC_POINT
|
|
};
|
|
static const CK_ULONG ecPubKeyAttrsCount =
|
|
sizeof(ecPubKeyAttrs)/sizeof(ecPubKeyAttrs[0]);
|
|
#endif
|
|
|
|
static const CK_ATTRIBUTE_TYPE commonPrivKeyAttrs[] = {
|
|
CKA_DECRYPT, CKA_SIGN, CKA_SIGN_RECOVER, CKA_UNWRAP, CKA_SUBJECT,
|
|
CKA_SENSITIVE, CKA_EXTRACTABLE, CKA_NETSCAPE_DB
|
|
};
|
|
static const CK_ULONG commonPrivKeyAttrsCount =
|
|
sizeof(commonPrivKeyAttrs)/sizeof(commonPrivKeyAttrs[0]);
|
|
|
|
static const CK_ATTRIBUTE_TYPE rsaPrivKeyAttrs[] = {
|
|
CKA_MODULUS, CKA_PUBLIC_EXPONENT, CKA_PRIVATE_EXPONENT,
|
|
CKA_PRIME_1, CKA_PRIME_2, CKA_EXPONENT_1, CKA_EXPONENT_2, CKA_COEFFICIENT
|
|
};
|
|
static const CK_ULONG rsaPrivKeyAttrsCount =
|
|
sizeof(rsaPrivKeyAttrs)/sizeof(rsaPrivKeyAttrs[0]);
|
|
|
|
static const CK_ATTRIBUTE_TYPE dsaPrivKeyAttrs[] = {
|
|
CKA_SUBPRIME, CKA_PRIME, CKA_BASE, CKA_VALUE
|
|
};
|
|
static const CK_ULONG dsaPrivKeyAttrsCount =
|
|
sizeof(dsaPrivKeyAttrs)/sizeof(dsaPrivKeyAttrs[0]);
|
|
|
|
static const CK_ATTRIBUTE_TYPE dhPrivKeyAttrs[] = {
|
|
CKA_PRIME, CKA_BASE, CKA_VALUE
|
|
};
|
|
static const CK_ULONG dhPrivKeyAttrsCount =
|
|
sizeof(dhPrivKeyAttrs)/sizeof(dhPrivKeyAttrs[0]);
|
|
#ifdef NSS_ENABLE_ECC
|
|
static const CK_ATTRIBUTE_TYPE ecPrivKeyAttrs[] = {
|
|
CKA_EC_PARAMS, CKA_VALUE
|
|
};
|
|
static const CK_ULONG ecPrivKeyAttrsCount =
|
|
sizeof(ecPrivKeyAttrs)/sizeof(ecPrivKeyAttrs[0]);
|
|
#endif
|
|
|
|
static const CK_ATTRIBUTE_TYPE certAttrs[] = {
|
|
CKA_CERTIFICATE_TYPE, CKA_VALUE, CKA_SUBJECT, CKA_ISSUER, CKA_SERIAL_NUMBER
|
|
};
|
|
static const CK_ULONG certAttrsCount =
|
|
sizeof(certAttrs)/sizeof(certAttrs[0]);
|
|
|
|
static const CK_ATTRIBUTE_TYPE trustAttrs[] = {
|
|
CKA_ISSUER, CKA_SERIAL_NUMBER, CKA_CERT_SHA1_HASH, CKA_CERT_MD5_HASH,
|
|
CKA_TRUST_SERVER_AUTH, CKA_TRUST_CLIENT_AUTH, CKA_TRUST_EMAIL_PROTECTION,
|
|
CKA_TRUST_CODE_SIGNING, CKA_TRUST_STEP_UP_APPROVED
|
|
};
|
|
static const CK_ULONG trustAttrsCount =
|
|
sizeof(trustAttrs)/sizeof(trustAttrs[0]);
|
|
|
|
static const CK_ATTRIBUTE_TYPE smimeAttrs[] = {
|
|
CKA_SUBJECT, CKA_NETSCAPE_EMAIL, CKA_NETSCAPE_SMIME_TIMESTAMP, CKA_VALUE
|
|
};
|
|
static const CK_ULONG smimeAttrsCount =
|
|
sizeof(smimeAttrs)/sizeof(smimeAttrs[0]);
|
|
|
|
static const CK_ATTRIBUTE_TYPE crlAttrs[] = {
|
|
CKA_SUBJECT, CKA_VALUE, CKA_NETSCAPE_URL, CKA_NETSCAPE_KRL
|
|
};
|
|
static const CK_ULONG crlAttrsCount =
|
|
sizeof(crlAttrs)/sizeof(crlAttrs[0]);
|
|
|
|
/* copy an object based on it's table */
|
|
CK_RV
|
|
stfk_CopyTokenAttributes(SFTKObject *destObject,SFTKTokenObject *src_to,
|
|
const CK_ATTRIBUTE_TYPE *attrArray, CK_ULONG attrCount)
|
|
{
|
|
SFTKAttribute *attribute;
|
|
SFTKAttribute *newAttribute;
|
|
CK_RV crv = CKR_OK;
|
|
unsigned int i;
|
|
|
|
for (i=0; i < attrCount; i++) {
|
|
if (!sftk_hasAttribute(destObject,attrArray[i])) {
|
|
attribute =sftk_FindAttribute(&src_to->obj, attrArray[i]);
|
|
if (!attribute) {
|
|
continue; /* return CKR_ATTRIBUTE_VALUE_INVALID; */
|
|
}
|
|
/* we need to copy the attribute since each attribute
|
|
* only has one set of link list pointers */
|
|
newAttribute = sftk_NewAttribute( destObject,
|
|
sftk_attr_expand(&attribute->attrib));
|
|
sftk_FreeAttribute(attribute); /* free the old attribute */
|
|
if (!newAttribute) {
|
|
return CKR_HOST_MEMORY;
|
|
}
|
|
sftk_AddAttribute(destObject,newAttribute);
|
|
}
|
|
}
|
|
return crv;
|
|
}
|
|
|
|
CK_RV
|
|
stfk_CopyTokenPrivateKey(SFTKObject *destObject,SFTKTokenObject *src_to)
|
|
{
|
|
CK_RV crv;
|
|
CK_KEY_TYPE key_type;
|
|
SFTKAttribute *attribute;
|
|
|
|
/* copy the common attributes for all keys first */
|
|
crv = stfk_CopyTokenAttributes(destObject, src_to, commonKeyAttrs,
|
|
commonKeyAttrsCount);
|
|
if (crv != CKR_OK) {
|
|
goto fail;
|
|
}
|
|
/* copy the common attributes for all private keys next */
|
|
crv = stfk_CopyTokenAttributes(destObject, src_to, commonPrivKeyAttrs,
|
|
commonKeyAttrsCount);
|
|
if (crv != CKR_OK) {
|
|
goto fail;
|
|
}
|
|
attribute =sftk_FindAttribute(&src_to->obj, CKA_KEY_TYPE);
|
|
PORT_Assert(attribute); /* if it wasn't here, ww should have failed
|
|
* copying the common attributes */
|
|
if (!attribute) {
|
|
/* OK, so CKR_ATTRIBUTE_VALUE_INVALID is the immediate error, but
|
|
* the fact is, the only reason we couldn't get the attribute would
|
|
* be a memory error or database error (an error in the 'device').
|
|
* if we have a database error code, we could return it here */
|
|
crv = CKR_DEVICE_ERROR;
|
|
goto fail;
|
|
}
|
|
key_type = *(CK_KEY_TYPE *)attribute->attrib.pValue;
|
|
sftk_FreeAttribute(attribute);
|
|
|
|
/* finally copy the attributes for various private key types */
|
|
switch (key_type) {
|
|
case CKK_RSA:
|
|
crv = stfk_CopyTokenAttributes(destObject, src_to, rsaPrivKeyAttrs,
|
|
rsaPrivKeyAttrsCount);
|
|
break;
|
|
case CKK_DSA:
|
|
crv = stfk_CopyTokenAttributes(destObject, src_to, dsaPrivKeyAttrs,
|
|
dsaPrivKeyAttrsCount);
|
|
break;
|
|
case CKK_DH:
|
|
crv = stfk_CopyTokenAttributes(destObject, src_to, dhPrivKeyAttrs,
|
|
dhPrivKeyAttrsCount);
|
|
break;
|
|
#ifdef NSS_ENABLE_ECC
|
|
case CKK_EC:
|
|
crv = stfk_CopyTokenAttributes(destObject, src_to, ecPrivKeyAttrs,
|
|
ecPrivKeyAttrsCount);
|
|
break;
|
|
#endif
|
|
default:
|
|
crv = CKR_DEVICE_ERROR; /* shouldn't happen unless we store more types
|
|
* of token keys into our database. */
|
|
}
|
|
fail:
|
|
return crv;
|
|
}
|
|
|
|
CK_RV
|
|
stfk_CopyTokenPublicKey(SFTKObject *destObject,SFTKTokenObject *src_to)
|
|
{
|
|
CK_RV crv;
|
|
CK_KEY_TYPE key_type;
|
|
SFTKAttribute *attribute;
|
|
|
|
/* copy the common attributes for all keys first */
|
|
crv = stfk_CopyTokenAttributes(destObject, src_to, commonKeyAttrs,
|
|
commonKeyAttrsCount);
|
|
if (crv != CKR_OK) {
|
|
goto fail;
|
|
}
|
|
|
|
/* copy the common attributes for all public keys next */
|
|
crv = stfk_CopyTokenAttributes(destObject, src_to, commonPubKeyAttrs,
|
|
commonPubKeyAttrsCount);
|
|
if (crv != CKR_OK) {
|
|
goto fail;
|
|
}
|
|
attribute =sftk_FindAttribute(&src_to->obj, CKA_KEY_TYPE);
|
|
PORT_Assert(attribute); /* if it wasn't here, ww should have failed
|
|
* copying the common attributes */
|
|
if (!attribute) {
|
|
/* OK, so CKR_ATTRIBUTE_VALUE_INVALID is the immediate error, but
|
|
* the fact is, the only reason we couldn't get the attribute would
|
|
* be a memory error or database error (an error in the 'device').
|
|
* if we have a database error code, we could return it here */
|
|
crv = CKR_DEVICE_ERROR;
|
|
goto fail;
|
|
}
|
|
key_type = *(CK_KEY_TYPE *)attribute->attrib.pValue;
|
|
sftk_FreeAttribute(attribute);
|
|
|
|
/* finally copy the attributes for various public key types */
|
|
switch (key_type) {
|
|
case CKK_RSA:
|
|
crv = stfk_CopyTokenAttributes(destObject, src_to, rsaPubKeyAttrs,
|
|
rsaPubKeyAttrsCount);
|
|
break;
|
|
case CKK_DSA:
|
|
crv = stfk_CopyTokenAttributes(destObject, src_to, dsaPubKeyAttrs,
|
|
dsaPubKeyAttrsCount);
|
|
break;
|
|
case CKK_DH:
|
|
crv = stfk_CopyTokenAttributes(destObject, src_to, dhPubKeyAttrs,
|
|
dhPubKeyAttrsCount);
|
|
break;
|
|
#ifdef NSS_ENABLE_ECC
|
|
case CKK_EC:
|
|
crv = stfk_CopyTokenAttributes(destObject, src_to, ecPubKeyAttrs,
|
|
ecPubKeyAttrsCount);
|
|
break;
|
|
#endif
|
|
default:
|
|
crv = CKR_DEVICE_ERROR; /* shouldn't happen unless we store more types
|
|
* of token keys into our database. */
|
|
}
|
|
fail:
|
|
return crv;
|
|
}
|
|
CK_RV
|
|
stfk_CopyTokenSecretKey(SFTKObject *destObject,SFTKTokenObject *src_to)
|
|
{
|
|
CK_RV crv;
|
|
crv = stfk_CopyTokenAttributes(destObject, src_to, commonKeyAttrs,
|
|
commonKeyAttrsCount);
|
|
if (crv != CKR_OK) {
|
|
goto fail;
|
|
}
|
|
crv = stfk_CopyTokenAttributes(destObject, src_to, secretKeyAttrs,
|
|
secretKeyAttrsCount);
|
|
fail:
|
|
return crv;
|
|
}
|
|
|
|
/*
|
|
* Copy a token object. We need to explicitly copy the relevant
|
|
* attributes since token objects don't store those attributes in
|
|
* the token itself.
|
|
*/
|
|
CK_RV
|
|
sftk_CopyTokenObject(SFTKObject *destObject,SFTKObject *srcObject)
|
|
{
|
|
SFTKTokenObject *src_to = sftk_narrowToTokenObject(srcObject);
|
|
CK_RV crv;
|
|
|
|
PORT_Assert(src_to);
|
|
if (src_to == NULL) {
|
|
return CKR_DEVICE_ERROR; /* internal state inconsistant */
|
|
}
|
|
|
|
crv = stfk_CopyTokenAttributes(destObject, src_to, commonAttrs,
|
|
commonAttrsCount);
|
|
if (crv != CKR_OK) {
|
|
goto fail;
|
|
}
|
|
switch (src_to->obj.objclass) {
|
|
case CKO_CERTIFICATE:
|
|
crv = stfk_CopyTokenAttributes(destObject, src_to, certAttrs,
|
|
certAttrsCount);
|
|
break;
|
|
case CKO_NETSCAPE_TRUST:
|
|
crv = stfk_CopyTokenAttributes(destObject, src_to, trustAttrs,
|
|
trustAttrsCount);
|
|
break;
|
|
case CKO_NETSCAPE_SMIME:
|
|
crv = stfk_CopyTokenAttributes(destObject, src_to, smimeAttrs,
|
|
smimeAttrsCount);
|
|
break;
|
|
case CKO_NETSCAPE_CRL:
|
|
crv = stfk_CopyTokenAttributes(destObject, src_to, crlAttrs,
|
|
crlAttrsCount);
|
|
break;
|
|
case CKO_PRIVATE_KEY:
|
|
crv = stfk_CopyTokenPrivateKey(destObject,src_to);
|
|
break;
|
|
case CKO_PUBLIC_KEY:
|
|
crv = stfk_CopyTokenPublicKey(destObject,src_to);
|
|
break;
|
|
case CKO_SECRET_KEY:
|
|
crv = stfk_CopyTokenSecretKey(destObject,src_to);
|
|
break;
|
|
default:
|
|
crv = CKR_DEVICE_ERROR; /* shouldn't happen unless we store more types
|
|
* of token keys into our database. */
|
|
}
|
|
fail:
|
|
return crv;
|
|
}
|
|
|
|
/*
|
|
* copy the attributes from one object to another. Don't overwrite existing
|
|
* attributes. NOTE: This is a pretty expensive operation since it
|
|
* grabs the attribute locks for the src object for a *long* time.
|
|
*/
|
|
CK_RV
|
|
sftk_CopyObject(SFTKObject *destObject,SFTKObject *srcObject)
|
|
{
|
|
SFTKAttribute *attribute;
|
|
SFTKSessionObject *src_so = sftk_narrowToSessionObject(srcObject);
|
|
unsigned int i;
|
|
|
|
if (src_so == NULL) {
|
|
return sftk_CopyTokenObject(destObject,srcObject);
|
|
}
|
|
|
|
PZ_Lock(src_so->attributeLock);
|
|
for(i=0; i < src_so->hashSize; i++) {
|
|
attribute = src_so->head[i];
|
|
do {
|
|
if (attribute) {
|
|
if (!sftk_hasAttribute(destObject,attribute->handle)) {
|
|
/* we need to copy the attribute since each attribute
|
|
* only has one set of link list pointers */
|
|
SFTKAttribute *newAttribute = sftk_NewAttribute(
|
|
destObject,sftk_attr_expand(&attribute->attrib));
|
|
if (newAttribute == NULL) {
|
|
PZ_Unlock(src_so->attributeLock);
|
|
return CKR_HOST_MEMORY;
|
|
}
|
|
sftk_AddAttribute(destObject,newAttribute);
|
|
}
|
|
attribute=attribute->next;
|
|
}
|
|
} while (attribute != NULL);
|
|
}
|
|
PZ_Unlock(src_so->attributeLock);
|
|
|
|
return CKR_OK;
|
|
}
|
|
|
|
/*
|
|
* ******************** Search Utilities *******************************
|
|
*/
|
|
|
|
/* add an object to a search list */
|
|
CK_RV
|
|
AddToList(SFTKObjectListElement **list,SFTKObject *object)
|
|
{
|
|
SFTKObjectListElement *newElem =
|
|
(SFTKObjectListElement *)PORT_Alloc(sizeof(SFTKObjectListElement));
|
|
|
|
if (newElem == NULL) return CKR_HOST_MEMORY;
|
|
|
|
newElem->next = *list;
|
|
newElem->object = object;
|
|
sftk_ReferenceObject(object);
|
|
|
|
*list = newElem;
|
|
return CKR_OK;
|
|
}
|
|
|
|
|
|
/* return true if the object matches the template */
|
|
PRBool
|
|
sftk_objectMatch(SFTKObject *object,CK_ATTRIBUTE_PTR theTemplate,int count)
|
|
{
|
|
int i;
|
|
|
|
for (i=0; i < count; i++) {
|
|
SFTKAttribute *attribute = sftk_FindAttribute(object,theTemplate[i].type);
|
|
if (attribute == NULL) {
|
|
return PR_FALSE;
|
|
}
|
|
if (attribute->attrib.ulValueLen == theTemplate[i].ulValueLen) {
|
|
if (PORT_Memcmp(attribute->attrib.pValue,theTemplate[i].pValue,
|
|
theTemplate[i].ulValueLen) == 0) {
|
|
sftk_FreeAttribute(attribute);
|
|
continue;
|
|
}
|
|
}
|
|
sftk_FreeAttribute(attribute);
|
|
return PR_FALSE;
|
|
}
|
|
return PR_TRUE;
|
|
}
|
|
|
|
/* search through all the objects in the queue and return the template matches
|
|
* in the object list.
|
|
*/
|
|
CK_RV
|
|
sftk_searchObjectList(SFTKSearchResults *search,SFTKObject **head,
|
|
unsigned int size, PZLock *lock, CK_ATTRIBUTE_PTR theTemplate,
|
|
int count, PRBool isLoggedIn)
|
|
{
|
|
unsigned int i;
|
|
SFTKObject *object;
|
|
CK_RV crv = CKR_OK;
|
|
|
|
for(i=0; i < size; i++) {
|
|
/* We need to hold the lock to copy a consistant version of
|
|
* the linked list. */
|
|
PZ_Lock(lock);
|
|
for (object = head[i]; object != NULL; object= object->next) {
|
|
if (sftk_objectMatch(object,theTemplate,count)) {
|
|
/* don't return objects that aren't yet visible */
|
|
if ((!isLoggedIn) && sftk_isTrue(object,CKA_PRIVATE)) continue;
|
|
sftk_addHandle(search,object->handle);
|
|
}
|
|
}
|
|
PZ_Unlock(lock);
|
|
}
|
|
return crv;
|
|
}
|
|
|
|
/*
|
|
* free a single list element. Return the Next object in the list.
|
|
*/
|
|
SFTKObjectListElement *
|
|
sftk_FreeObjectListElement(SFTKObjectListElement *objectList)
|
|
{
|
|
SFTKObjectListElement *ol = objectList->next;
|
|
|
|
sftk_FreeObject(objectList->object);
|
|
PORT_Free(objectList);
|
|
return ol;
|
|
}
|
|
|
|
/* free an entire object list */
|
|
void
|
|
sftk_FreeObjectList(SFTKObjectListElement *objectList)
|
|
{
|
|
SFTKObjectListElement *ol;
|
|
|
|
for (ol= objectList; ol != NULL; ol = sftk_FreeObjectListElement(ol)) {}
|
|
}
|
|
|
|
/*
|
|
* free a search structure
|
|
*/
|
|
void
|
|
sftk_FreeSearch(SFTKSearchResults *search)
|
|
{
|
|
if (search->handles) {
|
|
PORT_Free(search->handles);
|
|
}
|
|
PORT_Free(search);
|
|
}
|
|
|
|
/*
|
|
* ******************** Session Utilities *******************************
|
|
*/
|
|
|
|
/* update the sessions state based in it's flags and wether or not it's
|
|
* logged in */
|
|
void
|
|
sftk_update_state(SFTKSlot *slot,SFTKSession *session)
|
|
{
|
|
if (slot->isLoggedIn) {
|
|
if (slot->ssoLoggedIn) {
|
|
session->info.state = CKS_RW_SO_FUNCTIONS;
|
|
} else if (session->info.flags & CKF_RW_SESSION) {
|
|
session->info.state = CKS_RW_USER_FUNCTIONS;
|
|
} else {
|
|
session->info.state = CKS_RO_USER_FUNCTIONS;
|
|
}
|
|
} else {
|
|
if (session->info.flags & CKF_RW_SESSION) {
|
|
session->info.state = CKS_RW_PUBLIC_SESSION;
|
|
} else {
|
|
session->info.state = CKS_RO_PUBLIC_SESSION;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* update the state of all the sessions on a slot */
|
|
void
|
|
sftk_update_all_states(SFTKSlot *slot)
|
|
{
|
|
unsigned int i;
|
|
SFTKSession *session;
|
|
|
|
for (i=0; i < slot->sessHashSize; i++) {
|
|
PZLock *lock = SFTK_SESSION_LOCK(slot,i);
|
|
PZ_Lock(lock);
|
|
for (session = slot->head[i]; session; session = session->next) {
|
|
sftk_update_state(slot,session);
|
|
}
|
|
PZ_Unlock(lock);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* context are cipher and digest contexts that are associated with a session
|
|
*/
|
|
void
|
|
sftk_FreeContext(SFTKSessionContext *context)
|
|
{
|
|
if (context->cipherInfo) {
|
|
(*context->destroy)(context->cipherInfo,PR_TRUE);
|
|
}
|
|
if (context->hashInfo) {
|
|
(*context->hashdestroy)(context->hashInfo,PR_TRUE);
|
|
}
|
|
if (context->key) {
|
|
sftk_FreeObject(context->key);
|
|
context->key = NULL;
|
|
}
|
|
PORT_Free(context);
|
|
}
|
|
|
|
/*
|
|
* create a new nession. NOTE: The session handle is not set, and the
|
|
* session is not added to the slot's session queue.
|
|
*/
|
|
SFTKSession *
|
|
sftk_NewSession(CK_SLOT_ID slotID, CK_NOTIFY notify, CK_VOID_PTR pApplication,
|
|
CK_FLAGS flags)
|
|
{
|
|
SFTKSession *session;
|
|
SFTKSlot *slot = sftk_SlotFromID(slotID, PR_FALSE);
|
|
|
|
if (slot == NULL) return NULL;
|
|
|
|
session = (SFTKSession*)PORT_Alloc(sizeof(SFTKSession));
|
|
if (session == NULL) return NULL;
|
|
|
|
session->next = session->prev = NULL;
|
|
session->refCount = 1;
|
|
session->enc_context = NULL;
|
|
session->hash_context = NULL;
|
|
session->sign_context = NULL;
|
|
session->search = NULL;
|
|
session->objectIDCount = 1;
|
|
session->objectLock = PZ_NewLock(nssILockObject);
|
|
if (session->objectLock == NULL) {
|
|
PORT_Free(session);
|
|
return NULL;
|
|
}
|
|
session->objects[0] = NULL;
|
|
|
|
session->slot = slot;
|
|
session->notify = notify;
|
|
session->appData = pApplication;
|
|
session->info.flags = flags;
|
|
session->info.slotID = slotID;
|
|
session->info.ulDeviceError = 0;
|
|
sftk_update_state(slot,session);
|
|
return session;
|
|
}
|
|
|
|
|
|
/* free all the data associated with a session. */
|
|
static void
|
|
sftk_DestroySession(SFTKSession *session)
|
|
{
|
|
SFTKObjectList *op,*next;
|
|
PORT_Assert(session->refCount == 0);
|
|
|
|
/* clean out the attributes */
|
|
/* since no one is referencing us, it's safe to walk the chain
|
|
* without a lock */
|
|
for (op = session->objects[0]; op != NULL; op = next) {
|
|
next = op->next;
|
|
/* paranoia */
|
|
op->next = op->prev = NULL;
|
|
sftk_DeleteObject(session,op->parent);
|
|
}
|
|
PZ_DestroyLock(session->objectLock);
|
|
if (session->enc_context) {
|
|
sftk_FreeContext(session->enc_context);
|
|
}
|
|
if (session->hash_context) {
|
|
sftk_FreeContext(session->hash_context);
|
|
}
|
|
if (session->sign_context) {
|
|
sftk_FreeContext(session->sign_context);
|
|
}
|
|
if (session->search) {
|
|
sftk_FreeSearch(session->search);
|
|
}
|
|
PORT_Free(session);
|
|
}
|
|
|
|
|
|
/*
|
|
* look up a session structure from a session handle
|
|
* generate a reference to it.
|
|
*/
|
|
SFTKSession *
|
|
sftk_SessionFromHandle(CK_SESSION_HANDLE handle)
|
|
{
|
|
SFTKSlot *slot = sftk_SlotFromSessionHandle(handle);
|
|
SFTKSession *session;
|
|
PZLock *lock;
|
|
|
|
if (!slot) return NULL;
|
|
lock = SFTK_SESSION_LOCK(slot,handle);
|
|
|
|
PZ_Lock(lock);
|
|
sftkqueue_find(session,handle,slot->head,slot->sessHashSize);
|
|
if (session) session->refCount++;
|
|
PZ_Unlock(lock);
|
|
|
|
return (session);
|
|
}
|
|
|
|
/*
|
|
* release a reference to a session handle
|
|
*/
|
|
void
|
|
sftk_FreeSession(SFTKSession *session)
|
|
{
|
|
PRBool destroy = PR_FALSE;
|
|
SFTKSlot *slot = sftk_SlotFromSession(session);
|
|
PZLock *lock = SFTK_SESSION_LOCK(slot,session->handle);
|
|
|
|
PZ_Lock(lock);
|
|
if (session->refCount == 1) destroy = PR_TRUE;
|
|
session->refCount--;
|
|
PZ_Unlock(lock);
|
|
|
|
if (destroy) sftk_DestroySession(session);
|
|
}
|
|
/*
|
|
* handle Token Object stuff
|
|
*/
|
|
static void
|
|
sftk_XORHash(unsigned char *key, unsigned char *dbkey, int len)
|
|
{
|
|
int i;
|
|
|
|
PORT_Memset(key, 0, 4);
|
|
|
|
for (i=0; i < len-4; i += 4) {
|
|
key[0] ^= dbkey[i];
|
|
key[1] ^= dbkey[i+1];
|
|
key[2] ^= dbkey[i+2];
|
|
key[3] ^= dbkey[i+3];
|
|
}
|
|
}
|
|
|
|
/* Make a token handle for an object and record it so we can find it again */
|
|
CK_OBJECT_HANDLE
|
|
sftk_mkHandle(SFTKSlot *slot, SECItem *dbKey, CK_OBJECT_HANDLE class)
|
|
{
|
|
unsigned char hashBuf[4];
|
|
CK_OBJECT_HANDLE handle;
|
|
SECItem *key;
|
|
|
|
handle = class;
|
|
/* there is only one KRL, use a fixed handle for it */
|
|
if (handle != SFTK_TOKEN_KRL_HANDLE) {
|
|
sftk_XORHash(hashBuf,dbKey->data,dbKey->len);
|
|
handle = (hashBuf[0] << 24) | (hashBuf[1] << 16) |
|
|
(hashBuf[2] << 8) | hashBuf[3];
|
|
handle = SFTK_TOKEN_MAGIC | class |
|
|
(handle & ~(SFTK_TOKEN_TYPE_MASK|SFTK_TOKEN_MASK));
|
|
/* we have a CRL who's handle has randomly matched the reserved KRL
|
|
* handle, increment it */
|
|
if (handle == SFTK_TOKEN_KRL_HANDLE) {
|
|
handle++;
|
|
}
|
|
}
|
|
|
|
sftk_tokenKeyLock(slot);
|
|
while ((key = sftk_lookupTokenKeyByHandle(slot,handle)) != NULL) {
|
|
if (SECITEM_ItemsAreEqual(key,dbKey)) {
|
|
sftk_tokenKeyUnlock(slot);
|
|
return handle;
|
|
}
|
|
handle++;
|
|
}
|
|
sftk_addTokenKeyByHandle(slot,handle,dbKey);
|
|
sftk_tokenKeyUnlock(slot);
|
|
return handle;
|
|
}
|
|
|
|
PRBool
|
|
sftk_poisonHandle(SFTKSlot *slot, SECItem *dbKey, CK_OBJECT_HANDLE class)
|
|
{
|
|
unsigned char hashBuf[4];
|
|
CK_OBJECT_HANDLE handle;
|
|
SECItem *key;
|
|
|
|
handle = class;
|
|
/* there is only one KRL, use a fixed handle for it */
|
|
if (handle != SFTK_TOKEN_KRL_HANDLE) {
|
|
sftk_XORHash(hashBuf,dbKey->data,dbKey->len);
|
|
handle = (hashBuf[0] << 24) | (hashBuf[1] << 16) |
|
|
(hashBuf[2] << 8) | hashBuf[3];
|
|
handle = SFTK_TOKEN_MAGIC | class |
|
|
(handle & ~(SFTK_TOKEN_TYPE_MASK|SFTK_TOKEN_MASK));
|
|
/* we have a CRL who's handle has randomly matched the reserved KRL
|
|
* handle, increment it */
|
|
if (handle == SFTK_TOKEN_KRL_HANDLE) {
|
|
handle++;
|
|
}
|
|
}
|
|
sftk_tokenKeyLock(slot);
|
|
while ((key = sftk_lookupTokenKeyByHandle(slot,handle)) != NULL) {
|
|
if (SECITEM_ItemsAreEqual(key,dbKey)) {
|
|
key->data[0] ^= 0x80;
|
|
sftk_tokenKeyUnlock(slot);
|
|
return PR_TRUE;
|
|
}
|
|
handle++;
|
|
}
|
|
sftk_tokenKeyUnlock(slot);
|
|
return PR_FALSE;
|
|
}
|
|
|
|
void
|
|
sftk_addHandle(SFTKSearchResults *search, CK_OBJECT_HANDLE handle)
|
|
{
|
|
if (search->handles == NULL) {
|
|
return;
|
|
}
|
|
if (search->size >= search->array_size) {
|
|
search->array_size += NSC_SEARCH_BLOCK_SIZE;
|
|
search->handles = (CK_OBJECT_HANDLE *) PORT_Realloc(search->handles,
|
|
sizeof(CK_OBJECT_HANDLE)* search->array_size);
|
|
if (search->handles == NULL) {
|
|
return;
|
|
}
|
|
}
|
|
search->handles[search->size] = handle;
|
|
search->size++;
|
|
}
|
|
|
|
static const CK_OBJECT_HANDLE sftk_classArray[] = {
|
|
0, CKO_PRIVATE_KEY, CKO_PUBLIC_KEY, CKO_SECRET_KEY,
|
|
CKO_NETSCAPE_TRUST, CKO_NETSCAPE_CRL, CKO_NETSCAPE_SMIME,
|
|
CKO_CERTIFICATE };
|
|
|
|
#define handleToClass(handle) \
|
|
sftk_classArray[((handle & SFTK_TOKEN_TYPE_MASK))>>28]
|
|
|
|
SFTKObject *
|
|
sftk_NewTokenObject(SFTKSlot *slot, SECItem *dbKey, CK_OBJECT_HANDLE handle)
|
|
{
|
|
SFTKObject *object = NULL;
|
|
SFTKTokenObject *tokObject = NULL;
|
|
PRBool hasLocks = PR_FALSE;
|
|
SECStatus rv;
|
|
|
|
object = sftk_GetObjectFromList(&hasLocks, PR_FALSE, &tokenObjectList, 0,
|
|
PR_FALSE);
|
|
if (object == NULL) {
|
|
return NULL;
|
|
}
|
|
tokObject = (SFTKTokenObject *) object;
|
|
|
|
object->objclass = handleToClass(handle);
|
|
object->handle = handle;
|
|
object->slot = slot;
|
|
object->objectInfo = NULL;
|
|
object->infoFree = NULL;
|
|
if (dbKey == NULL) {
|
|
sftk_tokenKeyLock(slot);
|
|
dbKey = sftk_lookupTokenKeyByHandle(slot,handle);
|
|
if (dbKey == NULL) {
|
|
sftk_tokenKeyUnlock(slot);
|
|
goto loser;
|
|
}
|
|
rv = SECITEM_CopyItem(NULL,&tokObject->dbKey,dbKey);
|
|
sftk_tokenKeyUnlock(slot);
|
|
} else {
|
|
rv = SECITEM_CopyItem(NULL,&tokObject->dbKey,dbKey);
|
|
}
|
|
if (rv != SECSuccess) {
|
|
goto loser;
|
|
}
|
|
if (!hasLocks) {
|
|
object->refLock = PZ_NewLock(nssILockRefLock);
|
|
}
|
|
if (object->refLock == NULL) {
|
|
goto loser;
|
|
}
|
|
object->refCount = 1;
|
|
|
|
return object;
|
|
loser:
|
|
if (object) {
|
|
(void) sftk_DestroyObject(object);
|
|
}
|
|
return NULL;
|
|
|
|
}
|
|
|
|
PRBool
|
|
sftk_tokenMatch(SFTKSlot *slot, SECItem *dbKey, CK_OBJECT_HANDLE class,
|
|
CK_ATTRIBUTE_PTR theTemplate,int count)
|
|
{
|
|
SFTKObject *object;
|
|
PRBool ret;
|
|
|
|
object = sftk_NewTokenObject(slot,dbKey,SFTK_TOKEN_MASK|class);
|
|
if (object == NULL) {
|
|
return PR_FALSE;
|
|
}
|
|
|
|
ret = sftk_objectMatch(object,theTemplate,count);
|
|
sftk_FreeObject(object);
|
|
return ret;
|
|
}
|
|
|
|
SFTKTokenObject *
|
|
sftk_convertSessionToToken(SFTKObject *obj)
|
|
{
|
|
SECItem *key;
|
|
SFTKSessionObject *so = (SFTKSessionObject *)obj;
|
|
SFTKTokenObject *to = sftk_narrowToTokenObject(obj);
|
|
SECStatus rv;
|
|
|
|
sftk_DestroySessionObjectData(so);
|
|
PZ_DestroyLock(so->attributeLock);
|
|
if (to == NULL) {
|
|
return NULL;
|
|
}
|
|
sftk_tokenKeyLock(so->obj.slot);
|
|
key = sftk_lookupTokenKeyByHandle(so->obj.slot,so->obj.handle);
|
|
if (key == NULL) {
|
|
sftk_tokenKeyUnlock(so->obj.slot);
|
|
return NULL;
|
|
}
|
|
rv = SECITEM_CopyItem(NULL,&to->dbKey,key);
|
|
sftk_tokenKeyUnlock(so->obj.slot);
|
|
if (rv == SECFailure) {
|
|
return NULL;
|
|
}
|
|
|
|
return to;
|
|
|
|
}
|
|
|
|
SFTKSessionObject *
|
|
sftk_narrowToSessionObject(SFTKObject *obj)
|
|
{
|
|
return !sftk_isToken(obj->handle) ? (SFTKSessionObject *)obj : NULL;
|
|
}
|
|
|
|
SFTKTokenObject *
|
|
sftk_narrowToTokenObject(SFTKObject *obj)
|
|
{
|
|
return sftk_isToken(obj->handle) ? (SFTKTokenObject *)obj : NULL;
|
|
}
|
|
|