mirror of
https://github.com/rn10950/RetroZilla.git
synced 2024-11-13 11:10:13 +01:00
30d33aa8e8
9934c8faef29, 3c3b381c4865, 5a67f6beee9a, 1b1eb6d77728, a8b668fd72f7, bug962760, bug743700, bug857304, bug972653, bug972450, bug971358, bug903885, bug977073, bug976111, bug949939, bug947653, bug947572, bug903885, bug979106, bug966596, bug979004, bug979752, bug980848, bug938369, bug981170, bug668130, bug974693, bug975056, bug979132, bug370717, bug979070, bug985070, bug900067, bug977673, bug519255, bug989558, bug557299, bug987263, bug369802, a751a5146718, bug992343, bug952572, bug979703, bug994883, bug994869, bug993489, bug984608, bug977869, bug667371, bug672828, bug793347, bug977869
1791 lines
49 KiB
C
1791 lines
49 KiB
C
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
/*
|
|
* Internal PKCS #11 functions. Should only be called by pkcs11.c
|
|
*/
|
|
#include "pkcs11.h"
|
|
#include "lgdb.h"
|
|
|
|
#include "pcertt.h"
|
|
#include "lowkeyi.h"
|
|
#include "pcert.h"
|
|
#include "blapi.h"
|
|
#include "secerr.h"
|
|
#include "secasn1.h"
|
|
|
|
/*
|
|
* Cache the object we are working on during Set's and Get's
|
|
*/
|
|
typedef struct LGObjectCacheStr {
|
|
CK_OBJECT_CLASS objclass;
|
|
CK_OBJECT_HANDLE handle;
|
|
SDB *sdb;
|
|
void *objectInfo;
|
|
LGFreeFunc infoFree;
|
|
SECItem dbKey;
|
|
} LGObjectCache;
|
|
|
|
static const CK_OBJECT_HANDLE lg_classArray[] = {
|
|
0, CKO_PRIVATE_KEY, CKO_PUBLIC_KEY, CKO_SECRET_KEY,
|
|
CKO_NSS_TRUST, CKO_NSS_CRL, CKO_NSS_SMIME,
|
|
CKO_CERTIFICATE };
|
|
|
|
#define handleToClass(handle) \
|
|
lg_classArray[((handle & LG_TOKEN_TYPE_MASK))>>LG_TOKEN_TYPE_SHIFT]
|
|
|
|
|
|
static void lg_DestroyObjectCache(LGObjectCache *obj);
|
|
|
|
static LGObjectCache *
|
|
lg_NewObjectCache(SDB *sdb, const SECItem *dbKey, CK_OBJECT_HANDLE handle)
|
|
{
|
|
LGObjectCache *obj = NULL;
|
|
SECStatus rv;
|
|
|
|
obj = PORT_New(LGObjectCache);
|
|
if (obj == NULL) {
|
|
return NULL;
|
|
}
|
|
|
|
obj->objclass = handleToClass(handle);
|
|
obj->handle = handle;
|
|
obj->sdb = sdb;
|
|
obj->objectInfo = NULL;
|
|
obj->infoFree = NULL;
|
|
obj->dbKey.data = NULL;
|
|
obj->dbKey.len = 0;
|
|
lg_DBLock(sdb);
|
|
if (dbKey == NULL) {
|
|
dbKey = lg_lookupTokenKeyByHandle(sdb,handle);
|
|
}
|
|
if (dbKey == NULL) {
|
|
lg_DBUnlock(sdb);
|
|
goto loser;
|
|
}
|
|
rv = SECITEM_CopyItem(NULL,&obj->dbKey,dbKey);
|
|
lg_DBUnlock(sdb);
|
|
if (rv != SECSuccess) {
|
|
goto loser;
|
|
}
|
|
|
|
return obj;
|
|
loser:
|
|
if (obj) {
|
|
(void) lg_DestroyObjectCache(obj);
|
|
}
|
|
return NULL;
|
|
|
|
}
|
|
|
|
/*
|
|
* free all the data associated with an object. Object reference count must
|
|
* be 'zero'.
|
|
*/
|
|
static void
|
|
lg_DestroyObjectCache(LGObjectCache *obj)
|
|
{
|
|
if (obj->dbKey.data) {
|
|
PORT_Free(obj->dbKey.data);
|
|
obj->dbKey.data = NULL;
|
|
}
|
|
if (obj->objectInfo) {
|
|
(*obj->infoFree)(obj->objectInfo);
|
|
obj->objectInfo = NULL;
|
|
obj->infoFree = NULL;
|
|
}
|
|
PORT_Free(obj);
|
|
}
|
|
/*
|
|
* ******************** Attribute Utilities *******************************
|
|
*/
|
|
|
|
static CK_RV
|
|
lg_ULongAttribute(CK_ATTRIBUTE *attr, CK_ATTRIBUTE_TYPE type, CK_ULONG value)
|
|
{
|
|
unsigned char *data;
|
|
int i;
|
|
|
|
if (attr->pValue == NULL) {
|
|
attr->ulValueLen = 4;
|
|
return CKR_OK;
|
|
}
|
|
if (attr->ulValueLen < 4) {
|
|
attr->ulValueLen = (CK_ULONG) -1;
|
|
return CKR_BUFFER_TOO_SMALL;
|
|
}
|
|
|
|
data = (unsigned char *)attr->pValue;
|
|
for (i=0; i < 4; i++) {
|
|
data[i] = (value >> ((3-i)*8)) & 0xff;
|
|
}
|
|
attr->ulValueLen = 4;
|
|
return CKR_OK;
|
|
}
|
|
|
|
static CK_RV
|
|
lg_CopyAttribute(CK_ATTRIBUTE *attr, CK_ATTRIBUTE_TYPE type,
|
|
CK_VOID_PTR value, CK_ULONG len)
|
|
{
|
|
|
|
if (attr->pValue == NULL) {
|
|
attr->ulValueLen = len;
|
|
return CKR_OK;
|
|
}
|
|
if (attr->ulValueLen < len) {
|
|
attr->ulValueLen = (CK_ULONG) -1;
|
|
return CKR_BUFFER_TOO_SMALL;
|
|
}
|
|
PORT_Memcpy(attr->pValue,value,len);
|
|
attr->ulValueLen = len;
|
|
return CKR_OK;
|
|
}
|
|
|
|
static CK_RV
|
|
lg_CopyAttributeSigned(CK_ATTRIBUTE *attribute, CK_ATTRIBUTE_TYPE type,
|
|
void *value, CK_ULONG len)
|
|
{
|
|
unsigned char * dval = (unsigned char *)value;
|
|
if (*dval == 0) {
|
|
dval++;
|
|
len--;
|
|
}
|
|
return lg_CopyAttribute(attribute,type,dval,len);
|
|
}
|
|
|
|
static CK_RV
|
|
lg_CopyPrivAttribute(CK_ATTRIBUTE *attribute, CK_ATTRIBUTE_TYPE type,
|
|
void *value, CK_ULONG len, SDB *sdbpw)
|
|
{
|
|
SECItem plainText, *cipherText = NULL;
|
|
CK_RV crv = CKR_USER_NOT_LOGGED_IN;
|
|
SECStatus rv;
|
|
|
|
plainText.data = value;
|
|
plainText.len = len;
|
|
rv = lg_util_encrypt(NULL, sdbpw, &plainText, &cipherText);
|
|
if (rv != SECSuccess) {
|
|
goto loser;
|
|
}
|
|
crv = lg_CopyAttribute(attribute,type,cipherText->data,cipherText->len);
|
|
loser:
|
|
if (cipherText) {
|
|
SECITEM_FreeItem(cipherText,PR_TRUE);
|
|
}
|
|
return crv;
|
|
}
|
|
|
|
static CK_RV
|
|
lg_CopyPrivAttrSigned(CK_ATTRIBUTE *attribute, CK_ATTRIBUTE_TYPE type,
|
|
void *value, CK_ULONG len, SDB *sdbpw)
|
|
{
|
|
unsigned char * dval = (unsigned char *)value;
|
|
|
|
if (*dval == 0) {
|
|
dval++;
|
|
len--;
|
|
}
|
|
return lg_CopyPrivAttribute(attribute,type,dval,len,sdbpw);
|
|
}
|
|
|
|
static CK_RV
|
|
lg_invalidAttribute(CK_ATTRIBUTE *attr)
|
|
{
|
|
attr->ulValueLen = (CK_ULONG) -1;
|
|
return CKR_ATTRIBUTE_TYPE_INVALID;
|
|
}
|
|
|
|
|
|
#define LG_DEF_ATTRIBUTE(value,len) \
|
|
{ 0, value, len }
|
|
|
|
#define LG_CLONE_ATTR(attribute, type, staticAttr) \
|
|
lg_CopyAttribute(attribute, type, staticAttr.pValue, staticAttr.ulValueLen)
|
|
|
|
CK_BBOOL lg_staticTrueValue = CK_TRUE;
|
|
CK_BBOOL lg_staticFalseValue = CK_FALSE;
|
|
static const CK_ATTRIBUTE lg_StaticTrueAttr =
|
|
LG_DEF_ATTRIBUTE(&lg_staticTrueValue,sizeof(lg_staticTrueValue));
|
|
static const CK_ATTRIBUTE lg_StaticFalseAttr =
|
|
LG_DEF_ATTRIBUTE(&lg_staticFalseValue,sizeof(lg_staticFalseValue));
|
|
static const CK_ATTRIBUTE lg_StaticNullAttr = LG_DEF_ATTRIBUTE(NULL,0);
|
|
char lg_StaticOneValue = 1;
|
|
static const CK_ATTRIBUTE lg_StaticOneAttr =
|
|
LG_DEF_ATTRIBUTE(&lg_StaticOneValue,sizeof(lg_StaticOneValue));
|
|
|
|
/*
|
|
* helper functions which get the database and call the underlying
|
|
* low level database function.
|
|
*/
|
|
static char *
|
|
lg_FindKeyNicknameByPublicKey(SDB *sdb, SECItem *dbKey)
|
|
{
|
|
NSSLOWKEYDBHandle *keyHandle;
|
|
char * label;
|
|
|
|
keyHandle = lg_getKeyDB(sdb);
|
|
if (!keyHandle) {
|
|
return NULL;
|
|
}
|
|
|
|
label = nsslowkey_FindKeyNicknameByPublicKey(keyHandle, dbKey,
|
|
sdb);
|
|
return label;
|
|
}
|
|
|
|
|
|
NSSLOWKEYPrivateKey *
|
|
lg_FindKeyByPublicKey(SDB *sdb, SECItem *dbKey)
|
|
{
|
|
NSSLOWKEYPrivateKey *privKey;
|
|
NSSLOWKEYDBHandle *keyHandle;
|
|
|
|
keyHandle = lg_getKeyDB(sdb);
|
|
if (keyHandle == NULL) {
|
|
return NULL;
|
|
}
|
|
privKey = nsslowkey_FindKeyByPublicKey(keyHandle, dbKey, sdb);
|
|
if (privKey == NULL) {
|
|
return NULL;
|
|
}
|
|
return privKey;
|
|
}
|
|
|
|
static certDBEntrySMime *
|
|
lg_getSMime(LGObjectCache *obj)
|
|
{
|
|
certDBEntrySMime *entry;
|
|
NSSLOWCERTCertDBHandle *certHandle;
|
|
|
|
if (obj->objclass != CKO_NSS_SMIME) {
|
|
return NULL;
|
|
}
|
|
if (obj->objectInfo) {
|
|
return (certDBEntrySMime *)obj->objectInfo;
|
|
}
|
|
|
|
certHandle = lg_getCertDB(obj->sdb);
|
|
if (!certHandle) {
|
|
return NULL;
|
|
}
|
|
entry = nsslowcert_ReadDBSMimeEntry(certHandle, (char *)obj->dbKey.data);
|
|
obj->objectInfo = (void *)entry;
|
|
obj->infoFree = (LGFreeFunc) nsslowcert_DestroyDBEntry;
|
|
return entry;
|
|
}
|
|
|
|
static certDBEntryRevocation *
|
|
lg_getCrl(LGObjectCache *obj)
|
|
{
|
|
certDBEntryRevocation *crl;
|
|
PRBool isKrl;
|
|
NSSLOWCERTCertDBHandle *certHandle;
|
|
|
|
if (obj->objclass != CKO_NSS_CRL) {
|
|
return NULL;
|
|
}
|
|
if (obj->objectInfo) {
|
|
return (certDBEntryRevocation *)obj->objectInfo;
|
|
}
|
|
|
|
isKrl = (PRBool) (obj->handle == LG_TOKEN_KRL_HANDLE);
|
|
certHandle = lg_getCertDB(obj->sdb);
|
|
if (!certHandle) {
|
|
return NULL;
|
|
}
|
|
|
|
crl = nsslowcert_FindCrlByKey(certHandle, &obj->dbKey, isKrl);
|
|
obj->objectInfo = (void *)crl;
|
|
obj->infoFree = (LGFreeFunc) nsslowcert_DestroyDBEntry;
|
|
return crl;
|
|
}
|
|
|
|
static NSSLOWCERTCertificate *
|
|
lg_getCert(LGObjectCache *obj, NSSLOWCERTCertDBHandle *certHandle)
|
|
{
|
|
NSSLOWCERTCertificate *cert;
|
|
CK_OBJECT_CLASS objClass = obj->objclass;
|
|
|
|
if ((objClass != CKO_CERTIFICATE) && (objClass != CKO_NSS_TRUST)) {
|
|
return NULL;
|
|
}
|
|
if (objClass == CKO_CERTIFICATE && obj->objectInfo) {
|
|
return (NSSLOWCERTCertificate *)obj->objectInfo;
|
|
}
|
|
cert = nsslowcert_FindCertByKey(certHandle, &obj->dbKey);
|
|
if (objClass == CKO_CERTIFICATE) {
|
|
obj->objectInfo = (void *)cert;
|
|
obj->infoFree = (LGFreeFunc) nsslowcert_DestroyCertificate ;
|
|
}
|
|
return cert;
|
|
}
|
|
|
|
static NSSLOWCERTTrust *
|
|
lg_getTrust(LGObjectCache *obj, NSSLOWCERTCertDBHandle *certHandle)
|
|
{
|
|
NSSLOWCERTTrust *trust;
|
|
|
|
if (obj->objclass != CKO_NSS_TRUST) {
|
|
return NULL;
|
|
}
|
|
if (obj->objectInfo) {
|
|
return (NSSLOWCERTTrust *)obj->objectInfo;
|
|
}
|
|
trust = nsslowcert_FindTrustByKey(certHandle, &obj->dbKey);
|
|
obj->objectInfo = (void *)trust;
|
|
obj->infoFree = (LGFreeFunc) nsslowcert_DestroyTrust ;
|
|
return trust;
|
|
}
|
|
|
|
static NSSLOWKEYPublicKey *
|
|
lg_GetPublicKey(LGObjectCache *obj)
|
|
{
|
|
NSSLOWKEYPublicKey *pubKey;
|
|
NSSLOWKEYPrivateKey *privKey;
|
|
|
|
if (obj->objclass != CKO_PUBLIC_KEY) {
|
|
return NULL;
|
|
}
|
|
if (obj->objectInfo) {
|
|
return (NSSLOWKEYPublicKey *)obj->objectInfo;
|
|
}
|
|
privKey = lg_FindKeyByPublicKey(obj->sdb, &obj->dbKey);
|
|
if (privKey == NULL) {
|
|
return NULL;
|
|
}
|
|
pubKey = lg_nsslowkey_ConvertToPublicKey(privKey);
|
|
lg_nsslowkey_DestroyPrivateKey(privKey);
|
|
obj->objectInfo = (void *) pubKey;
|
|
obj->infoFree = (LGFreeFunc) lg_nsslowkey_DestroyPublicKey ;
|
|
return pubKey;
|
|
}
|
|
|
|
/*
|
|
* we need two versions of lg_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 sdb (where we don't already have a key handle.
|
|
* This version does the former.
|
|
*/
|
|
static NSSLOWKEYPrivateKey *
|
|
lg_GetPrivateKeyWithDB(LGObjectCache *obj, NSSLOWKEYDBHandle *keyHandle)
|
|
{
|
|
NSSLOWKEYPrivateKey *privKey;
|
|
|
|
if ((obj->objclass != CKO_PRIVATE_KEY) &&
|
|
(obj->objclass != CKO_SECRET_KEY)) {
|
|
return NULL;
|
|
}
|
|
if (obj->objectInfo) {
|
|
return (NSSLOWKEYPrivateKey *)obj->objectInfo;
|
|
}
|
|
privKey = nsslowkey_FindKeyByPublicKey(keyHandle, &obj->dbKey, obj->sdb);
|
|
if (privKey == NULL) {
|
|
return NULL;
|
|
}
|
|
obj->objectInfo = (void *) privKey;
|
|
obj->infoFree = (LGFreeFunc) lg_nsslowkey_DestroyPrivateKey ;
|
|
return privKey;
|
|
}
|
|
|
|
/* this version does the latter */
|
|
static NSSLOWKEYPrivateKey *
|
|
lg_GetPrivateKey(LGObjectCache *obj)
|
|
{
|
|
NSSLOWKEYDBHandle *keyHandle;
|
|
NSSLOWKEYPrivateKey *privKey;
|
|
|
|
keyHandle = lg_getKeyDB(obj->sdb);
|
|
if (!keyHandle) {
|
|
return NULL;
|
|
}
|
|
privKey = lg_GetPrivateKeyWithDB(obj, keyHandle);
|
|
return privKey;
|
|
}
|
|
|
|
/* lg_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 *
|
|
lg_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;
|
|
#ifndef NSS_DISABLE_ECC
|
|
case NSSLOWKEYECKey:
|
|
pubItem = &pubKey->u.ec.publicValue;
|
|
break;
|
|
#endif /* NSS_DISABLE_ECC */
|
|
default:
|
|
break;
|
|
}
|
|
return pubItem;
|
|
}
|
|
|
|
static const SEC_ASN1Template lg_SerialTemplate[] = {
|
|
{ SEC_ASN1_INTEGER, offsetof(NSSLOWCERTCertificate,serialNumber) },
|
|
{ 0 }
|
|
};
|
|
|
|
static CK_RV
|
|
lg_FindRSAPublicKeyAttribute(NSSLOWKEYPublicKey *key, CK_ATTRIBUTE_TYPE type,
|
|
CK_ATTRIBUTE *attribute)
|
|
{
|
|
unsigned char hash[SHA1_LENGTH];
|
|
CK_KEY_TYPE keyType = CKK_RSA;
|
|
|
|
switch (type) {
|
|
case CKA_KEY_TYPE:
|
|
return lg_ULongAttribute(attribute, type, keyType);
|
|
case CKA_ID:
|
|
SHA1_HashBuf(hash,key->u.rsa.modulus.data,key->u.rsa.modulus.len);
|
|
return lg_CopyAttribute(attribute,type,hash,SHA1_LENGTH);
|
|
case CKA_DERIVE:
|
|
return LG_CLONE_ATTR(attribute,type,lg_StaticFalseAttr);
|
|
case CKA_ENCRYPT:
|
|
case CKA_VERIFY:
|
|
case CKA_VERIFY_RECOVER:
|
|
case CKA_WRAP:
|
|
return LG_CLONE_ATTR(attribute,type,lg_StaticTrueAttr);
|
|
case CKA_MODULUS:
|
|
return lg_CopyAttributeSigned(attribute,type,key->u.rsa.modulus.data,
|
|
key->u.rsa.modulus.len);
|
|
case CKA_PUBLIC_EXPONENT:
|
|
return lg_CopyAttributeSigned(attribute, type,
|
|
key->u.rsa.publicExponent.data,
|
|
key->u.rsa.publicExponent.len);
|
|
default:
|
|
break;
|
|
}
|
|
return lg_invalidAttribute(attribute);
|
|
}
|
|
|
|
static CK_RV
|
|
lg_FindDSAPublicKeyAttribute(NSSLOWKEYPublicKey *key, CK_ATTRIBUTE_TYPE type,
|
|
CK_ATTRIBUTE *attribute)
|
|
{
|
|
unsigned char hash[SHA1_LENGTH];
|
|
CK_KEY_TYPE keyType = CKK_DSA;
|
|
|
|
switch (type) {
|
|
case CKA_KEY_TYPE:
|
|
return lg_ULongAttribute(attribute, type, keyType);
|
|
case CKA_ID:
|
|
SHA1_HashBuf(hash,key->u.dsa.publicValue.data,
|
|
key->u.dsa.publicValue.len);
|
|
return lg_CopyAttribute(attribute,type,hash,SHA1_LENGTH);
|
|
case CKA_DERIVE:
|
|
case CKA_ENCRYPT:
|
|
case CKA_VERIFY_RECOVER:
|
|
case CKA_WRAP:
|
|
return LG_CLONE_ATTR(attribute,type,lg_StaticFalseAttr);
|
|
case CKA_VERIFY:
|
|
return LG_CLONE_ATTR(attribute,type,lg_StaticTrueAttr);
|
|
case CKA_VALUE:
|
|
return lg_CopyAttributeSigned(attribute,type,
|
|
key->u.dsa.publicValue.data,
|
|
key->u.dsa.publicValue.len);
|
|
case CKA_PRIME:
|
|
return lg_CopyAttributeSigned(attribute,type,
|
|
key->u.dsa.params.prime.data,
|
|
key->u.dsa.params.prime.len);
|
|
case CKA_SUBPRIME:
|
|
return lg_CopyAttributeSigned(attribute,type,
|
|
key->u.dsa.params.subPrime.data,
|
|
key->u.dsa.params.subPrime.len);
|
|
case CKA_BASE:
|
|
return lg_CopyAttributeSigned(attribute,type,
|
|
key->u.dsa.params.base.data,
|
|
key->u.dsa.params.base.len);
|
|
default:
|
|
break;
|
|
}
|
|
return lg_invalidAttribute(attribute);
|
|
}
|
|
|
|
static CK_RV
|
|
lg_FindDHPublicKeyAttribute(NSSLOWKEYPublicKey *key, CK_ATTRIBUTE_TYPE type,
|
|
CK_ATTRIBUTE *attribute)
|
|
{
|
|
unsigned char hash[SHA1_LENGTH];
|
|
CK_KEY_TYPE keyType = CKK_DH;
|
|
|
|
switch (type) {
|
|
case CKA_KEY_TYPE:
|
|
return lg_ULongAttribute(attribute, type, keyType);
|
|
case CKA_ID:
|
|
SHA1_HashBuf(hash,key->u.dh.publicValue.data,key->u.dh.publicValue.len);
|
|
return lg_CopyAttribute(attribute,type,hash,SHA1_LENGTH);
|
|
case CKA_DERIVE:
|
|
return LG_CLONE_ATTR(attribute,type,lg_StaticTrueAttr);
|
|
case CKA_ENCRYPT:
|
|
case CKA_VERIFY:
|
|
case CKA_VERIFY_RECOVER:
|
|
case CKA_WRAP:
|
|
return LG_CLONE_ATTR(attribute,type,lg_StaticFalseAttr);
|
|
case CKA_VALUE:
|
|
return lg_CopyAttributeSigned(attribute,type,
|
|
key->u.dh.publicValue.data,
|
|
key->u.dh.publicValue.len);
|
|
case CKA_PRIME:
|
|
return lg_CopyAttributeSigned(attribute,type,key->u.dh.prime.data,
|
|
key->u.dh.prime.len);
|
|
case CKA_BASE:
|
|
return lg_CopyAttributeSigned(attribute,type,key->u.dh.base.data,
|
|
key->u.dh.base.len);
|
|
default:
|
|
break;
|
|
}
|
|
return lg_invalidAttribute(attribute);
|
|
}
|
|
|
|
#ifndef NSS_DISABLE_ECC
|
|
static CK_RV
|
|
lg_FindECPublicKeyAttribute(NSSLOWKEYPublicKey *key, CK_ATTRIBUTE_TYPE type,
|
|
CK_ATTRIBUTE *attribute)
|
|
{
|
|
unsigned char hash[SHA1_LENGTH];
|
|
CK_KEY_TYPE keyType = CKK_EC;
|
|
|
|
switch (type) {
|
|
case CKA_KEY_TYPE:
|
|
return lg_ULongAttribute(attribute, type, keyType);
|
|
case CKA_ID:
|
|
SHA1_HashBuf(hash, key->u.ec.publicValue.data,
|
|
key->u.ec.publicValue.len);
|
|
return lg_CopyAttribute(attribute,type,hash,SHA1_LENGTH);
|
|
case CKA_DERIVE:
|
|
case CKA_VERIFY:
|
|
return LG_CLONE_ATTR(attribute,type,lg_StaticTrueAttr);
|
|
case CKA_ENCRYPT:
|
|
case CKA_VERIFY_RECOVER:
|
|
case CKA_WRAP:
|
|
return LG_CLONE_ATTR(attribute,type,lg_StaticFalseAttr);
|
|
case CKA_EC_PARAMS:
|
|
return lg_CopyAttributeSigned(attribute,type,
|
|
key->u.ec.ecParams.DEREncoding.data,
|
|
key->u.ec.ecParams.DEREncoding.len);
|
|
case CKA_EC_POINT:
|
|
if (getenv("NSS_USE_DECODED_CKA_EC_POINT")) {
|
|
return lg_CopyAttributeSigned(attribute, type,
|
|
key->u.ec.publicValue.data,
|
|
key->u.ec.publicValue.len);
|
|
} else {
|
|
SECItem *pubValue = SEC_ASN1EncodeItem(NULL, NULL,
|
|
&(key->u.ec.publicValue),
|
|
SEC_ASN1_GET(SEC_OctetStringTemplate));
|
|
CK_RV crv;
|
|
if (!pubValue) {
|
|
return CKR_HOST_MEMORY;
|
|
}
|
|
crv = lg_CopyAttributeSigned(attribute, type,
|
|
pubValue->data,
|
|
pubValue->len);
|
|
SECITEM_FreeItem(pubValue, PR_TRUE);
|
|
return crv;
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
return lg_invalidAttribute(attribute);
|
|
}
|
|
#endif /* NSS_DISABLE_ECC */
|
|
|
|
|
|
static CK_RV
|
|
lg_FindPublicKeyAttribute(LGObjectCache *obj, CK_ATTRIBUTE_TYPE type,
|
|
CK_ATTRIBUTE *attribute)
|
|
{
|
|
NSSLOWKEYPublicKey *key;
|
|
CK_RV crv;
|
|
char *label;
|
|
|
|
switch (type) {
|
|
case CKA_PRIVATE:
|
|
case CKA_SENSITIVE:
|
|
case CKA_ALWAYS_SENSITIVE:
|
|
case CKA_NEVER_EXTRACTABLE:
|
|
return LG_CLONE_ATTR(attribute,type,lg_StaticFalseAttr);
|
|
case CKA_MODIFIABLE:
|
|
case CKA_EXTRACTABLE:
|
|
return LG_CLONE_ATTR(attribute,type,lg_StaticTrueAttr);
|
|
case CKA_SUBJECT:
|
|
return LG_CLONE_ATTR(attribute,type,lg_StaticNullAttr);
|
|
case CKA_START_DATE:
|
|
case CKA_END_DATE:
|
|
return LG_CLONE_ATTR(attribute,type,lg_StaticNullAttr);
|
|
case CKA_LABEL:
|
|
label = lg_FindKeyNicknameByPublicKey(obj->sdb, &obj->dbKey);
|
|
if (label == NULL) {
|
|
return LG_CLONE_ATTR(attribute,type,lg_StaticNullAttr);
|
|
}
|
|
crv = lg_CopyAttribute(attribute,type,label,PORT_Strlen(label));
|
|
PORT_Free(label);
|
|
return crv;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
key = lg_GetPublicKey(obj);
|
|
if (key == NULL) {
|
|
if (type == CKA_ID) {
|
|
return LG_CLONE_ATTR(attribute,type,lg_StaticNullAttr);
|
|
}
|
|
return CKR_OBJECT_HANDLE_INVALID;
|
|
}
|
|
|
|
switch (key->keyType) {
|
|
case NSSLOWKEYRSAKey:
|
|
return lg_FindRSAPublicKeyAttribute(key,type,attribute);
|
|
case NSSLOWKEYDSAKey:
|
|
return lg_FindDSAPublicKeyAttribute(key,type,attribute);
|
|
case NSSLOWKEYDHKey:
|
|
return lg_FindDHPublicKeyAttribute(key,type,attribute);
|
|
#ifndef NSS_DISABLE_ECC
|
|
case NSSLOWKEYECKey:
|
|
return lg_FindECPublicKeyAttribute(key,type,attribute);
|
|
#endif /* NSS_DISABLE_ECC */
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return lg_invalidAttribute(attribute);
|
|
}
|
|
|
|
static CK_RV
|
|
lg_FindSecretKeyAttribute(LGObjectCache *obj, CK_ATTRIBUTE_TYPE type,
|
|
CK_ATTRIBUTE *attribute)
|
|
{
|
|
NSSLOWKEYPrivateKey *key;
|
|
char *label;
|
|
unsigned char *keyString;
|
|
CK_RV crv;
|
|
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:
|
|
case CKA_LOCAL:
|
|
return LG_CLONE_ATTR(attribute,type,lg_StaticTrueAttr);
|
|
case CKA_NEVER_EXTRACTABLE:
|
|
return LG_CLONE_ATTR(attribute,type,lg_StaticFalseAttr);
|
|
case CKA_START_DATE:
|
|
case CKA_END_DATE:
|
|
return LG_CLONE_ATTR(attribute,type,lg_StaticNullAttr);
|
|
case CKA_LABEL:
|
|
label = lg_FindKeyNicknameByPublicKey(obj->sdb, &obj->dbKey);
|
|
if (label == NULL) {
|
|
return LG_CLONE_ATTR(attribute,type,lg_StaticNullAttr);
|
|
}
|
|
crv = lg_CopyAttribute(attribute,type,label,PORT_Strlen(label));
|
|
PORT_Free(label);
|
|
return crv;
|
|
case CKA_ID:
|
|
return lg_CopyAttribute(attribute,type,obj->dbKey.data,
|
|
obj->dbKey.len);
|
|
case CKA_KEY_TYPE:
|
|
case CKA_VALUE_LEN:
|
|
case CKA_VALUE:
|
|
break;
|
|
default:
|
|
return lg_invalidAttribute(attribute);
|
|
}
|
|
|
|
key = lg_GetPrivateKey(obj);
|
|
if (key == NULL) {
|
|
return CKR_OBJECT_HANDLE_INVALID;
|
|
}
|
|
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. When we 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 lg_ULongAttribute(attribute, type, keyType);
|
|
case CKA_VALUE:
|
|
return lg_CopyPrivAttribute(attribute,type,key->u.rsa.privateExponent.data,
|
|
key->u.rsa.privateExponent.len, obj->sdb);
|
|
case CKA_VALUE_LEN:
|
|
keyLen=key->u.rsa.privateExponent.len;
|
|
return lg_ULongAttribute(attribute,type, keyLen);
|
|
}
|
|
return lg_invalidAttribute(attribute);
|
|
}
|
|
|
|
static CK_RV
|
|
lg_FindRSAPrivateKeyAttribute(NSSLOWKEYPrivateKey *key, CK_ATTRIBUTE_TYPE type,
|
|
CK_ATTRIBUTE *attribute, SDB *sdbpw)
|
|
{
|
|
unsigned char hash[SHA1_LENGTH];
|
|
CK_KEY_TYPE keyType = CKK_RSA;
|
|
|
|
switch (type) {
|
|
case CKA_KEY_TYPE:
|
|
return lg_ULongAttribute(attribute, type, keyType);
|
|
case CKA_ID:
|
|
SHA1_HashBuf(hash,key->u.rsa.modulus.data,key->u.rsa.modulus.len);
|
|
return lg_CopyAttribute(attribute,type,hash,SHA1_LENGTH);
|
|
case CKA_DERIVE:
|
|
return LG_CLONE_ATTR(attribute,type,lg_StaticFalseAttr);
|
|
case CKA_DECRYPT:
|
|
case CKA_SIGN:
|
|
case CKA_SIGN_RECOVER:
|
|
case CKA_UNWRAP:
|
|
return LG_CLONE_ATTR(attribute, type,lg_StaticTrueAttr);
|
|
case CKA_MODULUS:
|
|
return lg_CopyAttributeSigned(attribute,type,key->u.rsa.modulus.data,
|
|
key->u.rsa.modulus.len);
|
|
case CKA_PUBLIC_EXPONENT:
|
|
return lg_CopyAttributeSigned(attribute, type,
|
|
key->u.rsa.publicExponent.data,
|
|
key->u.rsa.publicExponent.len);
|
|
case CKA_PRIVATE_EXPONENT:
|
|
return lg_CopyPrivAttrSigned(attribute,type,
|
|
key->u.rsa.privateExponent.data,
|
|
key->u.rsa.privateExponent.len, sdbpw);
|
|
case CKA_PRIME_1:
|
|
return lg_CopyPrivAttrSigned(attribute, type, key->u.rsa.prime1.data,
|
|
key->u.rsa.prime1.len, sdbpw);
|
|
case CKA_PRIME_2:
|
|
return lg_CopyPrivAttrSigned(attribute, type, key->u.rsa.prime2.data,
|
|
key->u.rsa.prime2.len, sdbpw);
|
|
case CKA_EXPONENT_1:
|
|
return lg_CopyPrivAttrSigned(attribute, type,
|
|
key->u.rsa.exponent1.data,
|
|
key->u.rsa.exponent1.len, sdbpw);
|
|
case CKA_EXPONENT_2:
|
|
return lg_CopyPrivAttrSigned(attribute, type,
|
|
key->u.rsa.exponent2.data,
|
|
key->u.rsa.exponent2.len, sdbpw);
|
|
case CKA_COEFFICIENT:
|
|
return lg_CopyPrivAttrSigned(attribute, type,
|
|
key->u.rsa.coefficient.data,
|
|
key->u.rsa.coefficient.len, sdbpw);
|
|
default:
|
|
break;
|
|
}
|
|
return lg_invalidAttribute(attribute);
|
|
}
|
|
|
|
static CK_RV
|
|
lg_FindDSAPrivateKeyAttribute(NSSLOWKEYPrivateKey *key, CK_ATTRIBUTE_TYPE type,
|
|
CK_ATTRIBUTE *attribute, SDB *sdbpw)
|
|
{
|
|
unsigned char hash[SHA1_LENGTH];
|
|
CK_KEY_TYPE keyType = CKK_DSA;
|
|
|
|
switch (type) {
|
|
case CKA_KEY_TYPE:
|
|
return lg_ULongAttribute(attribute, type, keyType);
|
|
case CKA_ID:
|
|
SHA1_HashBuf(hash,key->u.dsa.publicValue.data,
|
|
key->u.dsa.publicValue.len);
|
|
return lg_CopyAttribute(attribute,type,hash,SHA1_LENGTH);
|
|
case CKA_DERIVE:
|
|
case CKA_DECRYPT:
|
|
case CKA_SIGN_RECOVER:
|
|
case CKA_UNWRAP:
|
|
return LG_CLONE_ATTR(attribute,type,lg_StaticFalseAttr);
|
|
case CKA_SIGN:
|
|
return LG_CLONE_ATTR(attribute,type,lg_StaticTrueAttr);
|
|
case CKA_VALUE:
|
|
return lg_CopyPrivAttrSigned(attribute, type,
|
|
key->u.dsa.privateValue.data,
|
|
key->u.dsa.privateValue.len, sdbpw);
|
|
case CKA_PRIME:
|
|
return lg_CopyAttributeSigned(attribute, type,
|
|
key->u.dsa.params.prime.data,
|
|
key->u.dsa.params.prime.len);
|
|
case CKA_SUBPRIME:
|
|
return lg_CopyAttributeSigned(attribute, type,
|
|
key->u.dsa.params.subPrime.data,
|
|
key->u.dsa.params.subPrime.len);
|
|
case CKA_BASE:
|
|
return lg_CopyAttributeSigned(attribute, type,
|
|
key->u.dsa.params.base.data,
|
|
key->u.dsa.params.base.len);
|
|
case CKA_NETSCAPE_DB:
|
|
return lg_CopyAttributeSigned(attribute, type,
|
|
key->u.dsa.publicValue.data,
|
|
key->u.dsa.publicValue.len);
|
|
default:
|
|
break;
|
|
}
|
|
return lg_invalidAttribute(attribute);
|
|
}
|
|
|
|
static CK_RV
|
|
lg_FindDHPrivateKeyAttribute(NSSLOWKEYPrivateKey *key, CK_ATTRIBUTE_TYPE type,
|
|
CK_ATTRIBUTE *attribute, SDB *sdbpw)
|
|
{
|
|
unsigned char hash[SHA1_LENGTH];
|
|
CK_KEY_TYPE keyType = CKK_DH;
|
|
|
|
switch (type) {
|
|
case CKA_KEY_TYPE:
|
|
return lg_ULongAttribute(attribute, type, keyType);
|
|
case CKA_ID:
|
|
SHA1_HashBuf(hash,key->u.dh.publicValue.data,key->u.dh.publicValue.len);
|
|
return lg_CopyAttribute(attribute,type,hash,SHA1_LENGTH);
|
|
case CKA_DERIVE:
|
|
return LG_CLONE_ATTR(attribute,type,lg_StaticTrueAttr);
|
|
case CKA_DECRYPT:
|
|
case CKA_SIGN:
|
|
case CKA_SIGN_RECOVER:
|
|
case CKA_UNWRAP:
|
|
return LG_CLONE_ATTR(attribute,type,lg_StaticFalseAttr);
|
|
case CKA_VALUE:
|
|
return lg_CopyPrivAttrSigned(attribute, type,
|
|
key->u.dh.privateValue.data,
|
|
key->u.dh.privateValue.len, sdbpw);
|
|
case CKA_PRIME:
|
|
return lg_CopyAttributeSigned(attribute, type, key->u.dh.prime.data,
|
|
key->u.dh.prime.len);
|
|
case CKA_BASE:
|
|
return lg_CopyAttributeSigned(attribute, type, key->u.dh.base.data,
|
|
key->u.dh.base.len);
|
|
case CKA_NETSCAPE_DB:
|
|
return lg_CopyAttributeSigned(attribute, type,
|
|
key->u.dh.publicValue.data,
|
|
key->u.dh.publicValue.len);
|
|
default:
|
|
break;
|
|
}
|
|
return lg_invalidAttribute(attribute);
|
|
}
|
|
|
|
#ifndef NSS_DISABLE_ECC
|
|
static CK_RV
|
|
lg_FindECPrivateKeyAttribute(NSSLOWKEYPrivateKey *key, CK_ATTRIBUTE_TYPE type,
|
|
CK_ATTRIBUTE *attribute, SDB *sdbpw)
|
|
{
|
|
unsigned char hash[SHA1_LENGTH];
|
|
CK_KEY_TYPE keyType = CKK_EC;
|
|
|
|
switch (type) {
|
|
case CKA_KEY_TYPE:
|
|
return lg_ULongAttribute(attribute, type, keyType);
|
|
case CKA_ID:
|
|
SHA1_HashBuf(hash,key->u.ec.publicValue.data,key->u.ec.publicValue.len);
|
|
return lg_CopyAttribute(attribute,type,hash,SHA1_LENGTH);
|
|
case CKA_DERIVE:
|
|
case CKA_SIGN:
|
|
return LG_CLONE_ATTR(attribute,type,lg_StaticTrueAttr);
|
|
case CKA_DECRYPT:
|
|
case CKA_SIGN_RECOVER:
|
|
case CKA_UNWRAP:
|
|
return LG_CLONE_ATTR(attribute,type,lg_StaticFalseAttr);
|
|
case CKA_VALUE:
|
|
return lg_CopyPrivAttrSigned(attribute, type,
|
|
key->u.ec.privateValue.data,
|
|
key->u.ec.privateValue.len, sdbpw);
|
|
case CKA_EC_PARAMS:
|
|
return lg_CopyAttributeSigned(attribute, type,
|
|
key->u.ec.ecParams.DEREncoding.data,
|
|
key->u.ec.ecParams.DEREncoding.len);
|
|
case CKA_NETSCAPE_DB:
|
|
return lg_CopyAttributeSigned(attribute, type,
|
|
key->u.ec.publicValue.data,
|
|
key->u.ec.publicValue.len);
|
|
default:
|
|
break;
|
|
}
|
|
return lg_invalidAttribute(attribute);
|
|
}
|
|
#endif /* NSS_DISABLE_ECC */
|
|
|
|
static CK_RV
|
|
lg_FindPrivateKeyAttribute(LGObjectCache *obj, CK_ATTRIBUTE_TYPE type,
|
|
CK_ATTRIBUTE *attribute)
|
|
{
|
|
NSSLOWKEYPrivateKey *key;
|
|
char *label;
|
|
CK_RV crv;
|
|
|
|
switch (type) {
|
|
case CKA_PRIVATE:
|
|
case CKA_SENSITIVE:
|
|
case CKA_ALWAYS_SENSITIVE:
|
|
case CKA_EXTRACTABLE:
|
|
case CKA_MODIFIABLE:
|
|
case CKA_LOCAL:
|
|
return LG_CLONE_ATTR(attribute,type,lg_StaticTrueAttr);
|
|
case CKA_NEVER_EXTRACTABLE:
|
|
return LG_CLONE_ATTR(attribute,type,lg_StaticFalseAttr);
|
|
case CKA_SUBJECT:
|
|
return LG_CLONE_ATTR(attribute,type,lg_StaticNullAttr);
|
|
case CKA_START_DATE:
|
|
case CKA_END_DATE:
|
|
return LG_CLONE_ATTR(attribute,type,lg_StaticNullAttr);
|
|
case CKA_LABEL:
|
|
label = lg_FindKeyNicknameByPublicKey(obj->sdb, &obj->dbKey);
|
|
if (label == NULL) {
|
|
return LG_CLONE_ATTR(attribute,type,lg_StaticNullAttr);
|
|
}
|
|
crv = lg_CopyAttribute(attribute,type,label,PORT_Strlen(label));
|
|
PORT_Free(label);
|
|
return crv;
|
|
default:
|
|
break;
|
|
}
|
|
key = lg_GetPrivateKey(obj);
|
|
if (key == NULL) {
|
|
return CKR_OBJECT_HANDLE_INVALID;
|
|
}
|
|
switch (key->keyType) {
|
|
case NSSLOWKEYRSAKey:
|
|
return lg_FindRSAPrivateKeyAttribute(key,type,attribute,obj->sdb);
|
|
case NSSLOWKEYDSAKey:
|
|
return lg_FindDSAPrivateKeyAttribute(key,type,attribute,obj->sdb);
|
|
case NSSLOWKEYDHKey:
|
|
return lg_FindDHPrivateKeyAttribute(key,type,attribute,obj->sdb);
|
|
#ifndef NSS_DISABLE_ECC
|
|
case NSSLOWKEYECKey:
|
|
return lg_FindECPrivateKeyAttribute(key,type,attribute,obj->sdb);
|
|
#endif /* NSS_DISABLE_ECC */
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return lg_invalidAttribute(attribute);
|
|
}
|
|
|
|
static CK_RV
|
|
lg_FindSMIMEAttribute(LGObjectCache *obj, CK_ATTRIBUTE_TYPE type,
|
|
CK_ATTRIBUTE *attribute)
|
|
{
|
|
certDBEntrySMime *entry;
|
|
switch (type) {
|
|
case CKA_PRIVATE:
|
|
case CKA_MODIFIABLE:
|
|
return LG_CLONE_ATTR(attribute,type,lg_StaticFalseAttr);
|
|
case CKA_NSS_EMAIL:
|
|
return lg_CopyAttribute(attribute,type,obj->dbKey.data,
|
|
obj->dbKey.len-1);
|
|
case CKA_NSS_SMIME_TIMESTAMP:
|
|
case CKA_SUBJECT:
|
|
case CKA_VALUE:
|
|
break;
|
|
default:
|
|
return lg_invalidAttribute(attribute);
|
|
}
|
|
entry = lg_getSMime(obj);
|
|
if (entry == NULL) {
|
|
return CKR_OBJECT_HANDLE_INVALID;
|
|
}
|
|
switch (type) {
|
|
case CKA_NSS_SMIME_TIMESTAMP:
|
|
return lg_CopyAttribute(attribute,type,entry->optionsDate.data,
|
|
entry->optionsDate.len);
|
|
case CKA_SUBJECT:
|
|
return lg_CopyAttribute(attribute,type,entry->subjectName.data,
|
|
entry->subjectName.len);
|
|
case CKA_VALUE:
|
|
return lg_CopyAttribute(attribute,type,entry->smimeOptions.data,
|
|
entry->smimeOptions.len);
|
|
default:
|
|
break;
|
|
}
|
|
return lg_invalidAttribute(attribute);
|
|
}
|
|
|
|
static CK_RV
|
|
lg_FindTrustAttribute(LGObjectCache *obj, CK_ATTRIBUTE_TYPE type,
|
|
CK_ATTRIBUTE *attribute)
|
|
{
|
|
NSSLOWCERTTrust *trust;
|
|
NSSLOWCERTCertDBHandle *certHandle;
|
|
NSSLOWCERTCertificate *cert;
|
|
unsigned char hash[SHA1_LENGTH];
|
|
unsigned int trustFlags;
|
|
CK_RV crv;
|
|
|
|
switch (type) {
|
|
case CKA_PRIVATE:
|
|
return LG_CLONE_ATTR(attribute,type,lg_StaticFalseAttr);
|
|
case CKA_MODIFIABLE:
|
|
return LG_CLONE_ATTR(attribute,type,lg_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:
|
|
case CKA_ISSUER:
|
|
case CKA_SERIAL_NUMBER:
|
|
break;
|
|
default:
|
|
return lg_invalidAttribute(attribute);
|
|
}
|
|
certHandle = lg_getCertDB(obj->sdb);
|
|
if (!certHandle) {
|
|
return CKR_OBJECT_HANDLE_INVALID;
|
|
}
|
|
trust = lg_getTrust(obj, certHandle);
|
|
if (trust == NULL) {
|
|
return CKR_OBJECT_HANDLE_INVALID;
|
|
}
|
|
switch (type) {
|
|
case CKA_CERT_SHA1_HASH:
|
|
SHA1_HashBuf(hash,trust->derCert->data,trust->derCert->len);
|
|
return lg_CopyAttribute(attribute, type, hash, SHA1_LENGTH);
|
|
case CKA_CERT_MD5_HASH:
|
|
MD5_HashBuf(hash,trust->derCert->data,trust->derCert->len);
|
|
return lg_CopyAttribute(attribute, type, hash, MD5_LENGTH);
|
|
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 lg_ULongAttribute(attribute, type,
|
|
CKT_NSS_TRUSTED_DELEGATOR);
|
|
}
|
|
if (trustFlags & CERTDB_TRUSTED) {
|
|
return lg_ULongAttribute(attribute, type, CKT_NSS_TRUSTED);
|
|
}
|
|
if (trustFlags & CERTDB_MUST_VERIFY) {
|
|
return lg_ULongAttribute(attribute, type,
|
|
CKT_NSS_MUST_VERIFY_TRUST);
|
|
}
|
|
if (trustFlags & CERTDB_TRUSTED_UNKNOWN) {
|
|
return lg_ULongAttribute(attribute, type, CKT_NSS_TRUST_UNKNOWN);
|
|
}
|
|
if (trustFlags & CERTDB_VALID_CA) {
|
|
return lg_ULongAttribute(attribute, type, CKT_NSS_VALID_DELEGATOR);
|
|
}
|
|
if (trustFlags & CERTDB_TERMINAL_RECORD) {
|
|
return lg_ULongAttribute(attribute, type, CKT_NSS_NOT_TRUSTED);
|
|
}
|
|
return lg_ULongAttribute(attribute, type, CKT_NSS_TRUST_UNKNOWN);
|
|
case CKA_TRUST_STEP_UP_APPROVED:
|
|
if (trust->trust->sslFlags & CERTDB_GOVT_APPROVED_CA) {
|
|
return LG_CLONE_ATTR(attribute,type,lg_StaticTrueAttr);
|
|
} else {
|
|
return LG_CLONE_ATTR(attribute,type,lg_StaticFalseAttr);
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
|
|
|
|
switch (type) {
|
|
case CKA_ISSUER:
|
|
cert = lg_getCert(obj, certHandle);
|
|
if (cert == NULL) break;
|
|
crv = lg_CopyAttribute(attribute,type,cert->derIssuer.data,
|
|
cert->derIssuer.len);
|
|
break;
|
|
case CKA_SERIAL_NUMBER:
|
|
cert = lg_getCert(obj, certHandle);
|
|
if (cert == NULL) break;
|
|
crv = lg_CopyAttribute(attribute,type,cert->derSN.data,
|
|
cert->derSN.len);
|
|
break;
|
|
default:
|
|
cert = NULL;
|
|
break;
|
|
}
|
|
if (cert) {
|
|
nsslowcert_DestroyCertificate(cert);
|
|
return crv;
|
|
}
|
|
return lg_invalidAttribute(attribute);
|
|
}
|
|
|
|
static CK_RV
|
|
lg_FindCrlAttribute(LGObjectCache *obj, CK_ATTRIBUTE_TYPE type,
|
|
CK_ATTRIBUTE *attribute)
|
|
{
|
|
certDBEntryRevocation *crl;
|
|
|
|
switch (type) {
|
|
case CKA_PRIVATE:
|
|
case CKA_MODIFIABLE:
|
|
return LG_CLONE_ATTR(attribute,type,lg_StaticFalseAttr);
|
|
case CKA_NSS_KRL:
|
|
return ((obj->handle == LG_TOKEN_KRL_HANDLE)
|
|
? LG_CLONE_ATTR(attribute,type,lg_StaticTrueAttr)
|
|
: LG_CLONE_ATTR(attribute,type,lg_StaticFalseAttr));
|
|
case CKA_SUBJECT:
|
|
return lg_CopyAttribute(attribute,type,obj->dbKey.data,
|
|
obj->dbKey.len);
|
|
case CKA_NSS_URL:
|
|
case CKA_VALUE:
|
|
break;
|
|
default:
|
|
return lg_invalidAttribute(attribute);
|
|
}
|
|
crl = lg_getCrl(obj);
|
|
if (!crl) {
|
|
return CKR_OBJECT_HANDLE_INVALID;
|
|
}
|
|
switch (type) {
|
|
case CKA_NSS_URL:
|
|
if (crl->url == NULL) {
|
|
return LG_CLONE_ATTR(attribute,type,lg_StaticNullAttr);
|
|
}
|
|
return lg_CopyAttribute(attribute, type, crl->url,
|
|
PORT_Strlen(crl->url)+1);
|
|
case CKA_VALUE:
|
|
return lg_CopyAttribute(attribute, type, crl->derCrl.data,
|
|
crl->derCrl.len);
|
|
default:
|
|
break;
|
|
}
|
|
return lg_invalidAttribute(attribute);
|
|
}
|
|
|
|
static CK_RV
|
|
lg_FindCertAttribute(LGObjectCache *obj, CK_ATTRIBUTE_TYPE type,
|
|
CK_ATTRIBUTE *attribute)
|
|
{
|
|
NSSLOWCERTCertificate *cert;
|
|
NSSLOWCERTCertDBHandle *certHandle;
|
|
NSSLOWKEYPublicKey *pubKey;
|
|
unsigned char hash[SHA1_LENGTH];
|
|
SECItem *item;
|
|
|
|
switch (type) {
|
|
case CKA_PRIVATE:
|
|
return LG_CLONE_ATTR(attribute,type,lg_StaticFalseAttr);
|
|
case CKA_MODIFIABLE:
|
|
return LG_CLONE_ATTR(attribute,type,lg_StaticTrueAttr);
|
|
case CKA_CERTIFICATE_TYPE:
|
|
/* hardcoding X.509 into here */
|
|
return lg_ULongAttribute(attribute, type, CKC_X_509);
|
|
case CKA_VALUE:
|
|
case CKA_ID:
|
|
case CKA_LABEL:
|
|
case CKA_SUBJECT:
|
|
case CKA_ISSUER:
|
|
case CKA_SERIAL_NUMBER:
|
|
case CKA_NSS_EMAIL:
|
|
break;
|
|
default:
|
|
return lg_invalidAttribute(attribute);
|
|
}
|
|
|
|
certHandle = lg_getCertDB(obj->sdb);
|
|
if (certHandle == NULL) {
|
|
return CKR_OBJECT_HANDLE_INVALID;
|
|
}
|
|
|
|
cert = lg_getCert(obj, certHandle);
|
|
if (cert == NULL) {
|
|
return CKR_OBJECT_HANDLE_INVALID;
|
|
}
|
|
switch (type) {
|
|
case CKA_VALUE:
|
|
return lg_CopyAttribute(attribute,type,cert->derCert.data,
|
|
cert->derCert.len);
|
|
case CKA_ID:
|
|
if (((cert->trust->sslFlags & CERTDB_USER) == 0) &&
|
|
((cert->trust->emailFlags & CERTDB_USER) == 0) &&
|
|
((cert->trust->objectSigningFlags & CERTDB_USER) == 0)) {
|
|
return LG_CLONE_ATTR(attribute,type,lg_StaticNullAttr);
|
|
}
|
|
pubKey = nsslowcert_ExtractPublicKey(cert);
|
|
if (pubKey == NULL) break;
|
|
item = lg_GetPubItem(pubKey);
|
|
if (item == NULL) {
|
|
lg_nsslowkey_DestroyPublicKey(pubKey);
|
|
break;
|
|
}
|
|
SHA1_HashBuf(hash,item->data,item->len);
|
|
/* item is imbedded in pubKey, just free the key */
|
|
lg_nsslowkey_DestroyPublicKey(pubKey);
|
|
return lg_CopyAttribute(attribute, type, hash, SHA1_LENGTH);
|
|
case CKA_LABEL:
|
|
return cert->nickname
|
|
? lg_CopyAttribute(attribute, type, cert->nickname,
|
|
PORT_Strlen(cert->nickname))
|
|
: LG_CLONE_ATTR(attribute,type,lg_StaticNullAttr);
|
|
case CKA_SUBJECT:
|
|
return lg_CopyAttribute(attribute,type,cert->derSubject.data,
|
|
cert->derSubject.len);
|
|
case CKA_ISSUER:
|
|
return lg_CopyAttribute(attribute,type,cert->derIssuer.data,
|
|
cert->derIssuer.len);
|
|
case CKA_SERIAL_NUMBER:
|
|
return lg_CopyAttribute(attribute,type,cert->derSN.data,
|
|
cert->derSN.len);
|
|
case CKA_NSS_EMAIL:
|
|
return (cert->emailAddr && cert->emailAddr[0])
|
|
? lg_CopyAttribute(attribute, type, cert->emailAddr,
|
|
PORT_Strlen(cert->emailAddr))
|
|
: LG_CLONE_ATTR(attribute,type,lg_StaticNullAttr);
|
|
default:
|
|
break;
|
|
}
|
|
return lg_invalidAttribute(attribute);
|
|
}
|
|
|
|
CK_RV
|
|
lg_GetSingleAttribute(LGObjectCache *obj, CK_ATTRIBUTE *attribute)
|
|
{
|
|
/* handle the common ones */
|
|
CK_ATTRIBUTE_TYPE type = attribute->type;
|
|
switch (type) {
|
|
case CKA_CLASS:
|
|
return lg_ULongAttribute(attribute,type,obj->objclass);
|
|
case CKA_TOKEN:
|
|
return LG_CLONE_ATTR(attribute, type,lg_StaticTrueAttr);
|
|
case CKA_LABEL:
|
|
if ( (obj->objclass == CKO_CERTIFICATE)
|
|
|| (obj->objclass == CKO_PRIVATE_KEY)
|
|
|| (obj->objclass == CKO_PUBLIC_KEY)
|
|
|| (obj->objclass == CKO_SECRET_KEY)) {
|
|
break;
|
|
}
|
|
return LG_CLONE_ATTR(attribute,type,lg_StaticNullAttr);
|
|
default:
|
|
break;
|
|
}
|
|
switch (obj->objclass) {
|
|
case CKO_CERTIFICATE:
|
|
return lg_FindCertAttribute(obj,type,attribute);
|
|
case CKO_NSS_CRL:
|
|
return lg_FindCrlAttribute(obj,type,attribute);
|
|
case CKO_NSS_TRUST:
|
|
return lg_FindTrustAttribute(obj,type,attribute);
|
|
case CKO_NSS_SMIME:
|
|
return lg_FindSMIMEAttribute(obj,type,attribute);
|
|
case CKO_PUBLIC_KEY:
|
|
return lg_FindPublicKeyAttribute(obj,type,attribute);
|
|
case CKO_PRIVATE_KEY:
|
|
return lg_FindPrivateKeyAttribute(obj,type,attribute);
|
|
case CKO_SECRET_KEY:
|
|
return lg_FindSecretKeyAttribute(obj,type,attribute);
|
|
default:
|
|
break;
|
|
}
|
|
return lg_invalidAttribute(attribute);
|
|
}
|
|
|
|
/*
|
|
* Fill in the attribute template based on the data in the database.
|
|
*/
|
|
CK_RV
|
|
lg_GetAttributeValue(SDB *sdb, CK_OBJECT_HANDLE handle, CK_ATTRIBUTE *templ,
|
|
CK_ULONG count)
|
|
{
|
|
LGObjectCache *obj = lg_NewObjectCache(sdb, NULL, handle & ~LG_TOKEN_MASK);
|
|
CK_RV crv, crvCollect = CKR_OK;
|
|
int i;
|
|
|
|
if (obj == NULL) {
|
|
return CKR_OBJECT_HANDLE_INVALID;
|
|
}
|
|
|
|
for (i=0; i < count; i++) {
|
|
crv = lg_GetSingleAttribute(obj, &templ[i]);
|
|
if (crvCollect == CKR_OK) crvCollect = crv;
|
|
}
|
|
|
|
lg_DestroyObjectCache(obj);
|
|
return crvCollect;
|
|
}
|
|
|
|
PRBool
|
|
lg_cmpAttribute(LGObjectCache *obj, const CK_ATTRIBUTE *attribute)
|
|
{
|
|
unsigned char buf[LG_BUF_SPACE];
|
|
CK_ATTRIBUTE testAttr;
|
|
unsigned char *tempBuf = NULL;
|
|
PRBool match = PR_TRUE;
|
|
CK_RV crv;
|
|
|
|
/* we're going to compare 'attribute' with the actual attribute from
|
|
* the object. We'll use the length of 'attribute' to decide how much
|
|
* space we need to read the test attribute. If 'attribute' doesn't give
|
|
* enough space, then we know the values don't match and that will
|
|
* show up as ckr != CKR_OK */
|
|
testAttr = *attribute;
|
|
testAttr.pValue = buf;
|
|
|
|
/* if we don't have enough space, malloc it */
|
|
if (attribute->ulValueLen > LG_BUF_SPACE) {
|
|
tempBuf = PORT_Alloc(attribute->ulValueLen);
|
|
if (!tempBuf) {
|
|
return PR_FALSE;
|
|
}
|
|
testAttr.pValue = tempBuf;
|
|
}
|
|
|
|
/* get the attribute */
|
|
crv = lg_GetSingleAttribute(obj, &testAttr);
|
|
/* if the attribute was read OK, compare it */
|
|
if ((crv != CKR_OK) || (attribute->ulValueLen != testAttr.ulValueLen) ||
|
|
(PORT_Memcmp(attribute->pValue,testAttr.pValue,testAttr.ulValueLen)!= 0)){
|
|
/* something didn't match, this isn't the object we are looking for */
|
|
match = PR_FALSE;
|
|
}
|
|
/* free the buffer we may have allocated */
|
|
if (tempBuf) {
|
|
PORT_Free(tempBuf);
|
|
}
|
|
return match;
|
|
}
|
|
|
|
PRBool
|
|
lg_tokenMatch(SDB *sdb, const SECItem *dbKey, CK_OBJECT_HANDLE class,
|
|
const CK_ATTRIBUTE *templ, CK_ULONG count)
|
|
{
|
|
PRBool match = PR_TRUE;
|
|
LGObjectCache *obj = lg_NewObjectCache(sdb, dbKey, class);
|
|
int i;
|
|
|
|
if (obj == NULL) {
|
|
return PR_FALSE;
|
|
}
|
|
|
|
for (i=0; i < count; i++) {
|
|
match = lg_cmpAttribute(obj, &templ[i]);
|
|
if (!match) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* done looking, free up our cache */
|
|
lg_DestroyObjectCache(obj);
|
|
|
|
/* if we get through the whole list without finding a mismatched attribute,
|
|
* then this object fits the criteria we are matching */
|
|
return match;
|
|
}
|
|
|
|
static CK_RV
|
|
lg_SetCertAttribute(LGObjectCache *obj, CK_ATTRIBUTE_TYPE type,
|
|
const 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_NSS_EMAIL) {
|
|
return CKR_OK;
|
|
}
|
|
|
|
certHandle = lg_getCertDB(obj->sdb);
|
|
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 = lg_getCert(obj, 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)) {
|
|
NSSLOWKEYDBHandle *keyHandle;
|
|
|
|
keyHandle = lg_getKeyDB(obj->sdb);
|
|
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);
|
|
}
|
|
}
|
|
}
|
|
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);
|
|
}
|
|
return crv;
|
|
}
|
|
|
|
static CK_RV
|
|
lg_SetPrivateKeyAttribute(LGObjectCache *obj, CK_ATTRIBUTE_TYPE type,
|
|
const void *value, unsigned int len,
|
|
PRBool *writePrivate)
|
|
{
|
|
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) ||
|
|
(type == CKA_LOCAL) || (type == CKA_NEVER_EXTRACTABLE) ||
|
|
(type == CKA_ALWAYS_SENSITIVE)) {
|
|
return CKR_OK;
|
|
}
|
|
|
|
keyHandle = lg_getKeyDB(obj->sdb);
|
|
if (keyHandle == NULL) {
|
|
crv = CKR_TOKEN_WRITE_PROTECTED;
|
|
goto done;
|
|
}
|
|
|
|
privKey = lg_GetPrivateKeyWithDB(obj, keyHandle);
|
|
if (privKey == NULL) {
|
|
crv = CKR_OBJECT_HANDLE_INVALID;
|
|
goto done;
|
|
}
|
|
|
|
crv = CKR_ATTRIBUTE_READ_ONLY;
|
|
switch(type) {
|
|
case 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 = nsslowkey_UpdateNickname(keyHandle, privKey, &obj->dbKey,
|
|
nickname, obj->sdb);
|
|
crv = (rv == SECSuccess) ? CKR_OK : CKR_DEVICE_ERROR;
|
|
break;
|
|
case CKA_UNWRAP:
|
|
case CKA_SIGN:
|
|
case CKA_DERIVE:
|
|
case CKA_SIGN_RECOVER:
|
|
case CKA_DECRYPT:
|
|
/* ignore attempts to change restrict these.
|
|
* legacyDB ignore these flags and always presents all of them
|
|
* that are valid as true.
|
|
* NOTE: We only get here if the current value and the new value do
|
|
* not match. */
|
|
if (*(char *)value == 0) {
|
|
crv = CKR_OK;
|
|
}
|
|
break;
|
|
case CKA_VALUE:
|
|
case CKA_PRIVATE_EXPONENT:
|
|
case CKA_PRIME_1:
|
|
case CKA_PRIME_2:
|
|
case CKA_EXPONENT_1:
|
|
case CKA_EXPONENT_2:
|
|
case CKA_COEFFICIENT:
|
|
/* We aren't really changing these values, we are just triggering
|
|
* the database to update it's entry */
|
|
*writePrivate = PR_TRUE;
|
|
crv = CKR_OK;
|
|
break;
|
|
default:
|
|
crv = CKR_ATTRIBUTE_READ_ONLY;
|
|
break;
|
|
}
|
|
done:
|
|
if (nickname) {
|
|
PORT_Free(nickname);
|
|
}
|
|
return crv;
|
|
}
|
|
|
|
static CK_RV
|
|
lg_SetPublicKeyAttribute(LGObjectCache *obj, CK_ATTRIBUTE_TYPE type,
|
|
const void *value, unsigned int len,
|
|
PRBool *writePrivate)
|
|
{
|
|
/* 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) || (type == CKA_LABEL)) {
|
|
return CKR_OK;
|
|
}
|
|
return CKR_ATTRIBUTE_READ_ONLY;
|
|
}
|
|
|
|
static CK_RV
|
|
lg_SetTrustAttribute(LGObjectCache *obj, const CK_ATTRIBUTE *attr)
|
|
{
|
|
unsigned int flags;
|
|
CK_TRUST trust;
|
|
NSSLOWCERTCertificate *cert;
|
|
NSSLOWCERTCertDBHandle *certHandle;
|
|
NSSLOWCERTCertTrust dbTrust;
|
|
SECStatus rv;
|
|
CK_RV crv;
|
|
|
|
if (attr->type == CKA_LABEL) {
|
|
return CKR_OK;
|
|
}
|
|
|
|
crv = lg_GetULongAttribute(attr->type, attr, 1, &trust);
|
|
if (crv != CKR_OK) {
|
|
return crv;
|
|
}
|
|
flags = lg_MapTrust(trust, (PRBool) (attr->type == CKA_TRUST_CLIENT_AUTH));
|
|
|
|
certHandle = lg_getCertDB(obj->sdb);
|
|
|
|
if (certHandle == NULL) {
|
|
crv = CKR_TOKEN_WRITE_PROTECTED;
|
|
goto done;
|
|
}
|
|
|
|
cert = lg_getCert(obj, certHandle);
|
|
if (cert == NULL) {
|
|
crv = CKR_OBJECT_HANDLE_INVALID;
|
|
goto done;
|
|
}
|
|
dbTrust = *cert->trust;
|
|
|
|
switch (attr->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:
|
|
return crv;
|
|
}
|
|
|
|
static CK_RV
|
|
lg_SetSingleAttribute(LGObjectCache *obj, const CK_ATTRIBUTE *attr,
|
|
PRBool *writePrivate)
|
|
{
|
|
CK_ATTRIBUTE attribLocal;
|
|
CK_RV crv;
|
|
|
|
if ((attr->type == CKA_NETSCAPE_DB) && (obj->objclass == CKO_PRIVATE_KEY)) {
|
|
*writePrivate = PR_TRUE;
|
|
return CKR_OK;
|
|
}
|
|
|
|
/* Make sure the attribute exists first */
|
|
attribLocal.type = attr->type;
|
|
attribLocal.pValue = NULL;
|
|
attribLocal.ulValueLen = 0;
|
|
crv = lg_GetSingleAttribute(obj, &attribLocal);
|
|
if (crv != CKR_OK) {
|
|
return crv;
|
|
}
|
|
|
|
/* 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. */
|
|
if (attr->type != CKA_LABEL) {
|
|
if (lg_cmpAttribute(obj,attr)) {
|
|
return CKR_OK;
|
|
}
|
|
}
|
|
|
|
crv = CKR_ATTRIBUTE_READ_ONLY;
|
|
switch (obj->objclass) {
|
|
case CKO_CERTIFICATE:
|
|
/* change NICKNAME, EMAIL, */
|
|
crv = lg_SetCertAttribute(obj,attr->type,
|
|
attr->pValue,attr->ulValueLen);
|
|
break;
|
|
case CKO_NSS_CRL:
|
|
/* change URL */
|
|
break;
|
|
case CKO_NSS_TRUST:
|
|
crv = lg_SetTrustAttribute(obj,attr);
|
|
break;
|
|
case CKO_PRIVATE_KEY:
|
|
case CKO_SECRET_KEY:
|
|
crv = lg_SetPrivateKeyAttribute(obj,attr->type,
|
|
attr->pValue,attr->ulValueLen, writePrivate);
|
|
break;
|
|
case CKO_PUBLIC_KEY:
|
|
crv = lg_SetPublicKeyAttribute(obj,attr->type,
|
|
attr->pValue,attr->ulValueLen, writePrivate);
|
|
break;
|
|
}
|
|
return crv;
|
|
}
|
|
|
|
/*
|
|
* Fill in the attribute template based on the data in the database.
|
|
*/
|
|
CK_RV
|
|
lg_SetAttributeValue(SDB *sdb, CK_OBJECT_HANDLE handle,
|
|
const CK_ATTRIBUTE *templ, CK_ULONG count)
|
|
{
|
|
LGObjectCache *obj = lg_NewObjectCache(sdb, NULL, handle & ~LG_TOKEN_MASK);
|
|
CK_RV crv, crvCollect = CKR_OK;
|
|
PRBool writePrivate = PR_FALSE;
|
|
int i;
|
|
|
|
if (obj == NULL) {
|
|
return CKR_OBJECT_HANDLE_INVALID;
|
|
}
|
|
|
|
for (i=0; i < count; i++) {
|
|
crv = lg_SetSingleAttribute(obj, &templ[i], &writePrivate);
|
|
if (crvCollect == CKR_OK) crvCollect = crv;
|
|
}
|
|
|
|
/* Write any collected changes out for private and secret keys.
|
|
* don't do the write for just the label */
|
|
if (writePrivate) {
|
|
NSSLOWKEYPrivateKey *privKey = lg_GetPrivateKey(obj);
|
|
SECStatus rv = SECFailure;
|
|
char * label = lg_FindKeyNicknameByPublicKey(obj->sdb, &obj->dbKey);
|
|
|
|
if (privKey) {
|
|
rv = nsslowkey_StoreKeyByPublicKeyAlg(lg_getKeyDB(sdb), privKey,
|
|
&obj->dbKey, label, sdb, PR_TRUE );
|
|
}
|
|
if (rv != SECSuccess) {
|
|
crv = CKR_DEVICE_ERROR;
|
|
}
|
|
}
|
|
|
|
lg_DestroyObjectCache(obj);
|
|
return crvCollect;
|
|
}
|