<commit_before>/*
 * The contents of this file are subject to the Mozilla Public
 * License Version 1.1 (the "License"); you may not use this file
 * except in compliance with the License. You may obtain a copy of
 * the License at http://www.mozilla.org/MPL/
 * 
 * Software distributed under the License is distributed on an "AS
 * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
 * implied. See the License for the specific language governing
 * rights and limitations under the License.
 * 
 * The Original Code is the Netscape security libraries.
 * 
 * The Initial Developer of the Original Code is Netscape
 * Communications Corporation.  Portions created by Netscape are 
 * Copyright (C) 1994-2000 Netscape Communications Corporation.  All
 * Rights Reserved.
 * 
 * Contributor(s):
 * 
 * Alternatively, the contents of this file may be used under the
 * terms of the GNU General Public License Version 2 or later (the
 * "GPL"), in which case the provisions of the GPL are applicable 
 * instead of those above.  If you wish to allow use of your 
 * version of this file only under the terms of the GPL and not to
 * allow others to use your version of this file under the MPL,
 * indicate your decision by deleting the provisions above and
 * replace them with the notice and other provisions required by
 * the GPL.  If you do not delete the provisions above, a recipient
 * may use your version of this file under either the MPL or the
 * GPL.
 */
/*
 * Internal PKCS #11 functions. Should only be called by pkcs11.c
 */
#include "pkcs11.h"
#include "pkcs11i.h"
#include "pcertt.h"
#include "lowkeyi.h"
#include "pcert.h"
#include "secasn1.h"
#include "blapi.h"

/*
 * ******************** Attribute Utilities *******************************
 */

/*
 * create a new attribute with type, value, and length. Space is allocated
 * to hold value.
 */
static PK11Attribute *
pk11_NewAttribute(PK11Object *object,
	CK_ATTRIBUTE_TYPE type, CK_VOID_PTR value, CK_ULONG len)
{
    PK11Attribute *attribute;

#ifdef PKCS11_STATIC_ATTRIBUTES
    PK11SessionObject *so = pk11_narrowToSessionObject(object);
    int index;

    if (so == NULL)  {
	/* allocate new attribute in a buffer */
	PORT_Assert(0);
    }
    /* 
     * PKCS11_STATIC_ATTRIBUTES attempts to keep down contention on Malloc and Arena locks
     * by limiting the number of these calls on high traversed paths. this
     * is done for attributes by 'allocating' them from a pool already allocated
     * by the parent object.
     */
    PK11_USE_THREADS(PZ_Lock(so->attributeLock);)
    index = so->nextAttr++;
    PK11_USE_THREADS(PZ_Unlock(so->attributeLock);)
    PORT_Assert(index < MAX_OBJS_ATTRS);
    if (index >= MAX_OBJS_ATTRS) return NULL;

    attribute = &so->attrList[index];
    attribute->attrib.type = type;
    attribute->freeAttr = PR_FALSE;
    attribute->freeData = PR_FALSE;
    if (value) {
        if (len <= ATTR_SPACE) {
	    attribute->attrib.pValue = attribute->space;
	} else {
	    attribute->attrib.pValue = PORT_Alloc(len);
    	    attribute->freeData = PR_TRUE;
	}
	if (attribute->attrib.pValue == NULL) {
	    return NULL;
	}
	PORT_Memcpy(attribute->attrib.pValue,value,len);
	attribute->attrib.ulValueLen = len;
    } else {
	attribute->attrib.pValue = NULL;
	attribute->attrib.ulValueLen = 0;
    }
#else
#ifdef PKCS11_REF_COUNT_ATTRIBUTES
    attribute = (PK11Attribute*)PORT_Alloc(sizeof(PK11Attribute));
    attribute->freeAttr = PR_TRUE;
#else
    attribute = (PK11Attribute*)PORT_ArenaAlloc(object->arena,sizeof(PK11Attribute));
    attribute->freeAttr = PR_FALSE;
#endif /* PKCS11_REF_COUNT_ATTRIBUTES */
    if (attribute == NULL) return NULL;
    attribute->freeData = PR_FALSE;

    if (value) {
#ifdef PKCS11_REF_COUNT_ATTRIBUTES
	attribute->attrib.pValue = PORT_Alloc(len);
	attribute->freeData = PR_TRUE;
#else
	attribute->attrib.pValue = PORT_ArenaAlloc(object->arena,len);
#endif /* PKCS11_REF_COUNT_ATTRIBUTES */
	if (attribute->attrib.pValue == NULL) {
#ifdef PKCS11_REF_COUNT_ATTRIBUTES
	    PORT_Free(attribute);
#endif /* PKCS11_REF_COUNT_ATTRIBUTES */
	    return NULL;
	}
	PORT_Memcpy(attribute->attrib.pValue,value,len);
	attribute->attrib.ulValueLen = len;
    } else {
	attribute->attrib.pValue = NULL;
	attribute->attrib.ulValueLen = 0;
    }
#endif /* PKCS11_STATIC_ATTRIBUTES */
    attribute->attrib.type = type;
    attribute->handle = type;
    attribute->next = attribute->prev = NULL;
#ifdef PKCS11_REF_COUNT_ATTRIBUTES
    attribute->refCount = 1;
#ifdef PKCS11_USE_THREADS
    attribute->refLock = PZ_NewLock(nssILockRefLock);
    if (attribute->refLock == NULL) {
	if (attribute->attrib.pValue) PORT_Free(attribute->attrib.pValue);
	PORT_Free(attribute);
	return NULL;
    }
#else
    attribute->refLock = NULL;
#endif
#endif /* PKCS11_REF_COUNT_ATTRIBUTES */
    return attribute;
}

static PK11Attribute *
pk11_NewTokenAttribute(CK_ATTRIBUTE_TYPE type, CK_VOID_PTR value,
						CK_ULONG len, PRBool copy)
{
    PK11Attribute *attribute;

    attribute = (PK11Attribute*)PORT_Alloc(sizeof(PK11Attribute));

    if (attribute == NULL) return NULL;
    attribute->attrib.type = type;
    attribute->handle = type;
    attribute->next = attribute->prev = NULL;
    attribute->freeAttr = PR_TRUE;
    attribute->freeData = PR_FALSE;
#ifdef PKCS11_REF_COUNT_ATTRIBUTES
    attribute->refCount = 1;
#ifdef PKCS11_USE_THREADS
    attribute->refLock = PZ_NewLock(nssILockRefLock);
    if (attribute->refLock == NULL) {
	PORT_Free(attribute);
	return NULL;
    }
#else
    attribute->refLock = NULL;
#endif
#endif /* PKCS11_REF_COUNT_ATTRIBUTES */
    attribute->attrib.type = type;
    if (!copy) {
	attribute->attrib.pValue = value;
	attribute->attrib.ulValueLen = len;
	return attribute;
    }

    if (value) {
#ifdef PKCS11_STATIC_ATTRIBUTES
        if (len <= ATTR_SPACE) {
	    attribute->attrib.pValue = attribute->space;
	} else {
	    attribute->attrib.pValue = PORT_Alloc(len);
	    attribute->freeData = PR_TRUE;
	}
#else
	attribute->attrib.pValue = PORT_Alloc(len);
	attribute->freeData = PR_TRUE;
#endif
	if (attribute->attrib.pValue == NULL) {
#ifdef PKCS11_REF_COUNT_ATTRIBUTES
	    if (attribute->refLock) {
		PK11_USE_THREADS(PZ_DestroyLock(attribute->refLock);)
	    }
#endif
	    PORT_Free(attribute);
	    return NULL;
	}
	PORT_Memcpy(attribute->attrib.pValue,value,len);
	attribute->attrib.ulValueLen = len;
    } else {
	attribute->attrib.pValue = NULL;
	attribute->attrib.ulValueLen = 0;
    }
    return attribute;
}

