mirror of
https://github.com/rn10950/RetroZilla.git
synced 2024-11-15 04:00:12 +01:00
1c9b432ff7
M1357599, M923089+M1276618+M1278434, M1485864, M1520826, M1558548, #481-X25519, M1586176 with custom changes: - coreconf+makefiles: set NSS_NO_PKCS11_BYPASS by default (to disable, set NSS_PKCS11_BYPASS) and fix logic - curve25519_32: use PRuint32 instead of uint32_t - smime: fix decl on top of block - ssl3con: more VC6 fixes
1785 lines
49 KiB
C
1785 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;
|
|
|
|
/*
|
|
* 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 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_CopyPrivAttribute(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;
|
|
unsigned 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);
|
|
unsigned 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;
|
|
unsigned 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;
|
|
}
|
|
PORT_Free(label);
|
|
}
|
|
|
|
lg_DestroyObjectCache(obj);
|
|
return crvCollect;
|
|
}
|