andre@3: /* This Source Code Form is subject to the terms of the Mozilla Public andre@3: * License, v. 2.0. If a copy of the MPL was not distributed with this andre@3: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ andre@3: /* andre@3: * Internal PKCS #11 functions. Should only be called by pkcs11.c andre@3: */ andre@3: #include "pkcs11.h" andre@3: #include "lgdb.h" andre@3: andre@3: #include "pcertt.h" andre@3: #include "lowkeyi.h" andre@3: #include "pcert.h" andre@3: #include "blapi.h" andre@3: #include "secerr.h" andre@3: #include "secasn1.h" andre@3: andre@3: /* andre@3: * Cache the object we are working on during Set's and Get's andre@3: */ andre@3: typedef struct LGObjectCacheStr { andre@3: CK_OBJECT_CLASS objclass; andre@3: CK_OBJECT_HANDLE handle; andre@3: SDB *sdb; andre@3: void *objectInfo; andre@3: LGFreeFunc infoFree; andre@3: SECItem dbKey; andre@3: } LGObjectCache; andre@3: andre@3: static const CK_OBJECT_HANDLE lg_classArray[] = { andre@3: 0, CKO_PRIVATE_KEY, CKO_PUBLIC_KEY, CKO_SECRET_KEY, andre@3: CKO_NSS_TRUST, CKO_NSS_CRL, CKO_NSS_SMIME, andre@3: CKO_CERTIFICATE }; andre@3: andre@3: #define handleToClass(handle) \ andre@3: lg_classArray[((handle & LG_TOKEN_TYPE_MASK))>>LG_TOKEN_TYPE_SHIFT] andre@3: andre@3: andre@3: static void lg_DestroyObjectCache(LGObjectCache *obj); andre@3: andre@3: static LGObjectCache * andre@3: lg_NewObjectCache(SDB *sdb, const SECItem *dbKey, CK_OBJECT_HANDLE handle) andre@3: { andre@3: LGObjectCache *obj = NULL; andre@3: SECStatus rv; andre@3: andre@3: obj = PORT_New(LGObjectCache); andre@3: if (obj == NULL) { andre@3: return NULL; andre@3: } andre@3: andre@3: obj->objclass = handleToClass(handle); andre@3: obj->handle = handle; andre@3: obj->sdb = sdb; andre@3: obj->objectInfo = NULL; andre@3: obj->infoFree = NULL; andre@3: obj->dbKey.data = NULL; andre@3: obj->dbKey.len = 0; andre@3: lg_DBLock(sdb); andre@3: if (dbKey == NULL) { andre@3: dbKey = lg_lookupTokenKeyByHandle(sdb,handle); andre@3: } andre@3: if (dbKey == NULL) { andre@3: lg_DBUnlock(sdb); andre@3: goto loser; andre@3: } andre@3: rv = SECITEM_CopyItem(NULL,&obj->dbKey,dbKey); andre@3: lg_DBUnlock(sdb); andre@3: if (rv != SECSuccess) { andre@3: goto loser; andre@3: } andre@3: andre@3: return obj; andre@3: loser: andre@3: if (obj) { andre@3: (void) lg_DestroyObjectCache(obj); andre@3: } andre@3: return NULL; andre@3: andre@3: } andre@3: andre@3: /* andre@3: * free all the data associated with an object. Object reference count must andre@3: * be 'zero'. andre@3: */ andre@3: static void andre@3: lg_DestroyObjectCache(LGObjectCache *obj) andre@3: { andre@3: if (obj->dbKey.data) { andre@3: PORT_Free(obj->dbKey.data); andre@3: obj->dbKey.data = NULL; andre@3: } andre@3: if (obj->objectInfo) { andre@3: (*obj->infoFree)(obj->objectInfo); andre@3: obj->objectInfo = NULL; andre@3: obj->infoFree = NULL; andre@3: } andre@3: PORT_Free(obj); andre@3: } andre@3: /* andre@3: * ******************** Attribute Utilities ******************************* andre@3: */ andre@3: andre@3: static CK_RV andre@3: lg_ULongAttribute(CK_ATTRIBUTE *attr, CK_ATTRIBUTE_TYPE type, CK_ULONG value) andre@3: { andre@3: unsigned char *data; andre@3: int i; andre@3: andre@3: if (attr->pValue == NULL) { andre@3: attr->ulValueLen = 4; andre@3: return CKR_OK; andre@3: } andre@3: if (attr->ulValueLen < 4) { andre@3: attr->ulValueLen = (CK_ULONG) -1; andre@3: return CKR_BUFFER_TOO_SMALL; andre@3: } andre@3: andre@3: data = (unsigned char *)attr->pValue; andre@3: for (i=0; i < 4; i++) { andre@3: data[i] = (value >> ((3-i)*8)) & 0xff; andre@3: } andre@3: attr->ulValueLen = 4; andre@3: return CKR_OK; andre@3: } andre@3: andre@3: static CK_RV andre@3: lg_CopyAttribute(CK_ATTRIBUTE *attr, CK_ATTRIBUTE_TYPE type, andre@3: CK_VOID_PTR value, CK_ULONG len) andre@3: { andre@3: andre@3: if (attr->pValue == NULL) { andre@3: attr->ulValueLen = len; andre@3: return CKR_OK; andre@3: } andre@3: if (attr->ulValueLen < len) { andre@3: attr->ulValueLen = (CK_ULONG) -1; andre@3: return CKR_BUFFER_TOO_SMALL; andre@3: } andre@3: PORT_Memcpy(attr->pValue,value,len); andre@3: attr->ulValueLen = len; andre@3: return CKR_OK; andre@3: } andre@3: andre@3: static CK_RV andre@3: lg_CopyAttributeSigned(CK_ATTRIBUTE *attribute, CK_ATTRIBUTE_TYPE type, andre@3: void *value, CK_ULONG len) andre@3: { andre@3: unsigned char * dval = (unsigned char *)value; andre@3: if (*dval == 0) { andre@3: dval++; andre@3: len--; andre@3: } andre@3: return lg_CopyAttribute(attribute,type,dval,len); andre@3: } andre@3: andre@3: static CK_RV andre@3: lg_CopyPrivAttribute(CK_ATTRIBUTE *attribute, CK_ATTRIBUTE_TYPE type, andre@3: void *value, CK_ULONG len, SDB *sdbpw) andre@3: { andre@3: SECItem plainText, *cipherText = NULL; andre@3: CK_RV crv = CKR_USER_NOT_LOGGED_IN; andre@3: SECStatus rv; andre@3: andre@3: plainText.data = value; andre@3: plainText.len = len; andre@3: rv = lg_util_encrypt(NULL, sdbpw, &plainText, &cipherText); andre@3: if (rv != SECSuccess) { andre@3: goto loser; andre@3: } andre@3: crv = lg_CopyAttribute(attribute,type,cipherText->data,cipherText->len); andre@3: loser: andre@3: if (cipherText) { andre@3: SECITEM_FreeItem(cipherText,PR_TRUE); andre@3: } andre@3: return crv; andre@3: } andre@3: andre@3: static CK_RV andre@3: lg_CopyPrivAttrSigned(CK_ATTRIBUTE *attribute, CK_ATTRIBUTE_TYPE type, andre@3: void *value, CK_ULONG len, SDB *sdbpw) andre@3: { andre@3: unsigned char * dval = (unsigned char *)value; andre@3: andre@3: if (*dval == 0) { andre@3: dval++; andre@3: len--; andre@3: } andre@3: return lg_CopyPrivAttribute(attribute,type,dval,len,sdbpw); andre@3: } andre@3: andre@3: static CK_RV andre@3: lg_invalidAttribute(CK_ATTRIBUTE *attr) andre@3: { andre@3: attr->ulValueLen = (CK_ULONG) -1; andre@3: return CKR_ATTRIBUTE_TYPE_INVALID; andre@3: } andre@3: andre@3: andre@3: #define LG_DEF_ATTRIBUTE(value,len) \ andre@3: { 0, value, len } andre@3: andre@3: #define LG_CLONE_ATTR(attribute, type, staticAttr) \ andre@3: lg_CopyAttribute(attribute, type, staticAttr.pValue, staticAttr.ulValueLen) andre@3: andre@3: CK_BBOOL lg_staticTrueValue = CK_TRUE; andre@3: CK_BBOOL lg_staticFalseValue = CK_FALSE; andre@3: static const CK_ATTRIBUTE lg_StaticTrueAttr = andre@3: LG_DEF_ATTRIBUTE(&lg_staticTrueValue,sizeof(lg_staticTrueValue)); andre@3: static const CK_ATTRIBUTE lg_StaticFalseAttr = andre@3: LG_DEF_ATTRIBUTE(&lg_staticFalseValue,sizeof(lg_staticFalseValue)); andre@3: static const CK_ATTRIBUTE lg_StaticNullAttr = LG_DEF_ATTRIBUTE(NULL,0); andre@3: char lg_StaticOneValue = 1; andre@3: static const CK_ATTRIBUTE lg_StaticOneAttr = andre@3: LG_DEF_ATTRIBUTE(&lg_StaticOneValue,sizeof(lg_StaticOneValue)); andre@3: andre@3: /* andre@3: * helper functions which get the database and call the underlying andre@3: * low level database function. andre@3: */ andre@3: static char * andre@3: lg_FindKeyNicknameByPublicKey(SDB *sdb, SECItem *dbKey) andre@3: { andre@3: NSSLOWKEYDBHandle *keyHandle; andre@3: char * label; andre@3: andre@3: keyHandle = lg_getKeyDB(sdb); andre@3: if (!keyHandle) { andre@3: return NULL; andre@3: } andre@3: andre@3: label = nsslowkey_FindKeyNicknameByPublicKey(keyHandle, dbKey, andre@3: sdb); andre@3: return label; andre@3: } andre@3: andre@3: andre@3: NSSLOWKEYPrivateKey * andre@3: lg_FindKeyByPublicKey(SDB *sdb, SECItem *dbKey) andre@3: { andre@3: NSSLOWKEYPrivateKey *privKey; andre@3: NSSLOWKEYDBHandle *keyHandle; andre@3: andre@3: keyHandle = lg_getKeyDB(sdb); andre@3: if (keyHandle == NULL) { andre@3: return NULL; andre@3: } andre@3: privKey = nsslowkey_FindKeyByPublicKey(keyHandle, dbKey, sdb); andre@3: if (privKey == NULL) { andre@3: return NULL; andre@3: } andre@3: return privKey; andre@3: } andre@3: andre@3: static certDBEntrySMime * andre@3: lg_getSMime(LGObjectCache *obj) andre@3: { andre@3: certDBEntrySMime *entry; andre@3: NSSLOWCERTCertDBHandle *certHandle; andre@3: andre@3: if (obj->objclass != CKO_NSS_SMIME) { andre@3: return NULL; andre@3: } andre@3: if (obj->objectInfo) { andre@3: return (certDBEntrySMime *)obj->objectInfo; andre@3: } andre@3: andre@3: certHandle = lg_getCertDB(obj->sdb); andre@3: if (!certHandle) { andre@3: return NULL; andre@3: } andre@3: entry = nsslowcert_ReadDBSMimeEntry(certHandle, (char *)obj->dbKey.data); andre@3: obj->objectInfo = (void *)entry; andre@3: obj->infoFree = (LGFreeFunc) nsslowcert_DestroyDBEntry; andre@3: return entry; andre@3: } andre@3: andre@3: static certDBEntryRevocation * andre@3: lg_getCrl(LGObjectCache *obj) andre@3: { andre@3: certDBEntryRevocation *crl; andre@3: PRBool isKrl; andre@3: NSSLOWCERTCertDBHandle *certHandle; andre@3: andre@3: if (obj->objclass != CKO_NSS_CRL) { andre@3: return NULL; andre@3: } andre@3: if (obj->objectInfo) { andre@3: return (certDBEntryRevocation *)obj->objectInfo; andre@3: } andre@3: andre@3: isKrl = (PRBool) (obj->handle == LG_TOKEN_KRL_HANDLE); andre@3: certHandle = lg_getCertDB(obj->sdb); andre@3: if (!certHandle) { andre@3: return NULL; andre@3: } andre@3: andre@3: crl = nsslowcert_FindCrlByKey(certHandle, &obj->dbKey, isKrl); andre@3: obj->objectInfo = (void *)crl; andre@3: obj->infoFree = (LGFreeFunc) nsslowcert_DestroyDBEntry; andre@3: return crl; andre@3: } andre@3: andre@3: static NSSLOWCERTCertificate * andre@3: lg_getCert(LGObjectCache *obj, NSSLOWCERTCertDBHandle *certHandle) andre@3: { andre@3: NSSLOWCERTCertificate *cert; andre@3: CK_OBJECT_CLASS objClass = obj->objclass; andre@3: andre@3: if ((objClass != CKO_CERTIFICATE) && (objClass != CKO_NSS_TRUST)) { andre@3: return NULL; andre@3: } andre@3: if (objClass == CKO_CERTIFICATE && obj->objectInfo) { andre@3: return (NSSLOWCERTCertificate *)obj->objectInfo; andre@3: } andre@3: cert = nsslowcert_FindCertByKey(certHandle, &obj->dbKey); andre@3: if (objClass == CKO_CERTIFICATE) { andre@3: obj->objectInfo = (void *)cert; andre@3: obj->infoFree = (LGFreeFunc) nsslowcert_DestroyCertificate ; andre@3: } andre@3: return cert; andre@3: } andre@3: andre@3: static NSSLOWCERTTrust * andre@3: lg_getTrust(LGObjectCache *obj, NSSLOWCERTCertDBHandle *certHandle) andre@3: { andre@3: NSSLOWCERTTrust *trust; andre@3: andre@3: if (obj->objclass != CKO_NSS_TRUST) { andre@3: return NULL; andre@3: } andre@3: if (obj->objectInfo) { andre@3: return (NSSLOWCERTTrust *)obj->objectInfo; andre@3: } andre@3: trust = nsslowcert_FindTrustByKey(certHandle, &obj->dbKey); andre@3: obj->objectInfo = (void *)trust; andre@3: obj->infoFree = (LGFreeFunc) nsslowcert_DestroyTrust ; andre@3: return trust; andre@3: } andre@3: andre@3: static NSSLOWKEYPublicKey * andre@3: lg_GetPublicKey(LGObjectCache *obj) andre@3: { andre@3: NSSLOWKEYPublicKey *pubKey; andre@3: NSSLOWKEYPrivateKey *privKey; andre@3: andre@3: if (obj->objclass != CKO_PUBLIC_KEY) { andre@3: return NULL; andre@3: } andre@3: if (obj->objectInfo) { andre@3: return (NSSLOWKEYPublicKey *)obj->objectInfo; andre@3: } andre@3: privKey = lg_FindKeyByPublicKey(obj->sdb, &obj->dbKey); andre@3: if (privKey == NULL) { andre@3: return NULL; andre@3: } andre@3: pubKey = lg_nsslowkey_ConvertToPublicKey(privKey); andre@3: lg_nsslowkey_DestroyPrivateKey(privKey); andre@3: obj->objectInfo = (void *) pubKey; andre@3: obj->infoFree = (LGFreeFunc) lg_nsslowkey_DestroyPublicKey ; andre@3: return pubKey; andre@3: } andre@3: andre@3: /* andre@3: * we need two versions of lg_GetPrivateKey. One version that takes the andre@3: * DB handle so we can pass the handle we have already acquired in, andre@3: * rather than going through the 'getKeyDB' code again, andre@3: * which may fail the second time and another which just aquires andre@3: * the key handle from the sdb (where we don't already have a key handle. andre@3: * This version does the former. andre@3: */ andre@3: static NSSLOWKEYPrivateKey * andre@3: lg_GetPrivateKeyWithDB(LGObjectCache *obj, NSSLOWKEYDBHandle *keyHandle) andre@3: { andre@3: NSSLOWKEYPrivateKey *privKey; andre@3: andre@3: if ((obj->objclass != CKO_PRIVATE_KEY) && andre@3: (obj->objclass != CKO_SECRET_KEY)) { andre@3: return NULL; andre@3: } andre@3: if (obj->objectInfo) { andre@3: return (NSSLOWKEYPrivateKey *)obj->objectInfo; andre@3: } andre@3: privKey = nsslowkey_FindKeyByPublicKey(keyHandle, &obj->dbKey, obj->sdb); andre@3: if (privKey == NULL) { andre@3: return NULL; andre@3: } andre@3: obj->objectInfo = (void *) privKey; andre@3: obj->infoFree = (LGFreeFunc) lg_nsslowkey_DestroyPrivateKey ; andre@3: return privKey; andre@3: } andre@3: andre@3: /* this version does the latter */ andre@3: static NSSLOWKEYPrivateKey * andre@3: lg_GetPrivateKey(LGObjectCache *obj) andre@3: { andre@3: NSSLOWKEYDBHandle *keyHandle; andre@3: NSSLOWKEYPrivateKey *privKey; andre@3: andre@3: keyHandle = lg_getKeyDB(obj->sdb); andre@3: if (!keyHandle) { andre@3: return NULL; andre@3: } andre@3: privKey = lg_GetPrivateKeyWithDB(obj, keyHandle); andre@3: return privKey; andre@3: } andre@3: andre@3: /* lg_GetPubItem returns data associated with the public key. andre@3: * one only needs to free the public key. This comment is here andre@3: * because this sematic would be non-obvious otherwise. All callers andre@3: * should include this comment. andre@3: */ andre@3: static SECItem * andre@3: lg_GetPubItem(NSSLOWKEYPublicKey *pubKey) { andre@3: SECItem *pubItem = NULL; andre@3: /* get value to compare from the cert's public key */ andre@3: switch ( pubKey->keyType ) { andre@3: case NSSLOWKEYRSAKey: andre@3: pubItem = &pubKey->u.rsa.modulus; andre@3: break; andre@3: case NSSLOWKEYDSAKey: andre@3: pubItem = &pubKey->u.dsa.publicValue; andre@3: break; andre@3: case NSSLOWKEYDHKey: andre@3: pubItem = &pubKey->u.dh.publicValue; andre@3: break; andre@3: #ifndef NSS_DISABLE_ECC andre@3: case NSSLOWKEYECKey: andre@3: pubItem = &pubKey->u.ec.publicValue; andre@3: break; andre@3: #endif /* NSS_DISABLE_ECC */ andre@3: default: andre@3: break; andre@3: } andre@3: return pubItem; andre@3: } andre@3: andre@3: static const SEC_ASN1Template lg_SerialTemplate[] = { andre@3: { SEC_ASN1_INTEGER, offsetof(NSSLOWCERTCertificate,serialNumber) }, andre@3: { 0 } andre@3: }; andre@3: andre@3: static CK_RV andre@3: lg_FindRSAPublicKeyAttribute(NSSLOWKEYPublicKey *key, CK_ATTRIBUTE_TYPE type, andre@3: CK_ATTRIBUTE *attribute) andre@3: { andre@3: unsigned char hash[SHA1_LENGTH]; andre@3: CK_KEY_TYPE keyType = CKK_RSA; andre@3: andre@3: switch (type) { andre@3: case CKA_KEY_TYPE: andre@3: return lg_ULongAttribute(attribute, type, keyType); andre@3: case CKA_ID: andre@3: SHA1_HashBuf(hash,key->u.rsa.modulus.data,key->u.rsa.modulus.len); andre@3: return lg_CopyAttribute(attribute,type,hash,SHA1_LENGTH); andre@3: case CKA_DERIVE: andre@3: return LG_CLONE_ATTR(attribute,type,lg_StaticFalseAttr); andre@3: case CKA_ENCRYPT: andre@3: case CKA_VERIFY: andre@3: case CKA_VERIFY_RECOVER: andre@3: case CKA_WRAP: andre@3: return LG_CLONE_ATTR(attribute,type,lg_StaticTrueAttr); andre@3: case CKA_MODULUS: andre@3: return lg_CopyAttributeSigned(attribute,type,key->u.rsa.modulus.data, andre@3: key->u.rsa.modulus.len); andre@3: case CKA_PUBLIC_EXPONENT: andre@3: return lg_CopyAttributeSigned(attribute, type, andre@3: key->u.rsa.publicExponent.data, andre@3: key->u.rsa.publicExponent.len); andre@3: default: andre@3: break; andre@3: } andre@3: return lg_invalidAttribute(attribute); andre@3: } andre@3: andre@3: static CK_RV andre@3: lg_FindDSAPublicKeyAttribute(NSSLOWKEYPublicKey *key, CK_ATTRIBUTE_TYPE type, andre@3: CK_ATTRIBUTE *attribute) andre@3: { andre@3: unsigned char hash[SHA1_LENGTH]; andre@3: CK_KEY_TYPE keyType = CKK_DSA; andre@3: andre@3: switch (type) { andre@3: case CKA_KEY_TYPE: andre@3: return lg_ULongAttribute(attribute, type, keyType); andre@3: case CKA_ID: andre@3: SHA1_HashBuf(hash,key->u.dsa.publicValue.data, andre@3: key->u.dsa.publicValue.len); andre@3: return lg_CopyAttribute(attribute,type,hash,SHA1_LENGTH); andre@3: case CKA_DERIVE: andre@3: case CKA_ENCRYPT: andre@3: case CKA_VERIFY_RECOVER: andre@3: case CKA_WRAP: andre@3: return LG_CLONE_ATTR(attribute,type,lg_StaticFalseAttr); andre@3: case CKA_VERIFY: andre@3: return LG_CLONE_ATTR(attribute,type,lg_StaticTrueAttr); andre@3: case CKA_VALUE: andre@3: return lg_CopyAttributeSigned(attribute,type, andre@3: key->u.dsa.publicValue.data, andre@3: key->u.dsa.publicValue.len); andre@3: case CKA_PRIME: andre@3: return lg_CopyAttributeSigned(attribute,type, andre@3: key->u.dsa.params.prime.data, andre@3: key->u.dsa.params.prime.len); andre@3: case CKA_SUBPRIME: andre@3: return lg_CopyAttributeSigned(attribute,type, andre@3: key->u.dsa.params.subPrime.data, andre@3: key->u.dsa.params.subPrime.len); andre@3: case CKA_BASE: andre@3: return lg_CopyAttributeSigned(attribute,type, andre@3: key->u.dsa.params.base.data, andre@3: key->u.dsa.params.base.len); andre@3: default: andre@3: break; andre@3: } andre@3: return lg_invalidAttribute(attribute); andre@3: } andre@3: andre@3: static CK_RV andre@3: lg_FindDHPublicKeyAttribute(NSSLOWKEYPublicKey *key, CK_ATTRIBUTE_TYPE type, andre@3: CK_ATTRIBUTE *attribute) andre@3: { andre@3: unsigned char hash[SHA1_LENGTH]; andre@3: CK_KEY_TYPE keyType = CKK_DH; andre@3: andre@3: switch (type) { andre@3: case CKA_KEY_TYPE: andre@3: return lg_ULongAttribute(attribute, type, keyType); andre@3: case CKA_ID: andre@3: SHA1_HashBuf(hash,key->u.dh.publicValue.data,key->u.dh.publicValue.len); andre@3: return lg_CopyAttribute(attribute,type,hash,SHA1_LENGTH); andre@3: case CKA_DERIVE: andre@3: return LG_CLONE_ATTR(attribute,type,lg_StaticTrueAttr); andre@3: case CKA_ENCRYPT: andre@3: case CKA_VERIFY: andre@3: case CKA_VERIFY_RECOVER: andre@3: case CKA_WRAP: andre@3: return LG_CLONE_ATTR(attribute,type,lg_StaticFalseAttr); andre@3: case CKA_VALUE: andre@3: return lg_CopyAttributeSigned(attribute,type, andre@3: key->u.dh.publicValue.data, andre@3: key->u.dh.publicValue.len); andre@3: case CKA_PRIME: andre@3: return lg_CopyAttributeSigned(attribute,type,key->u.dh.prime.data, andre@3: key->u.dh.prime.len); andre@3: case CKA_BASE: andre@3: return lg_CopyAttributeSigned(attribute,type,key->u.dh.base.data, andre@3: key->u.dh.base.len); andre@3: default: andre@3: break; andre@3: } andre@3: return lg_invalidAttribute(attribute); andre@3: } andre@3: andre@3: #ifndef NSS_DISABLE_ECC andre@3: static CK_RV andre@3: lg_FindECPublicKeyAttribute(NSSLOWKEYPublicKey *key, CK_ATTRIBUTE_TYPE type, andre@3: CK_ATTRIBUTE *attribute) andre@3: { andre@3: unsigned char hash[SHA1_LENGTH]; andre@3: CK_KEY_TYPE keyType = CKK_EC; andre@3: andre@3: switch (type) { andre@3: case CKA_KEY_TYPE: andre@3: return lg_ULongAttribute(attribute, type, keyType); andre@3: case CKA_ID: andre@3: SHA1_HashBuf(hash, key->u.ec.publicValue.data, andre@3: key->u.ec.publicValue.len); andre@3: return lg_CopyAttribute(attribute,type,hash,SHA1_LENGTH); andre@3: case CKA_DERIVE: andre@3: case CKA_VERIFY: andre@3: return LG_CLONE_ATTR(attribute,type,lg_StaticTrueAttr); andre@3: case CKA_ENCRYPT: andre@3: case CKA_VERIFY_RECOVER: andre@3: case CKA_WRAP: andre@3: return LG_CLONE_ATTR(attribute,type,lg_StaticFalseAttr); andre@3: case CKA_EC_PARAMS: andre@3: return lg_CopyAttributeSigned(attribute,type, andre@3: key->u.ec.ecParams.DEREncoding.data, andre@3: key->u.ec.ecParams.DEREncoding.len); andre@3: case CKA_EC_POINT: andre@3: if (getenv("NSS_USE_DECODED_CKA_EC_POINT")) { andre@3: return lg_CopyAttributeSigned(attribute, type, andre@3: key->u.ec.publicValue.data, andre@3: key->u.ec.publicValue.len); andre@3: } else { andre@3: SECItem *pubValue = SEC_ASN1EncodeItem(NULL, NULL, andre@3: &(key->u.ec.publicValue), andre@3: SEC_ASN1_GET(SEC_OctetStringTemplate)); andre@3: CK_RV crv; andre@3: if (!pubValue) { andre@3: return CKR_HOST_MEMORY; andre@3: } andre@3: crv = lg_CopyAttributeSigned(attribute, type, andre@3: pubValue->data, andre@3: pubValue->len); andre@3: SECITEM_FreeItem(pubValue, PR_TRUE); andre@3: return crv; andre@3: } andre@3: default: andre@3: break; andre@3: } andre@3: return lg_invalidAttribute(attribute); andre@3: } andre@3: #endif /* NSS_DISABLE_ECC */ andre@3: andre@3: andre@3: static CK_RV andre@3: lg_FindPublicKeyAttribute(LGObjectCache *obj, CK_ATTRIBUTE_TYPE type, andre@3: CK_ATTRIBUTE *attribute) andre@3: { andre@3: NSSLOWKEYPublicKey *key; andre@3: CK_RV crv; andre@3: char *label; andre@3: andre@3: switch (type) { andre@3: case CKA_PRIVATE: andre@3: case CKA_SENSITIVE: andre@3: case CKA_ALWAYS_SENSITIVE: andre@3: case CKA_NEVER_EXTRACTABLE: andre@3: return LG_CLONE_ATTR(attribute,type,lg_StaticFalseAttr); andre@3: case CKA_MODIFIABLE: andre@3: case CKA_EXTRACTABLE: andre@3: return LG_CLONE_ATTR(attribute,type,lg_StaticTrueAttr); andre@3: case CKA_SUBJECT: andre@3: return LG_CLONE_ATTR(attribute,type,lg_StaticNullAttr); andre@3: case CKA_START_DATE: andre@3: case CKA_END_DATE: andre@3: return LG_CLONE_ATTR(attribute,type,lg_StaticNullAttr); andre@3: case CKA_LABEL: andre@3: label = lg_FindKeyNicknameByPublicKey(obj->sdb, &obj->dbKey); andre@3: if (label == NULL) { andre@3: return LG_CLONE_ATTR(attribute,type,lg_StaticNullAttr); andre@3: } andre@3: crv = lg_CopyAttribute(attribute,type,label,PORT_Strlen(label)); andre@3: PORT_Free(label); andre@3: return crv; andre@3: default: andre@3: break; andre@3: } andre@3: andre@3: key = lg_GetPublicKey(obj); andre@3: if (key == NULL) { andre@3: if (type == CKA_ID) { andre@3: return LG_CLONE_ATTR(attribute,type,lg_StaticNullAttr); andre@3: } andre@3: return CKR_OBJECT_HANDLE_INVALID; andre@3: } andre@3: andre@3: switch (key->keyType) { andre@3: case NSSLOWKEYRSAKey: andre@3: return lg_FindRSAPublicKeyAttribute(key,type,attribute); andre@3: case NSSLOWKEYDSAKey: andre@3: return lg_FindDSAPublicKeyAttribute(key,type,attribute); andre@3: case NSSLOWKEYDHKey: andre@3: return lg_FindDHPublicKeyAttribute(key,type,attribute); andre@3: #ifndef NSS_DISABLE_ECC andre@3: case NSSLOWKEYECKey: andre@3: return lg_FindECPublicKeyAttribute(key,type,attribute); andre@3: #endif /* NSS_DISABLE_ECC */ andre@3: default: andre@3: break; andre@3: } andre@3: andre@3: return lg_invalidAttribute(attribute); andre@3: } andre@3: andre@3: static CK_RV andre@3: lg_FindSecretKeyAttribute(LGObjectCache *obj, CK_ATTRIBUTE_TYPE type, andre@3: CK_ATTRIBUTE *attribute) andre@3: { andre@3: NSSLOWKEYPrivateKey *key; andre@3: char *label; andre@3: unsigned char *keyString; andre@3: CK_RV crv; andre@3: int keyTypeLen; andre@3: CK_ULONG keyLen; andre@3: CK_KEY_TYPE keyType; andre@3: PRUint32 keyTypeStorage; andre@3: andre@3: switch (type) { andre@3: case CKA_PRIVATE: andre@3: case CKA_SENSITIVE: andre@3: case CKA_ALWAYS_SENSITIVE: andre@3: case CKA_EXTRACTABLE: andre@3: case CKA_DERIVE: andre@3: case CKA_ENCRYPT: andre@3: case CKA_DECRYPT: andre@3: case CKA_SIGN: andre@3: case CKA_VERIFY: andre@3: case CKA_WRAP: andre@3: case CKA_UNWRAP: andre@3: case CKA_MODIFIABLE: andre@3: case CKA_LOCAL: andre@3: return LG_CLONE_ATTR(attribute,type,lg_StaticTrueAttr); andre@3: case CKA_NEVER_EXTRACTABLE: andre@3: return LG_CLONE_ATTR(attribute,type,lg_StaticFalseAttr); andre@3: case CKA_START_DATE: andre@3: case CKA_END_DATE: andre@3: return LG_CLONE_ATTR(attribute,type,lg_StaticNullAttr); andre@3: case CKA_LABEL: andre@3: label = lg_FindKeyNicknameByPublicKey(obj->sdb, &obj->dbKey); andre@3: if (label == NULL) { andre@3: return LG_CLONE_ATTR(attribute,type,lg_StaticNullAttr); andre@3: } andre@3: crv = lg_CopyAttribute(attribute,type,label,PORT_Strlen(label)); andre@3: PORT_Free(label); andre@3: return crv; andre@3: case CKA_ID: andre@3: return lg_CopyAttribute(attribute,type,obj->dbKey.data, andre@3: obj->dbKey.len); andre@3: case CKA_KEY_TYPE: andre@3: case CKA_VALUE_LEN: andre@3: case CKA_VALUE: andre@3: break; andre@3: default: andre@3: return lg_invalidAttribute(attribute); andre@3: } andre@3: andre@3: key = lg_GetPrivateKey(obj); andre@3: if (key == NULL) { andre@3: return CKR_OBJECT_HANDLE_INVALID; andre@3: } andre@3: switch (type) { andre@3: case CKA_KEY_TYPE: andre@3: /* handle legacy databases. In legacy databases key_type was stored andre@3: * in host order, with any leading zeros stripped off. Only key types andre@3: * under 0x1f (AES) were stored. We assume that any values which are andre@3: * either 1 byte long (big endian), or have byte[0] between 0 and andre@3: * 0x7f and bytes[1]-bytes[3] equal to '0' (little endian). All other andre@3: * values are assumed to be from the new database, which is always 4 andre@3: * bytes in network order */ andre@3: keyType=0; andre@3: keyString = key->u.rsa.coefficient.data; andre@3: keyTypeLen = key->u.rsa.coefficient.len; andre@3: andre@3: andre@3: /* andre@3: * Because of various endian and word lengths The database may have andre@3: * stored the keyType value in one of the following formats: andre@3: * (kt) <= 0x1f andre@3: * length data andre@3: * Big Endian, pre-3.9, all lengths: 1 (kt) andre@3: * Little Endian, pre-3.9, 32 bits: 4 (kt) 0 0 0 andre@3: * Little Endian, pre-3.9, 64 bits: 8 (kt) 0 0 0 0 0 0 0 andre@3: * All platforms, 3.9, 32 bits: 4 0 0 0 (kt) andre@3: * Big Endian, 3.9, 64 bits: 8 0 0 0 (kt) 0 0 0 0 andre@3: * Little Endian, 3.9, 64 bits: 8 0 0 0 0 0 0 0 (kt) andre@3: * All platforms, >= 3.9.1, all lengths: 4 (a) k1 k2 k3 andre@3: * where (a) is 0 or >= 0x80. currently (a) can only be 0. andre@3: */ andre@3: /* andre@3: * this key was written on a 64 bit platform with a using NSS 3.9 andre@3: * or earlier. Reduce the 64 bit possibilities above. When we are andre@3: * through, we will only have: andre@3: * andre@3: * Big Endian, pre-3.9, all lengths: 1 (kt) andre@3: * Little Endian, pre-3.9, all lengths: 4 (kt) 0 0 0 andre@3: * All platforms, 3.9, all lengths: 4 0 0 0 (kt) andre@3: * All platforms, => 3.9.1, all lengths: 4 (a) k1 k2 k3 andre@3: */ andre@3: if (keyTypeLen == 8) { andre@3: keyTypeStorage = *(PRUint32 *) keyString; andre@3: if (keyTypeStorage == 0) { andre@3: keyString += sizeof(PRUint32); andre@3: } andre@3: keyTypeLen = 4; andre@3: } andre@3: /* andre@3: * Now Handle: andre@3: * andre@3: * All platforms, 3.9, all lengths: 4 0 0 0 (kt) andre@3: * All platforms, => 3.9.1, all lengths: 4 (a) k1 k2 k3 andre@3: * andre@3: * NOTE: if kt == 0 or ak1k2k3 == 0, the test fails and andre@3: * we handle it as: andre@3: * andre@3: * Little Endian, pre-3.9, all lengths: 4 (kt) 0 0 0 andre@3: */ andre@3: if (keyTypeLen == sizeof(keyTypeStorage) && andre@3: (((keyString[0] & 0x80) == 0x80) || andre@3: !((keyString[1] == 0) && (keyString[2] == 0) andre@3: && (keyString[3] == 0))) ) { andre@3: PORT_Memcpy(&keyTypeStorage, keyString, sizeof(keyTypeStorage)); andre@3: keyType = (CK_KEY_TYPE) PR_ntohl(keyTypeStorage); andre@3: } else { andre@3: /* andre@3: * Now Handle: andre@3: * andre@3: * Big Endian, pre-3.9, all lengths: 1 (kt) andre@3: * Little Endian, pre-3.9, all lengths: 4 (kt) 0 0 0 andre@3: * -- KeyType == 0 all other cases ---: 4 0 0 0 0 andre@3: */ andre@3: keyType = (CK_KEY_TYPE) keyString[0] ; andre@3: } andre@3: return lg_ULongAttribute(attribute, type, keyType); andre@3: case CKA_VALUE: andre@3: return lg_CopyPrivAttribute(attribute,type,key->u.rsa.privateExponent.data, andre@3: key->u.rsa.privateExponent.len, obj->sdb); andre@3: case CKA_VALUE_LEN: andre@3: keyLen=key->u.rsa.privateExponent.len; andre@3: return lg_ULongAttribute(attribute,type, keyLen); andre@3: } andre@3: return lg_invalidAttribute(attribute); andre@3: } andre@3: andre@3: static CK_RV andre@3: lg_FindRSAPrivateKeyAttribute(NSSLOWKEYPrivateKey *key, CK_ATTRIBUTE_TYPE type, andre@3: CK_ATTRIBUTE *attribute, SDB *sdbpw) andre@3: { andre@3: unsigned char hash[SHA1_LENGTH]; andre@3: CK_KEY_TYPE keyType = CKK_RSA; andre@3: andre@3: switch (type) { andre@3: case CKA_KEY_TYPE: andre@3: return lg_ULongAttribute(attribute, type, keyType); andre@3: case CKA_ID: andre@3: SHA1_HashBuf(hash,key->u.rsa.modulus.data,key->u.rsa.modulus.len); andre@3: return lg_CopyAttribute(attribute,type,hash,SHA1_LENGTH); andre@3: case CKA_DERIVE: andre@3: return LG_CLONE_ATTR(attribute,type,lg_StaticFalseAttr); andre@3: case CKA_DECRYPT: andre@3: case CKA_SIGN: andre@3: case CKA_SIGN_RECOVER: andre@3: case CKA_UNWRAP: andre@3: return LG_CLONE_ATTR(attribute, type,lg_StaticTrueAttr); andre@3: case CKA_MODULUS: andre@3: return lg_CopyAttributeSigned(attribute,type,key->u.rsa.modulus.data, andre@3: key->u.rsa.modulus.len); andre@3: case CKA_PUBLIC_EXPONENT: andre@3: return lg_CopyAttributeSigned(attribute, type, andre@3: key->u.rsa.publicExponent.data, andre@3: key->u.rsa.publicExponent.len); andre@3: case CKA_PRIVATE_EXPONENT: andre@3: return lg_CopyPrivAttrSigned(attribute,type, andre@3: key->u.rsa.privateExponent.data, andre@3: key->u.rsa.privateExponent.len, sdbpw); andre@3: case CKA_PRIME_1: andre@3: return lg_CopyPrivAttrSigned(attribute, type, key->u.rsa.prime1.data, andre@3: key->u.rsa.prime1.len, sdbpw); andre@3: case CKA_PRIME_2: andre@3: return lg_CopyPrivAttrSigned(attribute, type, key->u.rsa.prime2.data, andre@3: key->u.rsa.prime2.len, sdbpw); andre@3: case CKA_EXPONENT_1: andre@3: return lg_CopyPrivAttrSigned(attribute, type, andre@3: key->u.rsa.exponent1.data, andre@3: key->u.rsa.exponent1.len, sdbpw); andre@3: case CKA_EXPONENT_2: andre@3: return lg_CopyPrivAttrSigned(attribute, type, andre@3: key->u.rsa.exponent2.data, andre@3: key->u.rsa.exponent2.len, sdbpw); andre@3: case CKA_COEFFICIENT: andre@3: return lg_CopyPrivAttrSigned(attribute, type, andre@3: key->u.rsa.coefficient.data, andre@3: key->u.rsa.coefficient.len, sdbpw); andre@3: default: andre@3: break; andre@3: } andre@3: return lg_invalidAttribute(attribute); andre@3: } andre@3: andre@3: static CK_RV andre@3: lg_FindDSAPrivateKeyAttribute(NSSLOWKEYPrivateKey *key, CK_ATTRIBUTE_TYPE type, andre@3: CK_ATTRIBUTE *attribute, SDB *sdbpw) andre@3: { andre@3: unsigned char hash[SHA1_LENGTH]; andre@3: CK_KEY_TYPE keyType = CKK_DSA; andre@3: andre@3: switch (type) { andre@3: case CKA_KEY_TYPE: andre@3: return lg_ULongAttribute(attribute, type, keyType); andre@3: case CKA_ID: andre@3: SHA1_HashBuf(hash,key->u.dsa.publicValue.data, andre@3: key->u.dsa.publicValue.len); andre@3: return lg_CopyAttribute(attribute,type,hash,SHA1_LENGTH); andre@3: case CKA_DERIVE: andre@3: case CKA_DECRYPT: andre@3: case CKA_SIGN_RECOVER: andre@3: case CKA_UNWRAP: andre@3: return LG_CLONE_ATTR(attribute,type,lg_StaticFalseAttr); andre@3: case CKA_SIGN: andre@3: return LG_CLONE_ATTR(attribute,type,lg_StaticTrueAttr); andre@3: case CKA_VALUE: andre@3: return lg_CopyPrivAttrSigned(attribute, type, andre@3: key->u.dsa.privateValue.data, andre@3: key->u.dsa.privateValue.len, sdbpw); andre@3: case CKA_PRIME: andre@3: return lg_CopyAttributeSigned(attribute, type, andre@3: key->u.dsa.params.prime.data, andre@3: key->u.dsa.params.prime.len); andre@3: case CKA_SUBPRIME: andre@3: return lg_CopyAttributeSigned(attribute, type, andre@3: key->u.dsa.params.subPrime.data, andre@3: key->u.dsa.params.subPrime.len); andre@3: case CKA_BASE: andre@3: return lg_CopyAttributeSigned(attribute, type, andre@3: key->u.dsa.params.base.data, andre@3: key->u.dsa.params.base.len); andre@3: case CKA_NETSCAPE_DB: andre@3: return lg_CopyAttributeSigned(attribute, type, andre@3: key->u.dsa.publicValue.data, andre@3: key->u.dsa.publicValue.len); andre@3: default: andre@3: break; andre@3: } andre@3: return lg_invalidAttribute(attribute); andre@3: } andre@3: andre@3: static CK_RV andre@3: lg_FindDHPrivateKeyAttribute(NSSLOWKEYPrivateKey *key, CK_ATTRIBUTE_TYPE type, andre@3: CK_ATTRIBUTE *attribute, SDB *sdbpw) andre@3: { andre@3: unsigned char hash[SHA1_LENGTH]; andre@3: CK_KEY_TYPE keyType = CKK_DH; andre@3: andre@3: switch (type) { andre@3: case CKA_KEY_TYPE: andre@3: return lg_ULongAttribute(attribute, type, keyType); andre@3: case CKA_ID: andre@3: SHA1_HashBuf(hash,key->u.dh.publicValue.data,key->u.dh.publicValue.len); andre@3: return lg_CopyAttribute(attribute,type,hash,SHA1_LENGTH); andre@3: case CKA_DERIVE: andre@3: return LG_CLONE_ATTR(attribute,type,lg_StaticTrueAttr); andre@3: case CKA_DECRYPT: andre@3: case CKA_SIGN: andre@3: case CKA_SIGN_RECOVER: andre@3: case CKA_UNWRAP: andre@3: return LG_CLONE_ATTR(attribute,type,lg_StaticFalseAttr); andre@3: case CKA_VALUE: andre@3: return lg_CopyPrivAttrSigned(attribute, type, andre@3: key->u.dh.privateValue.data, andre@3: key->u.dh.privateValue.len, sdbpw); andre@3: case CKA_PRIME: andre@3: return lg_CopyAttributeSigned(attribute, type, key->u.dh.prime.data, andre@3: key->u.dh.prime.len); andre@3: case CKA_BASE: andre@3: return lg_CopyAttributeSigned(attribute, type, key->u.dh.base.data, andre@3: key->u.dh.base.len); andre@3: case CKA_NETSCAPE_DB: andre@3: return lg_CopyAttributeSigned(attribute, type, andre@3: key->u.dh.publicValue.data, andre@3: key->u.dh.publicValue.len); andre@3: default: andre@3: break; andre@3: } andre@3: return lg_invalidAttribute(attribute); andre@3: } andre@3: andre@3: #ifndef NSS_DISABLE_ECC andre@3: static CK_RV andre@3: lg_FindECPrivateKeyAttribute(NSSLOWKEYPrivateKey *key, CK_ATTRIBUTE_TYPE type, andre@3: CK_ATTRIBUTE *attribute, SDB *sdbpw) andre@3: { andre@3: unsigned char hash[SHA1_LENGTH]; andre@3: CK_KEY_TYPE keyType = CKK_EC; andre@3: andre@3: switch (type) { andre@3: case CKA_KEY_TYPE: andre@3: return lg_ULongAttribute(attribute, type, keyType); andre@3: case CKA_ID: andre@3: SHA1_HashBuf(hash,key->u.ec.publicValue.data,key->u.ec.publicValue.len); andre@3: return lg_CopyAttribute(attribute,type,hash,SHA1_LENGTH); andre@3: case CKA_DERIVE: andre@3: case CKA_SIGN: andre@3: return LG_CLONE_ATTR(attribute,type,lg_StaticTrueAttr); andre@3: case CKA_DECRYPT: andre@3: case CKA_SIGN_RECOVER: andre@3: case CKA_UNWRAP: andre@3: return LG_CLONE_ATTR(attribute,type,lg_StaticFalseAttr); andre@3: case CKA_VALUE: andre@3: return lg_CopyPrivAttrSigned(attribute, type, andre@3: key->u.ec.privateValue.data, andre@3: key->u.ec.privateValue.len, sdbpw); andre@3: case CKA_EC_PARAMS: andre@3: return lg_CopyAttributeSigned(attribute, type, andre@3: key->u.ec.ecParams.DEREncoding.data, andre@3: key->u.ec.ecParams.DEREncoding.len); andre@3: case CKA_NETSCAPE_DB: andre@3: return lg_CopyAttributeSigned(attribute, type, andre@3: key->u.ec.publicValue.data, andre@3: key->u.ec.publicValue.len); andre@3: default: andre@3: break; andre@3: } andre@3: return lg_invalidAttribute(attribute); andre@3: } andre@3: #endif /* NSS_DISABLE_ECC */ andre@3: andre@3: static CK_RV andre@3: lg_FindPrivateKeyAttribute(LGObjectCache *obj, CK_ATTRIBUTE_TYPE type, andre@3: CK_ATTRIBUTE *attribute) andre@3: { andre@3: NSSLOWKEYPrivateKey *key; andre@3: char *label; andre@3: CK_RV crv; andre@3: andre@3: switch (type) { andre@3: case CKA_PRIVATE: andre@3: case CKA_SENSITIVE: andre@3: case CKA_ALWAYS_SENSITIVE: andre@3: case CKA_EXTRACTABLE: andre@3: case CKA_MODIFIABLE: andre@3: case CKA_LOCAL: andre@3: return LG_CLONE_ATTR(attribute,type,lg_StaticTrueAttr); andre@3: case CKA_NEVER_EXTRACTABLE: andre@3: return LG_CLONE_ATTR(attribute,type,lg_StaticFalseAttr); andre@3: case CKA_SUBJECT: andre@3: return LG_CLONE_ATTR(attribute,type,lg_StaticNullAttr); andre@3: case CKA_START_DATE: andre@3: case CKA_END_DATE: andre@3: return LG_CLONE_ATTR(attribute,type,lg_StaticNullAttr); andre@3: case CKA_LABEL: andre@3: label = lg_FindKeyNicknameByPublicKey(obj->sdb, &obj->dbKey); andre@3: if (label == NULL) { andre@3: return LG_CLONE_ATTR(attribute,type,lg_StaticNullAttr); andre@3: } andre@3: crv = lg_CopyAttribute(attribute,type,label,PORT_Strlen(label)); andre@3: PORT_Free(label); andre@3: return crv; andre@3: default: andre@3: break; andre@3: } andre@3: key = lg_GetPrivateKey(obj); andre@3: if (key == NULL) { andre@3: return CKR_OBJECT_HANDLE_INVALID; andre@3: } andre@3: switch (key->keyType) { andre@3: case NSSLOWKEYRSAKey: andre@3: return lg_FindRSAPrivateKeyAttribute(key,type,attribute,obj->sdb); andre@3: case NSSLOWKEYDSAKey: andre@3: return lg_FindDSAPrivateKeyAttribute(key,type,attribute,obj->sdb); andre@3: case NSSLOWKEYDHKey: andre@3: return lg_FindDHPrivateKeyAttribute(key,type,attribute,obj->sdb); andre@3: #ifndef NSS_DISABLE_ECC andre@3: case NSSLOWKEYECKey: andre@3: return lg_FindECPrivateKeyAttribute(key,type,attribute,obj->sdb); andre@3: #endif /* NSS_DISABLE_ECC */ andre@3: default: andre@3: break; andre@3: } andre@3: andre@3: return lg_invalidAttribute(attribute); andre@3: } andre@3: andre@3: static CK_RV andre@3: lg_FindSMIMEAttribute(LGObjectCache *obj, CK_ATTRIBUTE_TYPE type, andre@3: CK_ATTRIBUTE *attribute) andre@3: { andre@3: certDBEntrySMime *entry; andre@3: switch (type) { andre@3: case CKA_PRIVATE: andre@3: case CKA_MODIFIABLE: andre@3: return LG_CLONE_ATTR(attribute,type,lg_StaticFalseAttr); andre@3: case CKA_NSS_EMAIL: andre@3: return lg_CopyAttribute(attribute,type,obj->dbKey.data, andre@3: obj->dbKey.len-1); andre@3: case CKA_NSS_SMIME_TIMESTAMP: andre@3: case CKA_SUBJECT: andre@3: case CKA_VALUE: andre@3: break; andre@3: default: andre@3: return lg_invalidAttribute(attribute); andre@3: } andre@3: entry = lg_getSMime(obj); andre@3: if (entry == NULL) { andre@3: return CKR_OBJECT_HANDLE_INVALID; andre@3: } andre@3: switch (type) { andre@3: case CKA_NSS_SMIME_TIMESTAMP: andre@3: return lg_CopyAttribute(attribute,type,entry->optionsDate.data, andre@3: entry->optionsDate.len); andre@3: case CKA_SUBJECT: andre@3: return lg_CopyAttribute(attribute,type,entry->subjectName.data, andre@3: entry->subjectName.len); andre@3: case CKA_VALUE: andre@3: return lg_CopyAttribute(attribute,type,entry->smimeOptions.data, andre@3: entry->smimeOptions.len); andre@3: default: andre@3: break; andre@3: } andre@3: return lg_invalidAttribute(attribute); andre@3: } andre@3: andre@3: static CK_RV andre@3: lg_FindTrustAttribute(LGObjectCache *obj, CK_ATTRIBUTE_TYPE type, andre@3: CK_ATTRIBUTE *attribute) andre@3: { andre@3: NSSLOWCERTTrust *trust; andre@3: NSSLOWCERTCertDBHandle *certHandle; andre@3: NSSLOWCERTCertificate *cert; andre@3: unsigned char hash[SHA1_LENGTH]; andre@3: unsigned int trustFlags; andre@3: CK_RV crv; andre@3: andre@3: switch (type) { andre@3: case CKA_PRIVATE: andre@3: return LG_CLONE_ATTR(attribute,type,lg_StaticFalseAttr); andre@3: case CKA_MODIFIABLE: andre@3: return LG_CLONE_ATTR(attribute,type,lg_StaticTrueAttr); andre@3: case CKA_CERT_SHA1_HASH: andre@3: case CKA_CERT_MD5_HASH: andre@3: case CKA_TRUST_CLIENT_AUTH: andre@3: case CKA_TRUST_SERVER_AUTH: andre@3: case CKA_TRUST_EMAIL_PROTECTION: andre@3: case CKA_TRUST_CODE_SIGNING: andre@3: case CKA_TRUST_STEP_UP_APPROVED: andre@3: case CKA_ISSUER: andre@3: case CKA_SERIAL_NUMBER: andre@3: break; andre@3: default: andre@3: return lg_invalidAttribute(attribute); andre@3: } andre@3: certHandle = lg_getCertDB(obj->sdb); andre@3: if (!certHandle) { andre@3: return CKR_OBJECT_HANDLE_INVALID; andre@3: } andre@3: trust = lg_getTrust(obj, certHandle); andre@3: if (trust == NULL) { andre@3: return CKR_OBJECT_HANDLE_INVALID; andre@3: } andre@3: switch (type) { andre@3: case CKA_CERT_SHA1_HASH: andre@3: SHA1_HashBuf(hash,trust->derCert->data,trust->derCert->len); andre@3: return lg_CopyAttribute(attribute, type, hash, SHA1_LENGTH); andre@3: case CKA_CERT_MD5_HASH: andre@3: MD5_HashBuf(hash,trust->derCert->data,trust->derCert->len); andre@3: return lg_CopyAttribute(attribute, type, hash, MD5_LENGTH); andre@3: case CKA_TRUST_CLIENT_AUTH: andre@3: trustFlags = trust->trust->sslFlags & CERTDB_TRUSTED_CLIENT_CA ? andre@3: trust->trust->sslFlags | CERTDB_TRUSTED_CA : 0 ; andre@3: goto trust; andre@3: case CKA_TRUST_SERVER_AUTH: andre@3: trustFlags = trust->trust->sslFlags; andre@3: goto trust; andre@3: case CKA_TRUST_EMAIL_PROTECTION: andre@3: trustFlags = trust->trust->emailFlags; andre@3: goto trust; andre@3: case CKA_TRUST_CODE_SIGNING: andre@3: trustFlags = trust->trust->objectSigningFlags; andre@3: trust: andre@3: if (trustFlags & CERTDB_TRUSTED_CA ) { andre@3: return lg_ULongAttribute(attribute, type, andre@3: CKT_NSS_TRUSTED_DELEGATOR); andre@3: } andre@3: if (trustFlags & CERTDB_TRUSTED) { andre@3: return lg_ULongAttribute(attribute, type, CKT_NSS_TRUSTED); andre@3: } andre@3: if (trustFlags & CERTDB_MUST_VERIFY) { andre@3: return lg_ULongAttribute(attribute, type, andre@3: CKT_NSS_MUST_VERIFY_TRUST); andre@3: } andre@3: if (trustFlags & CERTDB_TRUSTED_UNKNOWN) { andre@3: return lg_ULongAttribute(attribute, type, CKT_NSS_TRUST_UNKNOWN); andre@3: } andre@3: if (trustFlags & CERTDB_VALID_CA) { andre@3: return lg_ULongAttribute(attribute, type, CKT_NSS_VALID_DELEGATOR); andre@3: } andre@3: if (trustFlags & CERTDB_TERMINAL_RECORD) { andre@3: return lg_ULongAttribute(attribute, type, CKT_NSS_NOT_TRUSTED); andre@3: } andre@3: return lg_ULongAttribute(attribute, type, CKT_NSS_TRUST_UNKNOWN); andre@3: case CKA_TRUST_STEP_UP_APPROVED: andre@3: if (trust->trust->sslFlags & CERTDB_GOVT_APPROVED_CA) { andre@3: return LG_CLONE_ATTR(attribute,type,lg_StaticTrueAttr); andre@3: } else { andre@3: return LG_CLONE_ATTR(attribute,type,lg_StaticFalseAttr); andre@3: } andre@3: default: andre@3: break; andre@3: } andre@3: andre@3: andre@3: switch (type) { andre@3: case CKA_ISSUER: andre@3: cert = lg_getCert(obj, certHandle); andre@3: if (cert == NULL) break; andre@3: crv = lg_CopyAttribute(attribute,type,cert->derIssuer.data, andre@3: cert->derIssuer.len); andre@3: break; andre@3: case CKA_SERIAL_NUMBER: andre@3: cert = lg_getCert(obj, certHandle); andre@3: if (cert == NULL) break; andre@3: crv = lg_CopyAttribute(attribute,type,cert->derSN.data, andre@3: cert->derSN.len); andre@3: break; andre@3: default: andre@3: cert = NULL; andre@3: break; andre@3: } andre@3: if (cert) { andre@3: nsslowcert_DestroyCertificate(cert); andre@3: return crv; andre@3: } andre@3: return lg_invalidAttribute(attribute); andre@3: } andre@3: andre@3: static CK_RV andre@3: lg_FindCrlAttribute(LGObjectCache *obj, CK_ATTRIBUTE_TYPE type, andre@3: CK_ATTRIBUTE *attribute) andre@3: { andre@3: certDBEntryRevocation *crl; andre@3: andre@3: switch (type) { andre@3: case CKA_PRIVATE: andre@3: case CKA_MODIFIABLE: andre@3: return LG_CLONE_ATTR(attribute,type,lg_StaticFalseAttr); andre@3: case CKA_NSS_KRL: andre@3: return ((obj->handle == LG_TOKEN_KRL_HANDLE) andre@3: ? LG_CLONE_ATTR(attribute,type,lg_StaticTrueAttr) andre@3: : LG_CLONE_ATTR(attribute,type,lg_StaticFalseAttr)); andre@3: case CKA_SUBJECT: andre@3: return lg_CopyAttribute(attribute,type,obj->dbKey.data, andre@3: obj->dbKey.len); andre@3: case CKA_NSS_URL: andre@3: case CKA_VALUE: andre@3: break; andre@3: default: andre@3: return lg_invalidAttribute(attribute); andre@3: } andre@3: crl = lg_getCrl(obj); andre@3: if (!crl) { andre@3: return CKR_OBJECT_HANDLE_INVALID; andre@3: } andre@3: switch (type) { andre@3: case CKA_NSS_URL: andre@3: if (crl->url == NULL) { andre@3: return LG_CLONE_ATTR(attribute,type,lg_StaticNullAttr); andre@3: } andre@3: return lg_CopyAttribute(attribute, type, crl->url, andre@3: PORT_Strlen(crl->url)+1); andre@3: case CKA_VALUE: andre@3: return lg_CopyAttribute(attribute, type, crl->derCrl.data, andre@3: crl->derCrl.len); andre@3: default: andre@3: break; andre@3: } andre@3: return lg_invalidAttribute(attribute); andre@3: } andre@3: andre@3: static CK_RV andre@3: lg_FindCertAttribute(LGObjectCache *obj, CK_ATTRIBUTE_TYPE type, andre@3: CK_ATTRIBUTE *attribute) andre@3: { andre@3: NSSLOWCERTCertificate *cert; andre@3: NSSLOWCERTCertDBHandle *certHandle; andre@3: NSSLOWKEYPublicKey *pubKey; andre@3: unsigned char hash[SHA1_LENGTH]; andre@3: SECItem *item; andre@3: andre@3: switch (type) { andre@3: case CKA_PRIVATE: andre@3: return LG_CLONE_ATTR(attribute,type,lg_StaticFalseAttr); andre@3: case CKA_MODIFIABLE: andre@3: return LG_CLONE_ATTR(attribute,type,lg_StaticTrueAttr); andre@3: case CKA_CERTIFICATE_TYPE: andre@3: /* hardcoding X.509 into here */ andre@3: return lg_ULongAttribute(attribute, type, CKC_X_509); andre@3: case CKA_VALUE: andre@3: case CKA_ID: andre@3: case CKA_LABEL: andre@3: case CKA_SUBJECT: andre@3: case CKA_ISSUER: andre@3: case CKA_SERIAL_NUMBER: andre@3: case CKA_NSS_EMAIL: andre@3: break; andre@3: default: andre@3: return lg_invalidAttribute(attribute); andre@3: } andre@3: andre@3: certHandle = lg_getCertDB(obj->sdb); andre@3: if (certHandle == NULL) { andre@3: return CKR_OBJECT_HANDLE_INVALID; andre@3: } andre@3: andre@3: cert = lg_getCert(obj, certHandle); andre@3: if (cert == NULL) { andre@3: return CKR_OBJECT_HANDLE_INVALID; andre@3: } andre@3: switch (type) { andre@3: case CKA_VALUE: andre@3: return lg_CopyAttribute(attribute,type,cert->derCert.data, andre@3: cert->derCert.len); andre@3: case CKA_ID: andre@3: if (((cert->trust->sslFlags & CERTDB_USER) == 0) && andre@3: ((cert->trust->emailFlags & CERTDB_USER) == 0) && andre@3: ((cert->trust->objectSigningFlags & CERTDB_USER) == 0)) { andre@3: return LG_CLONE_ATTR(attribute,type,lg_StaticNullAttr); andre@3: } andre@3: pubKey = nsslowcert_ExtractPublicKey(cert); andre@3: if (pubKey == NULL) break; andre@3: item = lg_GetPubItem(pubKey); andre@3: if (item == NULL) { andre@3: lg_nsslowkey_DestroyPublicKey(pubKey); andre@3: break; andre@3: } andre@3: SHA1_HashBuf(hash,item->data,item->len); andre@3: /* item is imbedded in pubKey, just free the key */ andre@3: lg_nsslowkey_DestroyPublicKey(pubKey); andre@3: return lg_CopyAttribute(attribute, type, hash, SHA1_LENGTH); andre@3: case CKA_LABEL: andre@3: return cert->nickname andre@3: ? lg_CopyAttribute(attribute, type, cert->nickname, andre@3: PORT_Strlen(cert->nickname)) andre@3: : LG_CLONE_ATTR(attribute,type,lg_StaticNullAttr); andre@3: case CKA_SUBJECT: andre@3: return lg_CopyAttribute(attribute,type,cert->derSubject.data, andre@3: cert->derSubject.len); andre@3: case CKA_ISSUER: andre@3: return lg_CopyAttribute(attribute,type,cert->derIssuer.data, andre@3: cert->derIssuer.len); andre@3: case CKA_SERIAL_NUMBER: andre@3: return lg_CopyAttribute(attribute,type,cert->derSN.data, andre@3: cert->derSN.len); andre@3: case CKA_NSS_EMAIL: andre@3: return (cert->emailAddr && cert->emailAddr[0]) andre@3: ? lg_CopyAttribute(attribute, type, cert->emailAddr, andre@3: PORT_Strlen(cert->emailAddr)) andre@3: : LG_CLONE_ATTR(attribute,type,lg_StaticNullAttr); andre@3: default: andre@3: break; andre@3: } andre@3: return lg_invalidAttribute(attribute); andre@3: } andre@3: andre@3: CK_RV andre@3: lg_GetSingleAttribute(LGObjectCache *obj, CK_ATTRIBUTE *attribute) andre@3: { andre@3: /* handle the common ones */ andre@3: CK_ATTRIBUTE_TYPE type = attribute->type; andre@3: switch (type) { andre@3: case CKA_CLASS: andre@3: return lg_ULongAttribute(attribute,type,obj->objclass); andre@3: case CKA_TOKEN: andre@3: return LG_CLONE_ATTR(attribute, type,lg_StaticTrueAttr); andre@3: case CKA_LABEL: andre@3: if ( (obj->objclass == CKO_CERTIFICATE) andre@3: || (obj->objclass == CKO_PRIVATE_KEY) andre@3: || (obj->objclass == CKO_PUBLIC_KEY) andre@3: || (obj->objclass == CKO_SECRET_KEY)) { andre@3: break; andre@3: } andre@3: return LG_CLONE_ATTR(attribute,type,lg_StaticNullAttr); andre@3: default: andre@3: break; andre@3: } andre@3: switch (obj->objclass) { andre@3: case CKO_CERTIFICATE: andre@3: return lg_FindCertAttribute(obj,type,attribute); andre@3: case CKO_NSS_CRL: andre@3: return lg_FindCrlAttribute(obj,type,attribute); andre@3: case CKO_NSS_TRUST: andre@3: return lg_FindTrustAttribute(obj,type,attribute); andre@3: case CKO_NSS_SMIME: andre@3: return lg_FindSMIMEAttribute(obj,type,attribute); andre@3: case CKO_PUBLIC_KEY: andre@3: return lg_FindPublicKeyAttribute(obj,type,attribute); andre@3: case CKO_PRIVATE_KEY: andre@3: return lg_FindPrivateKeyAttribute(obj,type,attribute); andre@3: case CKO_SECRET_KEY: andre@3: return lg_FindSecretKeyAttribute(obj,type,attribute); andre@3: default: andre@3: break; andre@3: } andre@3: return lg_invalidAttribute(attribute); andre@3: } andre@3: andre@3: /* andre@3: * Fill in the attribute template based on the data in the database. andre@3: */ andre@3: CK_RV andre@3: lg_GetAttributeValue(SDB *sdb, CK_OBJECT_HANDLE handle, CK_ATTRIBUTE *templ, andre@3: CK_ULONG count) andre@3: { andre@3: LGObjectCache *obj = lg_NewObjectCache(sdb, NULL, handle & ~LG_TOKEN_MASK); andre@3: CK_RV crv, crvCollect = CKR_OK; andre@3: unsigned int i; andre@3: andre@3: if (obj == NULL) { andre@3: return CKR_OBJECT_HANDLE_INVALID; andre@3: } andre@3: andre@3: for (i=0; i < count; i++) { andre@3: crv = lg_GetSingleAttribute(obj, &templ[i]); andre@3: if (crvCollect == CKR_OK) crvCollect = crv; andre@3: } andre@3: andre@3: lg_DestroyObjectCache(obj); andre@3: return crvCollect; andre@3: } andre@3: andre@3: PRBool andre@3: lg_cmpAttribute(LGObjectCache *obj, const CK_ATTRIBUTE *attribute) andre@3: { andre@3: unsigned char buf[LG_BUF_SPACE]; andre@3: CK_ATTRIBUTE testAttr; andre@3: unsigned char *tempBuf = NULL; andre@3: PRBool match = PR_TRUE; andre@3: CK_RV crv; andre@3: andre@3: /* we're going to compare 'attribute' with the actual attribute from andre@3: * the object. We'll use the length of 'attribute' to decide how much andre@3: * space we need to read the test attribute. If 'attribute' doesn't give andre@3: * enough space, then we know the values don't match and that will andre@3: * show up as ckr != CKR_OK */ andre@3: testAttr = *attribute; andre@3: testAttr.pValue = buf; andre@3: andre@3: /* if we don't have enough space, malloc it */ andre@3: if (attribute->ulValueLen > LG_BUF_SPACE) { andre@3: tempBuf = PORT_Alloc(attribute->ulValueLen); andre@3: if (!tempBuf) { andre@3: return PR_FALSE; andre@3: } andre@3: testAttr.pValue = tempBuf; andre@3: } andre@3: andre@3: /* get the attribute */ andre@3: crv = lg_GetSingleAttribute(obj, &testAttr); andre@3: /* if the attribute was read OK, compare it */ andre@3: if ((crv != CKR_OK) || (attribute->ulValueLen != testAttr.ulValueLen) || andre@3: (PORT_Memcmp(attribute->pValue,testAttr.pValue,testAttr.ulValueLen)!= 0)){ andre@3: /* something didn't match, this isn't the object we are looking for */ andre@3: match = PR_FALSE; andre@3: } andre@3: /* free the buffer we may have allocated */ andre@3: if (tempBuf) { andre@3: PORT_Free(tempBuf); andre@3: } andre@3: return match; andre@3: } andre@3: andre@3: PRBool andre@3: lg_tokenMatch(SDB *sdb, const SECItem *dbKey, CK_OBJECT_HANDLE class, andre@3: const CK_ATTRIBUTE *templ, CK_ULONG count) andre@3: { andre@3: PRBool match = PR_TRUE; andre@3: LGObjectCache *obj = lg_NewObjectCache(sdb, dbKey, class); andre@3: unsigned int i; andre@3: andre@3: if (obj == NULL) { andre@3: return PR_FALSE; andre@3: } andre@3: andre@3: for (i=0; i < count; i++) { andre@3: match = lg_cmpAttribute(obj, &templ[i]); andre@3: if (!match) { andre@3: break; andre@3: } andre@3: } andre@3: andre@3: /* done looking, free up our cache */ andre@3: lg_DestroyObjectCache(obj); andre@3: andre@3: /* if we get through the whole list without finding a mismatched attribute, andre@3: * then this object fits the criteria we are matching */ andre@3: return match; andre@3: } andre@3: andre@3: static CK_RV andre@3: lg_SetCertAttribute(LGObjectCache *obj, CK_ATTRIBUTE_TYPE type, andre@3: const void *value, unsigned int len) andre@3: { andre@3: NSSLOWCERTCertificate *cert; andre@3: NSSLOWCERTCertDBHandle *certHandle; andre@3: char *nickname = NULL; andre@3: SECStatus rv; andre@3: CK_RV crv; andre@3: andre@3: /* we can't change the EMAIL values, but let the andre@3: * upper layers feel better about the fact we tried to set these */ andre@3: if (type == CKA_NSS_EMAIL) { andre@3: return CKR_OK; andre@3: } andre@3: andre@3: certHandle = lg_getCertDB(obj->sdb); andre@3: if (certHandle == NULL) { andre@3: crv = CKR_TOKEN_WRITE_PROTECTED; andre@3: goto done; andre@3: } andre@3: andre@3: if ((type != CKA_LABEL) && (type != CKA_ID)) { andre@3: crv = CKR_ATTRIBUTE_READ_ONLY; andre@3: goto done; andre@3: } andre@3: andre@3: cert = lg_getCert(obj, certHandle); andre@3: if (cert == NULL) { andre@3: crv = CKR_OBJECT_HANDLE_INVALID; andre@3: goto done; andre@3: } andre@3: andre@3: /* if the app is trying to set CKA_ID, it's probably because it just andre@3: * imported the key. Look to see if we need to set the CERTDB_USER bits. andre@3: */ andre@3: if (type == CKA_ID) { andre@3: if (((cert->trust->sslFlags & CERTDB_USER) == 0) && andre@3: ((cert->trust->emailFlags & CERTDB_USER) == 0) && andre@3: ((cert->trust->objectSigningFlags & CERTDB_USER) == 0)) { andre@3: NSSLOWKEYDBHandle *keyHandle; andre@3: andre@3: keyHandle = lg_getKeyDB(obj->sdb); andre@3: if (keyHandle) { andre@3: if (nsslowkey_KeyForCertExists(keyHandle, cert)) { andre@3: NSSLOWCERTCertTrust trust = *cert->trust; andre@3: trust.sslFlags |= CERTDB_USER; andre@3: trust.emailFlags |= CERTDB_USER; andre@3: trust.objectSigningFlags |= CERTDB_USER; andre@3: nsslowcert_ChangeCertTrust(certHandle,cert,&trust); andre@3: } andre@3: } andre@3: } andre@3: crv = CKR_OK; andre@3: goto done; andre@3: } andre@3: andre@3: /* must be CKA_LABEL */ andre@3: if (value != NULL) { andre@3: nickname = PORT_ZAlloc(len+1); andre@3: if (nickname == NULL) { andre@3: crv = CKR_HOST_MEMORY; andre@3: goto done; andre@3: } andre@3: PORT_Memcpy(nickname,value,len); andre@3: nickname[len] = 0; andre@3: } andre@3: rv = nsslowcert_AddPermNickname(certHandle, cert, nickname); andre@3: crv = (rv == SECSuccess) ? CKR_OK : CKR_DEVICE_ERROR; andre@3: andre@3: done: andre@3: if (nickname) { andre@3: PORT_Free(nickname); andre@3: } andre@3: return crv; andre@3: } andre@3: andre@3: static CK_RV andre@3: lg_SetPrivateKeyAttribute(LGObjectCache *obj, CK_ATTRIBUTE_TYPE type, andre@3: const void *value, unsigned int len, andre@3: PRBool *writePrivate) andre@3: { andre@3: NSSLOWKEYPrivateKey *privKey; andre@3: NSSLOWKEYDBHandle *keyHandle; andre@3: char *nickname = NULL; andre@3: SECStatus rv; andre@3: CK_RV crv; andre@3: andre@3: /* we can't change the ID and we don't store the subject, but let the andre@3: * upper layers feel better about the fact we tried to set these */ andre@3: if ((type == CKA_ID) || (type == CKA_SUBJECT) || andre@3: (type == CKA_LOCAL) || (type == CKA_NEVER_EXTRACTABLE) || andre@3: (type == CKA_ALWAYS_SENSITIVE)) { andre@3: return CKR_OK; andre@3: } andre@3: andre@3: keyHandle = lg_getKeyDB(obj->sdb); andre@3: if (keyHandle == NULL) { andre@3: crv = CKR_TOKEN_WRITE_PROTECTED; andre@3: goto done; andre@3: } andre@3: andre@3: privKey = lg_GetPrivateKeyWithDB(obj, keyHandle); andre@3: if (privKey == NULL) { andre@3: crv = CKR_OBJECT_HANDLE_INVALID; andre@3: goto done; andre@3: } andre@3: andre@3: crv = CKR_ATTRIBUTE_READ_ONLY; andre@3: switch(type) { andre@3: case CKA_LABEL: andre@3: if (value != NULL) { andre@3: nickname = PORT_ZAlloc(len+1); andre@3: if (nickname == NULL) { andre@3: crv = CKR_HOST_MEMORY; andre@3: goto done; andre@3: } andre@3: PORT_Memcpy(nickname,value,len); andre@3: nickname[len] = 0; andre@3: } andre@3: rv = nsslowkey_UpdateNickname(keyHandle, privKey, &obj->dbKey, andre@3: nickname, obj->sdb); andre@3: crv = (rv == SECSuccess) ? CKR_OK : CKR_DEVICE_ERROR; andre@3: break; andre@3: case CKA_UNWRAP: andre@3: case CKA_SIGN: andre@3: case CKA_DERIVE: andre@3: case CKA_SIGN_RECOVER: andre@3: case CKA_DECRYPT: andre@3: /* ignore attempts to change restrict these. andre@3: * legacyDB ignore these flags and always presents all of them andre@3: * that are valid as true. andre@3: * NOTE: We only get here if the current value and the new value do andre@3: * not match. */ andre@3: if (*(char *)value == 0) { andre@3: crv = CKR_OK; andre@3: } andre@3: break; andre@3: case CKA_VALUE: andre@3: case CKA_PRIVATE_EXPONENT: andre@3: case CKA_PRIME_1: andre@3: case CKA_PRIME_2: andre@3: case CKA_EXPONENT_1: andre@3: case CKA_EXPONENT_2: andre@3: case CKA_COEFFICIENT: andre@3: /* We aren't really changing these values, we are just triggering andre@3: * the database to update it's entry */ andre@3: *writePrivate = PR_TRUE; andre@3: crv = CKR_OK; andre@3: break; andre@3: default: andre@3: crv = CKR_ATTRIBUTE_READ_ONLY; andre@3: break; andre@3: } andre@3: done: andre@3: if (nickname) { andre@3: PORT_Free(nickname); andre@3: } andre@3: return crv; andre@3: } andre@3: andre@3: static CK_RV andre@3: lg_SetPublicKeyAttribute(LGObjectCache *obj, CK_ATTRIBUTE_TYPE type, andre@3: const void *value, unsigned int len, andre@3: PRBool *writePrivate) andre@3: { andre@3: /* we can't change the ID and we don't store the subject, but let the andre@3: * upper layers feel better about the fact we tried to set these */ andre@3: if ((type == CKA_ID) || (type == CKA_SUBJECT) || (type == CKA_LABEL)) { andre@3: return CKR_OK; andre@3: } andre@3: return CKR_ATTRIBUTE_READ_ONLY; andre@3: } andre@3: andre@3: static CK_RV andre@3: lg_SetTrustAttribute(LGObjectCache *obj, const CK_ATTRIBUTE *attr) andre@3: { andre@3: unsigned int flags; andre@3: CK_TRUST trust; andre@3: NSSLOWCERTCertificate *cert; andre@3: NSSLOWCERTCertDBHandle *certHandle; andre@3: NSSLOWCERTCertTrust dbTrust; andre@3: SECStatus rv; andre@3: CK_RV crv; andre@3: andre@3: if (attr->type == CKA_LABEL) { andre@3: return CKR_OK; andre@3: } andre@3: andre@3: crv = lg_GetULongAttribute(attr->type, attr, 1, &trust); andre@3: if (crv != CKR_OK) { andre@3: return crv; andre@3: } andre@3: flags = lg_MapTrust(trust, (PRBool) (attr->type == CKA_TRUST_CLIENT_AUTH)); andre@3: andre@3: certHandle = lg_getCertDB(obj->sdb); andre@3: andre@3: if (certHandle == NULL) { andre@3: crv = CKR_TOKEN_WRITE_PROTECTED; andre@3: goto done; andre@3: } andre@3: andre@3: cert = lg_getCert(obj, certHandle); andre@3: if (cert == NULL) { andre@3: crv = CKR_OBJECT_HANDLE_INVALID; andre@3: goto done; andre@3: } andre@3: dbTrust = *cert->trust; andre@3: andre@3: switch (attr->type) { andre@3: case CKA_TRUST_EMAIL_PROTECTION: andre@3: dbTrust.emailFlags = flags | andre@3: (cert->trust->emailFlags & CERTDB_PRESERVE_TRUST_BITS); andre@3: break; andre@3: case CKA_TRUST_CODE_SIGNING: andre@3: dbTrust.objectSigningFlags = flags | andre@3: (cert->trust->objectSigningFlags & CERTDB_PRESERVE_TRUST_BITS); andre@3: break; andre@3: case CKA_TRUST_CLIENT_AUTH: andre@3: dbTrust.sslFlags = flags | (cert->trust->sslFlags & andre@3: (CERTDB_PRESERVE_TRUST_BITS|CERTDB_TRUSTED_CA)); andre@3: break; andre@3: case CKA_TRUST_SERVER_AUTH: andre@3: dbTrust.sslFlags = flags | (cert->trust->sslFlags & andre@3: (CERTDB_PRESERVE_TRUST_BITS|CERTDB_TRUSTED_CLIENT_CA)); andre@3: break; andre@3: default: andre@3: crv = CKR_ATTRIBUTE_READ_ONLY; andre@3: goto done; andre@3: } andre@3: andre@3: rv = nsslowcert_ChangeCertTrust(certHandle, cert, &dbTrust); andre@3: crv = (rv == SECSuccess) ? CKR_OK : CKR_DEVICE_ERROR; andre@3: done: andre@3: return crv; andre@3: } andre@3: andre@3: static CK_RV andre@3: lg_SetSingleAttribute(LGObjectCache *obj, const CK_ATTRIBUTE *attr, andre@3: PRBool *writePrivate) andre@3: { andre@3: CK_ATTRIBUTE attribLocal; andre@3: CK_RV crv; andre@3: andre@3: if ((attr->type == CKA_NETSCAPE_DB) && (obj->objclass == CKO_PRIVATE_KEY)) { andre@3: *writePrivate = PR_TRUE; andre@3: return CKR_OK; andre@3: } andre@3: andre@3: /* Make sure the attribute exists first */ andre@3: attribLocal.type = attr->type; andre@3: attribLocal.pValue = NULL; andre@3: attribLocal.ulValueLen = 0; andre@3: crv = lg_GetSingleAttribute(obj, &attribLocal); andre@3: if (crv != CKR_OK) { andre@3: return crv; andre@3: } andre@3: andre@3: /* if we are just setting it to the value we already have, andre@3: * allow it to happen. Let label setting go through so andre@3: * we have the opportunity to repair any database corruption. */ andre@3: if (attr->type != CKA_LABEL) { andre@3: if (lg_cmpAttribute(obj,attr)) { andre@3: return CKR_OK; andre@3: } andre@3: } andre@3: andre@3: crv = CKR_ATTRIBUTE_READ_ONLY; andre@3: switch (obj->objclass) { andre@3: case CKO_CERTIFICATE: andre@3: /* change NICKNAME, EMAIL, */ andre@3: crv = lg_SetCertAttribute(obj,attr->type, andre@3: attr->pValue,attr->ulValueLen); andre@3: break; andre@3: case CKO_NSS_CRL: andre@3: /* change URL */ andre@3: break; andre@3: case CKO_NSS_TRUST: andre@3: crv = lg_SetTrustAttribute(obj,attr); andre@3: break; andre@3: case CKO_PRIVATE_KEY: andre@3: case CKO_SECRET_KEY: andre@3: crv = lg_SetPrivateKeyAttribute(obj,attr->type, andre@3: attr->pValue,attr->ulValueLen, writePrivate); andre@3: break; andre@3: case CKO_PUBLIC_KEY: andre@3: crv = lg_SetPublicKeyAttribute(obj,attr->type, andre@3: attr->pValue,attr->ulValueLen, writePrivate); andre@3: break; andre@3: } andre@3: return crv; andre@3: } andre@3: andre@3: /* andre@3: * Fill in the attribute template based on the data in the database. andre@3: */ andre@3: CK_RV andre@3: lg_SetAttributeValue(SDB *sdb, CK_OBJECT_HANDLE handle, andre@3: const CK_ATTRIBUTE *templ, CK_ULONG count) andre@3: { andre@3: LGObjectCache *obj = lg_NewObjectCache(sdb, NULL, handle & ~LG_TOKEN_MASK); andre@3: CK_RV crv, crvCollect = CKR_OK; andre@3: PRBool writePrivate = PR_FALSE; andre@3: unsigned int i; andre@3: andre@3: if (obj == NULL) { andre@3: return CKR_OBJECT_HANDLE_INVALID; andre@3: } andre@3: andre@3: for (i=0; i < count; i++) { andre@3: crv = lg_SetSingleAttribute(obj, &templ[i], &writePrivate); andre@3: if (crvCollect == CKR_OK) crvCollect = crv; andre@3: } andre@3: andre@3: /* Write any collected changes out for private and secret keys. andre@3: * don't do the write for just the label */ andre@3: if (writePrivate) { andre@3: NSSLOWKEYPrivateKey *privKey = lg_GetPrivateKey(obj); andre@3: SECStatus rv = SECFailure; andre@3: char * label = lg_FindKeyNicknameByPublicKey(obj->sdb, &obj->dbKey); andre@3: andre@3: if (privKey) { andre@3: rv = nsslowkey_StoreKeyByPublicKeyAlg(lg_getKeyDB(sdb), privKey, andre@3: &obj->dbKey, label, sdb, PR_TRUE ); andre@3: } andre@3: if (rv != SECSuccess) { andre@3: crv = CKR_DEVICE_ERROR; andre@3: } andre@3: } andre@3: andre@3: lg_DestroyObjectCache(obj); andre@3: return crvCollect; andre@3: }