static PK11Attribute *
pk11_NewTokenAttributeSigned(CK_ATTRIBUTE_TYPE type, CK_VOID_PTR value, 
						CK_ULONG len, PRBool copy)
{
    unsigned char * dval = (unsigned char *)value;
    if (*dval == 0) {
	dval++;
	len--;
    }
    return pk11_NewTokenAttribute(type,dval,len,copy);
}

/*
 * Free up all the memory associated with an attribute. Reference count
 * must be zero to call this.
 */
static void
pk11_DestroyAttribute(PK11Attribute *attribute)
{
#ifdef PKCS11_REF_COUNT_ATTRIBUTES
    PORT_Assert(attribute->refCount == 0);
    PK11_USE_THREADS(PZ_DestroyLock(attribute->refLock);)
#endif
    if (attribute->freeData) {
	if (attribute->attrib.pValue) {
	    /* clear out the data in the attribute value... it may have been
	     * sensitive data */
	    PORT_Memset(attribute->attrib.pValue, 0,
						attribute->attrib.ulValueLen);
	}
	PORT_Free(attribute->attrib.pValue);
    }
    PORT_Free(attribute);
}

/*
 * release a reference to an attribute structure
 */
void
pk11_FreeAttribute(PK11Attribute *attribute)
{
#ifdef PKCS11_REF_COUNT_ATTRIBUTES
    PRBool destroy = PR_FALSE;
#endif

    if (attribute->freeAttr) {
	pk11_DestroyAttribute(attribute);
	return;
    }

#ifdef PKCS11_REF_COUNT_ATTRIBUTES
    PK11_USE_THREADS(PZ_Lock(attribute->refLock);)
    if (attribute->refCount == 1) destroy = PR_TRUE;
    attribute->refCount--;
    PK11_USE_THREADS(PZ_Unlock(attribute->refLock);)

    if (destroy) pk11_DestroyAttribute(attribute);
#endif
}

#ifdef PKCS11_REF_COUNT_ATTRIBUTES
#define PK11_DEF_ATTRIBUTE(value,len) \
   { NULL, NULL, PR_FALSE, PR_FALSE, 1, NULL, 0, { 0, value, len } }

#else
#define PK11_DEF_ATTRIBUTE(value,len) \
   { NULL, NULL, PR_FALSE, PR_FALSE, 0, { 0, value, len } }
#endif

CK_BBOOL pk11_staticTrueValue = CK_TRUE;
CK_BBOOL pk11_staticFalseValue = CK_FALSE;
static const PK11Attribute pk11_StaticTrueAttr = 
  PK11_DEF_ATTRIBUTE(&pk11_staticTrueValue,sizeof(pk11_staticTrueValue));
static const PK11Attribute pk11_StaticFalseAttr = 
  PK11_DEF_ATTRIBUTE(&pk11_staticFalseValue,sizeof(pk11_staticFalseValue));
static const PK11Attribute pk11_StaticNullAttr = PK11_DEF_ATTRIBUTE(NULL,0);

CK_CERTIFICATE_TYPE pk11_staticX509Value = CKC_X_509;
static const PK11Attribute pk11_StaticX509Attr =
  PK11_DEF_ATTRIBUTE(&pk11_staticX509Value, sizeof(pk11_staticX509Value));
CK_TRUST pk11_staticTrustedValue = CKT_NETSCAPE_TRUSTED;
CK_TRUST pk11_staticTrustedDelegatorValue = CKT_NETSCAPE_TRUSTED_DELEGATOR;
CK_TRUST pk11_staticUnTrustedValue = CKT_NETSCAPE_UNTRUSTED;
CK_TRUST pk11_staticTrustUnknownValue = CKT_NETSCAPE_TRUST_UNKNOWN;
CK_TRUST pk11_staticValidPeerValue = CKT_NETSCAPE_VALID;
CK_TRUST pk11_staticMustVerifyValue = CKT_NETSCAPE_MUST_VERIFY;
static const PK11Attribute pk11_StaticTrustedAttr =
  PK11_DEF_ATTRIBUTE(&pk11_staticTrustedValue,
				sizeof(pk11_staticTrustedValue));
static const PK11Attribute pk11_StaticTrustedDelegatorAttr =
  PK11_DEF_ATTRIBUTE(&pk11_staticTrustedDelegatorValue,
				sizeof(pk11_staticTrustedDelegatorValue));
static const PK11Attribute pk11_StaticUnTrustedAttr =
  PK11_DEF_ATTRIBUTE(&pk11_staticUnTrustedValue,
				sizeof(pk11_staticUnTrustedValue));
static const PK11Attribute pk11_StaticTrustUnknownAttr =
  PK11_DEF_ATTRIBUTE(&pk11_staticTrustUnknownValue,
				sizeof(pk11_staticTrustUnknownValue));
static const PK11Attribute pk11_StaticValidPeerAttr =
  PK11_DEF_ATTRIBUTE(&pk11_staticValidPeerValue,
				sizeof(pk11_staticValidPeerValue));
static const PK11Attribute pk11_StaticMustVerifyAttr =
  PK11_DEF_ATTRIBUTE(&pk11_staticMustVerifyValue,
				sizeof(pk11_staticMustVerifyValue));

static void pk11_FreeItem(SECItem *item)
{
    SECITEM_FreeItem(item, PR_TRUE);
}

static certDBEntrySMime *
pk11_getSMime(PK11TokenObject *object)
{
    certDBEntrySMime *entry;

    if (object->obj.objclass != CKO_NETSCAPE_SMIME) {
	return NULL;
    }
    if (object->obj.objectInfo) {
	return (certDBEntrySMime *)object->obj.objectInfo;
    }

    entry = nsslowcert_ReadDBSMimeEntry(object->obj.slot->certDB,
						(char *)object->dbKey.data);
    object->obj.objectInfo = (void *)entry;
    object->obj.infoFree = (PK11Free) nsslowcert_DestroyDBEntry;
    return entry;
}

