/* 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: (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; } if (len > 0 && value != NULL) { 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; case NSSLOWKEYECKey: pubItem = &pubKey->u.ec.publicValue; break; 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); } 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 (PR_GetEnvSecure("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); } 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); case NSSLOWKEYECKey: return lg_FindECPublicKeyAttribute(key, type, attribute); 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_NSS_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_NSS_DB: return lg_CopyAttributeSigned(attribute, type, key->u.dh.publicValue.data, key->u.dh.publicValue.len); default: break; } return lg_invalidAttribute(attribute); } 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_NSS_DB: return lg_CopyAttributeSigned(attribute, type, key->u.ec.publicValue.data, key->u.ec.publicValue.len); default: break; } return lg_invalidAttribute(attribute); } 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); case NSSLOWKEYECKey: return lg_FindECPrivateKeyAttribute(key, type, attribute, obj->sdb); 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 = CKR_CANCEL; 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->pValue == NULL) || (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 = NULL; 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: if (cert) { nsslowcert_DestroyCertificate(cert); } 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_NSS_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; }