static SECItem *
pk11_getCrl(PK11TokenObject *object)
{
    SECItem *crl;
    PRBool isKrl;

    if (object->obj.objclass != CKO_NETSCAPE_CRL) {
	return NULL;
    }
    if (object->obj.objectInfo) {
	return (SECItem *)object->obj.objectInfo;
    }

    isKrl = (PRBool) object->obj.handle == PK11_TOKEN_KRL_HANDLE;
    crl = nsslowcert_FindCrlByKey(object->obj.slot->certDB,&object->dbKey,
								NULL,isKrl);
    object->obj.objectInfo = (void *)crl;
    object->obj.infoFree = (PK11Free) pk11_FreeItem;
    return crl;
}

static char *
pk11_getUrl(PK11TokenObject *object)
{
    SECItem *crl;
    PRBool isKrl;
    char *url = NULL;

    if (object->obj.objclass != CKO_NETSCAPE_CRL) {
	return NULL;
    }

    isKrl = (PRBool) object->obj.handle == PK11_TOKEN_KRL_HANDLE;
    crl = nsslowcert_FindCrlByKey(object->obj.slot->certDB,&object->dbKey,
								&url,isKrl);
    if (object->obj.objectInfo == NULL) {
	object->obj.objectInfo = (void *)crl;
	object->obj.infoFree = (PK11Free) pk11_FreeItem;
    } else {
	if (crl) SECITEM_FreeItem(crl,PR_TRUE);
    }
    return url;
}

static NSSLOWCERTCertificate *
pk11_getCert(PK11TokenObject *object)
{
    NSSLOWCERTCertificate *cert;

    if ((object->obj.objclass != CKO_CERTIFICATE) &&
	 		(object->obj.objclass != CKO_NETSCAPE_TRUST)) {
	return NULL;
    }
    if (object->obj.objectInfo) {
	return (NSSLOWCERTCertificate *)object->obj.objectInfo;
    }
    cert = nsslowcert_FindCertByKey(object->obj.slot->certDB,&object->dbKey);
    object->obj.objectInfo = (void *)cert;
    object->obj.infoFree = (PK11Free) nsslowcert_DestroyCertificate ;
    return cert;
}

static NSSLOWKEYPublicKey *
pk11_GetPublicKey(PK11TokenObject *object)
{
    NSSLOWKEYPublicKey *pubKey;
    NSSLOWKEYPrivateKey *privKey;

    if (object->obj.objclass != CKO_PUBLIC_KEY) {
	return NULL;
    }
    if (object->obj.objectInfo) {
	return (NSSLOWKEYPublicKey *)object->obj.objectInfo;
    }
    privKey = nsslowkey_FindKeyByPublicKey(object->obj.slot->keyDB,
				&object->dbKey, object->obj.slot->password);
    if (privKey == NULL) {
	return NULL;
    }
    pubKey = nsslowkey_ConvertToPublicKey(privKey);
    nsslowkey_DestroyPrivateKey(privKey);
    object->obj.objectInfo = (void *) pubKey;
    object->obj.infoFree = (PK11Free) nsslowkey_DestroyPublicKey ;
    return pubKey;
}

static NSSLOWKEYPrivateKey *
pk11_GetPrivateKey(PK11TokenObject *object)
{
    NSSLOWKEYPrivateKey *privKey;

    if ((object->obj.objclass != CKO_PRIVATE_KEY) && 
			(object->obj.objclass != CKO_SECRET_KEY)) {
	return NULL;
    }
    if (object->obj.objectInfo) {
	return (NSSLOWKEYPrivateKey *)object->obj.objectInfo;
    }
    privKey = nsslowkey_FindKeyByPublicKey(object->obj.slot->keyDB,
				&object->dbKey, object->obj.slot->password);
    if (privKey == NULL) {
	return NULL;
    }
    object->obj.objectInfo = (void *) privKey;
    object->obj.infoFree = (PK11Free) nsslowkey_DestroyPrivateKey ;
    return privKey;
}

/* pk11_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 *
pk11_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;
    default:
	    break;
    }
    return pubItem;
}

static const SEC_ASN1Template pk11_SerialTemplate[] = {
    { SEC_ASN1_INTEGER, offsetof(NSSLOWCERTCertificate,serialNumber) },
    { 0 }
};

static PK11Attribute *
pk11_FindRSAPublicKeyAttribute(NSSLOWKEYPublicKey *key, CK_ATTRIBUTE_TYPE type)
{
    unsigned char hash[SHA1_LENGTH];
    CK_KEY_TYPE keyType = CKK_RSA;

    switch (type) {
    case CKA_KEY_TYPE:
	return pk11_NewTokenAttribute(type,&keyType,sizeof(keyType), PR_TRUE);
    case CKA_ID:
	SHA1_HashBuf(hash,key->u.rsa.modulus.data,key->u.rsa.modulus.len);
	return pk11_NewTokenAttribute(type,hash,SHA1_LENGTH, PR_TRUE);
    case CKA_DERIVE:
	return (PK11Attribute *) &pk11_StaticFalseAttr;
    case CKA_ENCRYPT:
    case CKA_VERIFY:
    case CKA_VERIFY_RECOVER:
    case CKA_WRAP:
	return (PK11Attribute *) &pk11_StaticTrueAttr;
    case CKA_MODULUS:
	return pk11_NewTokenAttributeSigned(type,key->u.rsa.modulus.data,
					key->u.rsa.modulus.len, PR_FALSE);
    case CKA_PUBLIC_EXPONENT:
	return pk11_NewTokenAttributeSigned(type,key->u.rsa.publicExponent.data,
				key->u.rsa.publicExponent.len, PR_FALSE);
    default:
	break;
    }
    return NULL;
}

static PK11Attribute *
pk11_FindDSAPublicKeyAttribute(NSSLOWKEYPublicKey *key, CK_ATTRIBUTE_TYPE type)
{
    unsigned char hash[SHA1_LENGTH];
    CK_KEY_TYPE keyType = CKK_DSA;

    switch (type) {
    case CKA_KEY_TYPE:
	return pk11_NewTokenAttribute(type,&keyType,sizeof(keyType), PR_TRUE);
    case CKA_ID:
	SHA1_HashBuf(hash,key->u.dsa.publicValue.data,
						key->u.dsa.publicValue.len);
	return pk11_NewTokenAttribute(type,hash,SHA1_LENGTH, PR_TRUE);
    case CKA_DERIVE:
    case CKA_ENCRYPT:
    case CKA_VERIFY_RECOVER:
    case CKA_WRAP:
	return (PK11Attribute *) &pk11_StaticFalseAttr;
    case CKA_VERIFY:
	return (PK11Attribute *) &pk11_StaticTrueAttr;
    case CKA_VALUE:
	return pk11_NewTokenAttributeSigned(type,key->u.dsa.publicValue.data,
					key->u.dsa.publicValue.len, PR_FALSE);
    case CKA_PRIME:
	return pk11_NewTokenAttributeSigned(type,key->u.dsa.params.prime.data,
					key->u.dsa.params.prime.len, PR_FALSE);
    case CKA_SUBPRIME:
	return pk11_NewTokenAttributeSigned(type,
				key->u.dsa.params.subPrime.data,
				key->u.dsa.params.subPrime.len, PR_FALSE);
    case CKA_BASE:
	return pk11_NewTokenAttributeSigned(type,key->u.dsa.params.base.data,
					key->u.dsa.params.base.len, PR_FALSE);
    default:
	break;
    }
    return NULL;
}

static PK11Attribute *
pk11_FindDHPublicKeyAttribute(NSSLOWKEYPublicKey *key, CK_ATTRIBUTE_TYPE type)
{
    unsigned char hash[SHA1_LENGTH];
    CK_KEY_TYPE keyType = CKK_DH;

    switch (type) {
    case CKA_KEY_TYPE:
	return pk11_NewTokenAttribute(type,&keyType,sizeof(keyType), PR_TRUE);
    case CKA_ID:
	SHA1_HashBuf(hash,key->u.dh.publicValue.data,key->u.dh.publicValue.len);
	return pk11_NewTokenAttribute(type,hash,SHA1_LENGTH, PR_TRUE);
    case CKA_DERIVE:
	return (PK11Attribute *) &pk11_StaticTrueAttr;
    case CKA_ENCRYPT:
    case CKA_VERIFY:
    case CKA_VERIFY_RECOVER:
    case CKA_WRAP:
	return (PK11Attribute *) &pk11_StaticFalseAttr;
    case CKA_VALUE:
	return pk11_NewTokenAttributeSigned(type,key->u.dh.publicValue.data,
					key->u.dh.publicValue.len, PR_FALSE);
    case CKA_PRIME:
	return pk11_NewTokenAttributeSigned(type,key->u.dh.prime.data,
					key->u.dh.prime.len, PR_FALSE);
    case CKA_BASE:
	return pk11_NewTokenAttributeSigned(type,key->u.dh.base.data,
					key->u.dh.base.len, PR_FALSE);
    default:
	break;
    }
    return NULL;
}

static PK11Attribute *
pk11_FindPublicKeyAttribute(PK11TokenObject *object, CK_ATTRIBUTE_TYPE type)
{
    NSSLOWKEYPublicKey *key;
    PK11Attribute *att = NULL;
    char *label;

    switch (type) {
    case CKA_PRIVATE:
    case CKA_SENSITIVE:
    case CKA_ALWAYS_SENSITIVE:
    case CKA_NEVER_EXTRACTABLE:
	return (PK11Attribute *) &pk11_StaticFalseAttr;
    case CKA_MODIFIABLE:
    case CKA_EXTRACTABLE:
	return (PK11Attribute *) &pk11_StaticTrueAttr;
    case CKA_LABEL:
        label = nsslowkey_FindKeyNicknameByPublicKey(object->obj.slot->keyDB,
				&object->dbKey, object->obj.slot->password);
	if (label == NULL) {
	   return (PK11Attribute *)&pk11_StaticNullAttr;
	}
	att = pk11_NewTokenAttribute(type,label,PORT_Strlen(label)+1, PR_TRUE);
	PORT_Free(label);
	return att;
    default:
	break;
    }

    key = pk11_GetPublicKey(object);
    if (key == NULL) {
	return NULL;
    }

    switch (key->keyType) {
    case NSSLOWKEYRSAKey:
	return pk11_FindRSAPublicKeyAttribute(key,type);
    case NSSLOWKEYDSAKey:
	return pk11_FindDSAPublicKeyAttribute(key,type);
    case NSSLOWKEYDHKey:
	return pk11_FindDHPublicKeyAttribute(key,type);
    default:
	break;
    }

    return NULL;
}

static PK11Attribute *
pk11_FindSecretKeyAttribute(PK11TokenObject *object, CK_ATTRIBUTE_TYPE type)
{
    NSSLOWKEYPrivateKey *key;
    char *label;
    PK11Attribute *att;

    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:
	return (PK11Attribute *) &pk11_StaticTrueAttr;
    case CKA_NEVER_EXTRACTABLE:
    case CKA_MODIFIABLE:
	return (PK11Attribute *) &pk11_StaticFalseAttr;
    case CKA_LABEL:
        label = nsslowkey_FindKeyNicknameByPublicKey(object->obj.slot->keyDB,
				&object->dbKey, object->obj.slot->password);
	if (label == NULL) {
	   return (PK11Attribute *)&pk11_StaticNullAttr;
	}
	att = pk11_NewTokenAttribute(type,label,PORT_Strlen(label)+1, PR_TRUE);
	PORT_Free(label);
	return att;
    default:
	break;
    }

    key = pk11_GetPrivateKey(object);
    if (key == NULL) {
	return NULL;
    }
    switch (type) {
    case CKA_KEY_TYPE:
	return pk11_NewTokenAttribute(type,key->u.rsa.coefficient.data,
					key->u.rsa.coefficient.len, PR_FALSE);
    case CKA_VALUE:
	return pk11_NewTokenAttribute(type,key->u.rsa.privateExponent.data,
				key->u.rsa.privateExponent.len, PR_FALSE);
    }

    return NULL;
}

static PK11Attribute *
pk11_FindRSAPrivateKeyAttribute(NSSLOWKEYPrivateKey *key,
							 CK_ATTRIBUTE_TYPE type)
{
    unsigned char hash[SHA1_LENGTH];
    CK_KEY_TYPE keyType = CKK_RSA;

    switch (type) {
    case CKA_KEY_TYPE:
	return pk11_NewTokenAttribute(type,&keyType,sizeof(keyType), PR_TRUE);
    case CKA_ID:
	SHA1_HashBuf(hash,key->u.rsa.modulus.data,key->u.rsa.modulus.len);
	return pk11_NewTokenAttribute(type,hash,SHA1_LENGTH, PR_TRUE);
    case CKA_DERIVE:
	return (PK11Attribute *) &pk11_StaticFalseAttr;
    case CKA_DECRYPT:
    case CKA_SIGN:<commit_msg>fix SDR on big-endian platforms.  The leading zeros in the RSA coefficient have been stripped, but PKCS#11 needs them back in order to form a CK_ULONG correctly.<commit_after>/*
 * The contents of this file are subject to the Mozilla Public
 * License Version 1.1 (the "License"); you may not use this file
 * except in compliance with the License. You may obtain a copy of
 * the License at http://www.mozilla.org/MPL/
 * 
 * Software distributed under the License is distributed on an "AS
 * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
 * implied. See the License for the specific language governing
 * rights and limitations under the License.
 * 
 * The Original Code is the Netscape security libraries.
 * 
 * The Initial Developer of the Original Code is Netscape
 * Communications Corporation.  Portions created by Netscape are 
 * Copyright (C) 1994-2000 Netscape Communications Corporation.  All
 * Rights Reserved.
 * 
 * Contributor(s):
 * 
 * Alternatively, the contents of this file may be used under the
 * terms of the GNU General Public License Version 2 or later (the
 * "GPL"), in which case the provisions of the GPL are applicable 
 * instead of those above.  If you wish to allow use of your 
 * version of this file only under the terms of the GPL and not to
 * allow others to use your version of this file under the MPL,
 * indicate your decision by deleting the provisions above and
 * replace them with the notice and other provisions required by
 * the GPL.  If you do not delete the provisions above, a recipient
 * may use your version of this file under either the MPL or the
 * GPL.
 */
/*
 * Internal PKCS #11 functions. Should only be called by pkcs11.c
 */
#include "pkcs11.h"
#include "pkcs11i.h"
#include "pcertt.h"
#include "lowkeyi.h"
#include "pcert.h"
#include "secasn1.h"
#include "blapi.h"

/*
 * ******************** Attribute Utilities *******************************
 */

/*
 * create a new attribute with type, value, and length. Space is allocated
 * to hold value.
 */
static PK11Attribute *
pk11_NewAttribute(PK11Object *object,
	CK_ATTRIBUTE_TYPE type, CK_VOID_PTR value, CK_ULONG len)
{
    PK11Attribute *attribute;

#ifdef PKCS11_STATIC_ATTRIBUTES
    PK11SessionObject *so = pk11_narrowToSessionObject(object);
    int index;

    if (so == NULL)  {
	/* allocate new attribute in a buffer */
	PORT_Assert(0);
    }
    /* 
     * PKCS11_STATIC_ATTRIBUTES attempts to keep down contention on Malloc and Arena locks
     * by limiting the number of these calls on high traversed paths. this
     * is done for attributes by 'allocating' them from a pool already allocated
     * by the parent object.
     */
    PK11_USE_THREADS(PZ_Lock(so->attributeLock);)
    index = so->nextAttr++;
    PK11_USE_THREADS(PZ_Unlock(so->attributeLock);)
    PORT_Assert(index < MAX_OBJS_ATTRS);
    if (index >= MAX_OBJS_ATTRS) return NULL;

    attribute = &so->attrList[index];
    attribute->attrib.type = type;
    attribute->freeAttr = PR_FALSE;
    attribute->freeData = PR_FALSE;
    if (value) {
        if (len <= ATTR_SPACE) {
	    attribute->attrib.pValue = attribute->space;
	} else {
	    attribute->attrib.pValue = PORT_Alloc(len);
    	    attribute->freeData = PR_TRUE;
	}
	if (attribute->attrib.pValue == NULL) {
	    return NULL;
	}
	PORT_Memcpy(attribute->attrib.pValue,value,len);
	attribute->attrib.ulValueLen = len;
    } else {
	attribute->attrib.pValue = NULL;
	attribute->attrib.ulValueLen = 0;
    }
#else
#ifdef PKCS11_REF_COUNT_ATTRIBUTES
    attribute = (PK11Attribute*)PORT_Alloc(sizeof(PK11Attribute));
    attribute->freeAttr = PR_TRUE;
#else
    attribute = (PK11Attribute*)PORT_ArenaAlloc(object->arena,sizeof(PK11Attribute));
    attribute->freeAttr = PR_FALSE;
#endif /* PKCS11_REF_COUNT_ATTRIBUTES */
    if (attribute == NULL) return NULL;
    attribute->freeData = PR_FALSE;

    if (value) {
#ifdef PKCS11_REF_COUNT_ATTRIBUTES
	attribute->attrib.pValue = PORT_Alloc(len);
	attribute->freeData = PR_TRUE;
#else
	attribute->attrib.pValue = PORT_ArenaAlloc(object->arena,len);
#endif /* PKCS11_REF_COUNT_ATTRIBUTES */
	if (attribute->attrib.pValue == NULL) {
#ifdef PKCS11_REF_COUNT_ATTRIBUTES
	    PORT_Free(attribute);
#endif /* PKCS11_REF_COUNT_ATTRIBUTES */
	    return NULL;
	}
	PORT_Memcpy(attribute->attrib.pValue,value,len);
	attribute->attrib.ulValueLen = len;
    } else {
	attribute->attrib.pValue = NULL;
	attribute->attrib.ulValueLen = 0;
    }
#endif /* PKCS11_STATIC_ATTRIBUTES */
    attribute->attrib.type = type;
    attribute->handle = type;
    attribute->next = attribute->prev = NULL;
#ifdef PKCS11_REF_COUNT_ATTRIBUTES
    attribute->refCount = 1;
#ifdef PKCS11_USE_THREADS
    attribute->refLock = PZ_NewLock(nssILockRefLock);
    if (attribute->refLock == NULL) {
	if (attribute->attrib.pValue) PORT_Free(attribute->attrib.pValue);
	PORT_Free(attribute);
	return NULL;
    }
#else
    attribute->refLock = NULL;
#endif
#endif /* PKCS11_REF_COUNT_ATTRIBUTES */
    return attribute;
}

static PK11Attribute *
pk11_NewTokenAttribute(CK_ATTRIBUTE_TYPE type, CK_VOID_PTR value,
						CK_ULONG len, PRBool copy)
{
    PK11Attribute *attribute;

    attribute = (PK11Attribute*)PORT_Alloc(sizeof(PK11Attribute));

    if (attribute == NULL) return NULL;
    attribute->attrib.type = type;
    attribute->handle = type;
    attribute->next = attribute->prev = NULL;
    attribute->freeAttr = PR_TRUE;
    attribute->freeData = PR_FALSE;
#ifdef PKCS11_REF_COUNT_ATTRIBUTES
    attribute->refCount = 1;
#ifdef PKCS11_USE_THREADS
    attribute->refLock = PZ_NewLock(nssILockRefLock);
    if (attribute->refLock == NULL) {
	PORT_Free(attribute);
	return NULL;
    }
#else
    attribute->refLock = NULL;
#endif
#endif /* PKCS11_REF_COUNT_ATTRIBUTES */
    attribute->attrib.type = type;
    if (!copy) {
	attribute->attrib.pValue = value;
	attribute->attrib.ulValueLen = len;
	return attribute;
    }

    if (value) {
#ifdef PKCS11_STATIC_ATTRIBUTES
        if (len <= ATTR_SPACE) {
	    attribute->attrib.pValue = attribute->space;
	} else {
	    attribute->attrib.pValue = PORT_Alloc(len);
	    attribute->freeData = PR_TRUE;
	}
#else
	attribute->attrib.pValue = PORT_Alloc(len);
	attribute->freeData = PR_TRUE;
#endif
	if (attribute->attrib.pValue == NULL) {
#ifdef PKCS11_REF_COUNT_ATTRIBUTES
	    if (attribute->refLock) {
		PK11_USE_THREADS(PZ_DestroyLock(attribute->refLock);)
	    }
#endif
	    PORT_Free(attribute);
	    return NULL;
	}
	PORT_Memcpy(attribute->attrib.pValue,value,len);
	attribute->attrib.ulValueLen = len;
    } else {
	attribute->attrib.pValue = NULL;
	attribute->attrib.ulValueLen = 0;
    }
    return attribute;
}

static PK11Attribute *
pk11_NewTokenAttributeSigned(CK_ATTRIBUTE_TYPE type, CK_VOID_PTR value, 
						CK_ULONG len, PRBool copy)
{
    unsigned char * dval = (unsigned char *)value;
    if (*dval == 0) {
	dval++;
	len--;
    }
    return pk11_NewTokenAttribute(type,dval,len,copy);
}

/*
 * Free up all the memory associated with an attribute. Reference count
 * must be zero to call this.
 */
static void
pk11_DestroyAttribute(PK11Attribute *attribute)
{
#ifdef PKCS11_REF_COUNT_ATTRIBUTES
    PORT_Assert(attribute->refCount == 0);
    PK11_USE_THREADS(PZ_DestroyLock(attribute->refLock);)
#endif
    if (attribute->freeData) {
	if (attribute->attrib.pValue) {
	    /* clear out the data in the attribute value... it may have been
	     * sensitive data */
	    PORT_Memset(attribute->attrib.pValue, 0,
						attribute->attrib.ulValueLen);
	}
	PORT_Free(attribute->attrib.pValue);
    }
    PORT_Free(attribute);
}

/*
 * release a reference to an attribute structure
 */
void
pk11_FreeAttribute(PK11Attribute *attribute)
{
#ifdef PKCS11_REF_COUNT_ATTRIBUTES
    PRBool destroy = PR_FALSE;
#endif

    if (attribute->freeAttr) {
	pk11_DestroyAttribute(attribute);
	return;
    }

#ifdef PKCS11_REF_COUNT_ATTRIBUTES
    PK11_USE_THREADS(PZ_Lock(attribute->refLock);)
    if (attribute->refCount == 1) destroy = PR_TRUE;
    attribute->refCount--;
    PK11_USE_THREADS(PZ_Unlock(attribute->refLock);)

    if (destroy) pk11_DestroyAttribute(attribute);
#endif
}

#ifdef PKCS11_REF_COUNT_ATTRIBUTES
#define PK11_DEF_ATTRIBUTE(value,len) \
   { NULL, NULL, PR_FALSE, PR_FALSE, 1, NULL, 0, { 0, value, len } }

#else
#define PK11_DEF_ATTRIBUTE(value,len) \
   { NULL, NULL, PR_FALSE, PR_FALSE, 0, { 0, value, len } }
#endif

CK_BBOOL pk11_staticTrueValue = CK_TRUE;
CK_BBOOL pk11_staticFalseValue = CK_FALSE;
static const PK11Attribute pk11_StaticTrueAttr = 
  PK11_DEF_ATTRIBUTE(&pk11_staticTrueValue,sizeof(pk11_staticTrueValue));
static const PK11Attribute pk11_StaticFalseAttr = 
  PK11_DEF_ATTRIBUTE(&pk11_staticFalseValue,sizeof(pk11_staticFalseValue));
static const PK11Attribute pk11_StaticNullAttr = PK11_DEF_ATTRIBUTE(NULL,0);

CK_CERTIFICATE_TYPE pk11_staticX509Value = CKC_X_509;
static const PK11Attribute pk11_StaticX509Attr =
  PK11_DEF_ATTRIBUTE(&pk11_staticX509Value, sizeof(pk11_staticX509Value));
CK_TRUST pk11_staticTrustedValue = CKT_NETSCAPE_TRUSTED;
CK_TRUST pk11_staticTrustedDelegatorValue = CKT_NETSCAPE_TRUSTED_DELEGATOR;
CK_TRUST pk11_staticUnTrustedValue = CKT_NETSCAPE_UNTRUSTED;
CK_TRUST pk11_staticTrustUnknownValue = CKT_NETSCAPE_TRUST_UNKNOWN;
CK_TRUST pk11_staticValidPeerValue = CKT_NETSCAPE_VALID;
CK_TRUST pk11_staticMustVerifyValue = CKT_NETSCAPE_MUST_VERIFY;
static const PK11Attribute pk11_StaticTrustedAttr =
  PK11_DEF_ATTRIBUTE(&pk11_staticTrustedValue,
				sizeof(pk11_staticTrustedValue));
static const PK11Attribute pk11_StaticTrustedDelegatorAttr =
  PK11_DEF_ATTRIBUTE(&pk11_staticTrustedDelegatorValue,
				sizeof(pk11_staticTrustedDelegatorValue));
static const PK11Attribute pk11_StaticUnTrustedAttr =
  PK11_DEF_ATTRIBUTE(&pk11_staticUnTrustedValue,
				sizeof(pk11_staticUnTrustedValue));
static const PK11Attribute pk11_StaticTrustUnknownAttr =
  PK11_DEF_ATTRIBUTE(&pk11_staticTrustUnknownValue,
				sizeof(pk11_staticTrustUnknownValue));
static const PK11Attribute pk11_StaticValidPeerAttr =
  PK11_DEF_ATTRIBUTE(&pk11_staticValidPeerValue,
				sizeof(pk11_staticValidPeerValue));
static const PK11Attribute pk11_StaticMustVerifyAttr =
  PK11_DEF_ATTRIBUTE(&pk11_staticMustVerifyValue,
				sizeof(pk11_staticMustVerifyValue));

static void pk11_FreeItem(SECItem *item)
{
    SECITEM_FreeItem(item, PR_TRUE);
}

static certDBEntrySMime *
pk11_getSMime(PK11TokenObject *object)
{
    certDBEntrySMime *entry;

    if (object->obj.objclass != CKO_NETSCAPE_SMIME) {
	return NULL;
    }
    if (object->obj.objectInfo) {
	return (certDBEntrySMime *)object->obj.objectInfo;
    }

    entry = nsslowcert_ReadDBSMimeEntry(object->obj.slot->certDB,
						(char *)object->dbKey.data);
    object->obj.objectInfo = (void *)entry;
    object->obj.infoFree = (PK11Free) nsslowcert_DestroyDBEntry;
    return entry;
}

static SECItem *
pk11_getCrl(PK11TokenObject *object)
{
    SECItem *crl;
    PRBool isKrl;

    if (object->obj.objclass != CKO_NETSCAPE_CRL) {
	return NULL;
    }
    if (object->obj.objectInfo) {
	return (SECItem *)object->obj.objectInfo;
    }

    isKrl = (PRBool) object->obj.handle == PK11_TOKEN_KRL_HANDLE;
    crl = nsslowcert_FindCrlByKey(object->obj.slot->certDB,&object->dbKey,
								NULL,isKrl);
    object->obj.objectInfo = (void *)crl;
    object->obj.infoFree = (PK11Free) pk11_FreeItem;
    return crl;
}

static char *
pk11_getUrl(PK11TokenObject *object)
{
    SECItem *crl;
    PRBool isKrl;
    char *url = NULL;

    if (object->obj.objclass != CKO_NETSCAPE_CRL) {
	return NULL;
    }

    isKrl = (PRBool) object->obj.handle == PK11_TOKEN_KRL_HANDLE;
    crl = nsslowcert_FindCrlByKey(object->obj.slot->certDB,&object->dbKey,
								&url,isKrl);
    if (object->obj.objectInfo == NULL) {
	object->obj.objectInfo = (void *)crl;
	object->obj.infoFree = (PK11Free) pk11_FreeItem;
    } else {
	if (crl) SECITEM_FreeItem(crl,PR_TRUE);
    }
    return url;
}

static NSSLOWCERTCertificate *
pk11_getCert(PK11TokenObject *object)
{
    NSSLOWCERTCertificate *cert;

    if ((object->obj.objclass != CKO_CERTIFICATE) &&
	 		(object->obj.objclass != CKO_NETSCAPE_TRUST)) {
	return NULL;
    }
    if (object->obj.objectInfo) {
	return (NSSLOWCERTCertificate *)object->obj.objectInfo;
    }
    cert = nsslowcert_FindCertByKey(object->obj.slot->certDB,&object->dbKey);
    object->obj.objectInfo = (void *)cert;
    object->obj.infoFree = (PK11Free) nsslowcert_DestroyCertificate ;
    return cert;
}

static NSSLOWKEYPublicKey *
pk11_GetPublicKey(PK11TokenObject *object)
{
    NSSLOWKEYPublicKey *pubKey;
    NSSLOWKEYPrivateKey *privKey;

    if (object->obj.objclass != CKO_PUBLIC_KEY) {
	return NULL;
    }
    if (object->obj.objectInfo) {
	return (NSSLOWKEYPublicKey *)object->obj.objectInfo;
    }
    privKey = nsslowkey_FindKeyByPublicKey(object->obj.slot->keyDB,
				&object->dbKey, object->obj.slot->password);
    if (privKey == NULL) {
	return NULL;
    }
    pubKey = nsslowkey_ConvertToPublicKey(privKey);
    nsslowkey_DestroyPrivateKey(privKey);
    object->obj.objectInfo = (void *) pubKey;
    object->obj.infoFree = (PK11Free) nsslowkey_DestroyPublicKey ;
    return pubKey;
}

static NSSLOWKEYPrivateKey *
pk11_GetPrivateKey(PK11TokenObject *object)
{
    NSSLOWKEYPrivateKey *privKey;

    if ((object->obj.objclass != CKO_PRIVATE_KEY) && 
			(object->obj.objclass != CKO_SECRET_KEY)) {
	return NULL;
    }
    if (object->obj.objectInfo) {
	return (NSSLOWKEYPrivateKey *)object->obj.objectInfo;
    }
    privKey = nsslowkey_FindKeyByPublicKey(object->obj.slot->keyDB,
				&object->dbKey, object->obj.slot->password);
    if (privKey == NULL) {
	return NULL;
    }
    object->obj.objectInfo = (void *) privKey;
    object->obj.infoFree = (PK11Free) nsslowkey_DestroyPrivateKey ;
    return privKey;
}

/* pk11_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 *
pk11_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;
    default:
	    break;
    }
    return pubItem;
}

static const SEC_ASN1Template pk11_SerialTemplate[] = {
    { SEC_ASN1_INTEGER, offsetof(NSSLOWCERTCertificate,serialNumber) },
    { 0 }
};

static PK11Attribute *
pk11_FindRSAPublicKeyAttribute(NSSLOWKEYPublicKey *key, CK_ATTRIBUTE_TYPE type)
{
    unsigned char hash[SHA1_LENGTH];
    CK_KEY_TYPE keyType = CKK_RSA;

    switch (type) {
    case CKA_KEY_TYPE:
	return pk11_NewTokenAttribute(type,&keyType,sizeof(keyType), PR_TRUE);
    case CKA_ID:
	SHA1_HashBuf(hash,key->u.rsa.modulus.data,key->u.rsa.modulus.len);
	return pk11_NewTokenAttribute(type,hash,SHA1_LENGTH, PR_TRUE);
    case CKA_DERIVE:
	return (PK11Attribute *) &pk11_StaticFalseAttr;
    case CKA_ENCRYPT:
    case CKA_VERIFY:
    case CKA_VERIFY_RECOVER:
    case CKA_WRAP:
	return (PK11Attribute *) &pk11_StaticTrueAttr;
    case CKA_MODULUS:
	return pk11_NewTokenAttributeSigned(type,key->u.rsa.modulus.data,
					key->u.rsa.modulus.len, PR_FALSE);
    case CKA_PUBLIC_EXPONENT:
	return pk11_NewTokenAttributeSigned(type,key->u.rsa.publicExponent.data,
				key->u.rsa.publicExponent.len, PR_FALSE);
    default:
	break;
    }
    return NULL;
}

static PK11Attribute *
pk11_FindDSAPublicKeyAttribute(NSSLOWKEYPublicKey *key, CK_ATTRIBUTE_TYPE type)
{
    unsigned char hash[SHA1_LENGTH];
    CK_KEY_TYPE keyType = CKK_DSA;

    switch (type) {
    case CKA_KEY_TYPE:
	return pk11_NewTokenAttribute(type,&keyType,sizeof(keyType), PR_TRUE);
    case CKA_ID:
	SHA1_HashBuf(hash,key->u.dsa.publicValue.data,
						key->u.dsa.publicValue.len);
	return pk11_NewTokenAttribute(type,hash,SHA1_LENGTH, PR_TRUE);
    case CKA_DERIVE:
    case CKA_ENCRYPT:
    case CKA_VERIFY_RECOVER:
    case CKA_WRAP:
	return (PK11Attribute *) &pk11_StaticFalseAttr;
    case CKA_VERIFY:
	return (PK11Attribute *) &pk11_StaticTrueAttr;
    case CKA_VALUE:
	return pk11_NewTokenAttributeSigned(type,key->u.dsa.publicValue.data,
					key->u.dsa.publicValue.len, PR_FALSE);
    case CKA_PRIME:
	return pk11_NewTokenAttributeSigned(type,key->u.dsa.params.prime.data,
					key->u.dsa.params.prime.len, PR_FALSE);
    case CKA_SUBPRIME:
	return pk11_NewTokenAttributeSigned(type,
				key->u.dsa.params.subPrime.data,
				key->u.dsa.params.subPrime.len, PR_FALSE);
    case CKA_BASE:
	return pk11_NewTokenAttributeSigned(type,key->u.dsa.params.base.data,
					key->u.dsa.params.base.len, PR_FALSE);
    default:
	break;
    }
    return NULL;
}

static PK11Attribute *
pk11_FindDHPublicKeyAttribute(NSSLOWKEYPublicKey *key, CK_ATTRIBUTE_TYPE type)
{
    unsigned char hash[SHA1_LENGTH];
    CK_KEY_TYPE keyType = CKK_DH;

    switch (type) {
    case CKA_KEY_TYPE:
	return pk11_NewTokenAttribute(type,&keyType,sizeof(keyType), PR_TRUE);
    case CKA_ID:
	SHA1_HashBuf(hash,key->u.dh.publicValue.data,key->u.dh.publicValue.len);
	return pk11_NewTokenAttribute(type,hash,SHA1_LENGTH, PR_TRUE);
    case CKA_DERIVE:
	return (PK11Attribute *) &pk11_StaticTrueAttr;
    case CKA_ENCRYPT:
    case CKA_VERIFY:
    case CKA_VERIFY_RECOVER:
    case CKA_WRAP:
	return (PK11Attribute *) &pk11_StaticFalseAttr;
    case CKA_VALUE:
	return pk11_NewTokenAttributeSigned(type,key->u.dh.publicValue.data,
					key->u.dh.publicValue.len, PR_FALSE);
    case CKA_PRIME:
	return pk11_NewTokenAttributeSigned(type,key->u.dh.prime.data,
					key->u.dh.prime.len, PR_FALSE);
    case CKA_BASE:
	return pk11_NewTokenAttributeSigned(type,key->u.dh.base.data,
					key->u.dh.base.len, PR_FALSE);
    default:
	break;
    }
    return NULL;
}

static PK11Attribute *
pk11_FindPublicKeyAttribute(PK11TokenObject *object, CK_ATTRIBUTE_TYPE type)
{
    NSSLOWKEYPublicKey *key;
    PK11Attribute *att = NULL;
    char *label;

    switch (type) {
    case CKA_PRIVATE:
    case CKA_SENSITIVE:
    case CKA_ALWAYS_SENSITIVE:
    case CKA_NEVER_EXTRACTABLE:
	return (PK11Attribute *) &pk11_StaticFalseAttr;
    case CKA_MODIFIABLE:
    case CKA_EXTRACTABLE:
	return (PK11Attribute *) &pk11_StaticTrueAttr;
    case CKA_LABEL:
        label = nsslowkey_FindKeyNicknameByPublicKey(object->obj.slot->keyDB,
				&object->dbKey, object->obj.slot->password);
	if (label == NULL) {
	   return (PK11Attribute *)&pk11_StaticNullAttr;
	}
	att = pk11_NewTokenAttribute(type,label,PORT_Strlen(label)+1, PR_TRUE);
	PORT_Free(label);
	return att;
    default:
	break;
    }

    key = pk11_GetPublicKey(object);
    if (key == NULL) {
	return NULL;
    }

    switch (key->keyType) {
    case NSSLOWKEYRSAKey:
	return pk11_FindRSAPublicKeyAttribute(key,type);
    case NSSLOWKEYDSAKey:
	return pk11_FindDSAPublicKeyAttribute(key,type);
    case NSSLOWKEYDHKey:
	return pk11_FindDHPublicKeyAttribute(key,type);
    default:
	break;
    }

    return NULL;
}

static PK11Attribute *
pk11_FindSecretKeyAttribute(PK11TokenObject *object, CK_ATTRIBUTE_TYPE type)
{
    NSSLOWKEYPrivateKey *key;
    char *label;
    PK11Attribute *att;

    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:
	return (PK11Attribute *) &pk11_StaticTrueAttr;
    case CKA_NEVER_EXTRACTABLE:
    case CKA_MODIFIABLE:
	return (PK11Attribute *) &pk11_StaticFalseAttr;
    case CKA_LABEL:
        label = nsslowkey_FindKeyNicknameByPublicKey(object->obj.slot->keyDB,
				&object->dbKey, object->obj.slot->password);
	if (label == NULL) {
	   return (PK11Attribute *)&pk11_StaticNullAttr;
	}
	att = pk11_NewTokenAttribute(type,label,PORT_Strlen(label)+1, PR_TRUE);
	PORT_Free(label);
	return att;
    default:
	break;
    }

    key = pk11_GetPrivateKey(object);
    if (key == NULL) {
	return NULL;
    }
    switch (type) {
    case CKA_KEY_TYPE:
	{
	    SECItem ktItem, *coeff;
	    unsigned char ktBuf[4];
	    int k;
	    coeff = &key->u.rsa.coefficient;
	    if (coeff->len < 4) {
		/* The coefficient has been decoded from an entry in the
		 * key db.  The decoder removes leading zeros, but PKCS#11
		 * expects an attribute 4 bytes long it can convert to a
		 * CK_ULONG.  In order for big-endian platforms to work, the
		 * leading zeros must be prepended again.
		 */
		ktItem.len = 4;
		ktItem.data = ktBuf;
		for (k=0; k<4; k++) {
		    if (k < coeff->len) {
			ktBuf[3-k] = coeff->data[k];
		    } else {
			ktBuf[3-k] = 0;
		    }
		}
		coeff = &ktItem;
	    }
	    return pk11_NewTokenAttribute(type, coeff->data, coeff->len, PR_FALSE);
	}
    case CKA_VALUE:
	return pk11_NewTokenAttribute(type,key->u.rsa.privateExponent.data,
				key->u.rsa.privateExponent.len, PR_FALSE);
    }

    return NULL;
}

static PK11Attribute *
pk11_FindRSAPrivateKeyAttribute(NSSLOWKEYPrivateKey *key,
							 CK_ATTRIBUTE_TYPE type)
{
    unsigned char hash[SHA1_LENGTH];
    CK_KEY_TYPE keyType = CKK_RSA;

    switch (type) {
    case CKA_KEY_TYPE:
	return pk11_NewTokenAttribute(type,&keyType,sizeof(keyType), PR_TRUE);
    case CKA_ID:
	SHA1_HashBuf(hash,key->u.rsa.modulus.data,key->u.rsa.modulus.len);
	return pk11_NewTokenAttribute(type,hash,SHA1_LENGTH, PR_TRUE);
    case CKA_DERIVE:
	return (PK11Attribute *) &pk11_StaticFalseAttr;
    case CKA_DECRYPT:
    case CKA_SIGN:
{'fraction_non_alphanumeric': 0.10675294117647059, 'fraction_numerical': 0.022705882352941176, 'mean_word_length': 4.24185989146522, 'pattern_counts': {'":': 0, '<': 12, '<?xml version=': 0, '>': 363, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6420678', 'n_tokens_mistral': 16223, 'n_tokens_neox': 15089, 'n_words': 3018}