Bug 289530. Supply the missing code so that NSC_CopyObject can copy NSS_PERFORMANCE_HACKS_BRANCH
authornelsonb%netscape.com
Thu, 14 Apr 2005 06:57:34 +0000
branchNSS_PERFORMANCE_HACKS_BRANCH
changeset 5617 5c13ccccf150a66112ff186526ee32f985c7b02a
parent 5612 26da2764a3beafb961e72088e79f2d11bb4ab6f8
child 5640 f8a88b00d0fe2d5350e46e61beac14dc8ba58227
push idunknown
push userunknown
push dateunknown
bugs289530
Bug 289530. Supply the missing code so that NSC_CopyObject can copy token keys to session keys. r=rrelyea. On HACKS branch.
security/nss/lib/softoken/pkcs11.c
security/nss/lib/softoken/pkcs11u.c
--- a/security/nss/lib/softoken/pkcs11.c
+++ b/security/nss/lib/softoken/pkcs11.c
@@ -1352,24 +1352,19 @@ fail:
 	if (pubKey.data) PORT_Free(pubKey.data);
 	nsslowkey_DestroyPrivateKey(privKey);
 	if (rv != SECSuccess) return CKR_DEVICE_ERROR;
     } else {
 	object->objectInfo = sftk_mkPrivKey(object,key_type,&crv);
 	if (object->objectInfo == NULL) return crv;
 	object->infoFree = (SFTKFree) nsslowkey_DestroyPrivateKey;
 	/* now NULL out the sensitive attributes */
-	if (sftk_isTrue(object,CKA_SENSITIVE)) {
-	    sftk_nullAttribute(object,CKA_PRIVATE_EXPONENT);
-	    sftk_nullAttribute(object,CKA_PRIME_1);
-	    sftk_nullAttribute(object,CKA_PRIME_2);
-	    sftk_nullAttribute(object,CKA_EXPONENT_1);
-	    sftk_nullAttribute(object,CKA_EXPONENT_2);
-	    sftk_nullAttribute(object,CKA_COEFFICIENT);
-	}
+	/* remove nulled out attributes for session objects. these only
+	 * applied to rsa private keys anyway (other private keys did not
+	 * get their attributes NULL'ed out */
     }
     return CKR_OK;
 }
 
 /* forward delcare the DES formating function for handleSecretKey */
 void sftk_FormatDESKey(unsigned char *key, int length);
 static NSSLOWKEYPrivateKey *sftk_mkSecretKeyRep(SFTKObject *object);
 
--- a/security/nss/lib/softoken/pkcs11u.c
+++ b/security/nss/lib/softoken/pkcs11u.c
@@ -188,16 +188,20 @@ sftk_FreeAttribute(SFTKAttribute *attrib
 	sftk_DestroyAttribute(attribute);
 	return;
     }
 }
 
 #define SFTK_DEF_ATTRIBUTE(value,len) \
    { NULL, NULL, PR_FALSE, PR_FALSE, 0, { 0, value, len } }
 
+#define SFTK_CLONE_ATTR(type, staticAttr) \
+    sftk_NewTokenAttribute( type, staticAttr.attrib.pValue, \
+    staticAttr.attrib.ulValueLen, PR_FALSE)
+
 CK_BBOOL sftk_staticTrueValue = CK_TRUE;
 CK_BBOOL sftk_staticFalseValue = CK_FALSE;
 static const SFTKAttribute sftk_StaticTrueAttr = 
   SFTK_DEF_ATTRIBUTE(&sftk_staticTrueValue,sizeof(sftk_staticTrueValue));
 static const SFTKAttribute sftk_StaticFalseAttr = 
   SFTK_DEF_ATTRIBUTE(&sftk_staticFalseValue,sizeof(sftk_staticFalseValue));
 static const SFTKAttribute sftk_StaticNullAttr = SFTK_DEF_ATTRIBUTE(NULL,0);
 char sftk_StaticOneValue = 1;
@@ -402,22 +406,22 @@ sftk_FindRSAPublicKeyAttribute(NSSLOWKEY
 
     switch (type) {
     case CKA_KEY_TYPE:
 	return sftk_NewTokenAttribute(type,&keyType,sizeof(keyType), PR_TRUE);
     case CKA_ID:
 	SHA1_HashBuf(hash,key->u.rsa.modulus.data,key->u.rsa.modulus.len);
 	return sftk_NewTokenAttribute(type,hash,SHA1_LENGTH, PR_TRUE);
     case CKA_DERIVE:
-	return (SFTKAttribute *) &sftk_StaticFalseAttr;
+	return SFTK_CLONE_ATTR(type,sftk_StaticFalseAttr);
     case CKA_ENCRYPT:
     case CKA_VERIFY:
     case CKA_VERIFY_RECOVER:
     case CKA_WRAP:
-	return (SFTKAttribute *) &sftk_StaticTrueAttr;
+	return SFTK_CLONE_ATTR(type,sftk_StaticTrueAttr);
     case CKA_MODULUS:
 	return sftk_NewTokenAttributeSigned(type,key->u.rsa.modulus.data,
 					key->u.rsa.modulus.len, PR_FALSE);
     case CKA_PUBLIC_EXPONENT:
 	return sftk_NewTokenAttributeSigned(type,key->u.rsa.publicExponent.data,
 				key->u.rsa.publicExponent.len, PR_FALSE);
     default:
 	break;
@@ -437,19 +441,19 @@ sftk_FindDSAPublicKeyAttribute(NSSLOWKEY
     case CKA_ID:
 	SHA1_HashBuf(hash,key->u.dsa.publicValue.data,
 						key->u.dsa.publicValue.len);
 	return sftk_NewTokenAttribute(type,hash,SHA1_LENGTH, PR_TRUE);
     case CKA_DERIVE:
     case CKA_ENCRYPT:
     case CKA_VERIFY_RECOVER:
     case CKA_WRAP:
-	return (SFTKAttribute *) &sftk_StaticFalseAttr;
+	return SFTK_CLONE_ATTR(type,sftk_StaticFalseAttr);
     case CKA_VERIFY:
-	return (SFTKAttribute *) &sftk_StaticTrueAttr;
+	return SFTK_CLONE_ATTR(type,sftk_StaticTrueAttr);
     case CKA_VALUE:
 	return sftk_NewTokenAttributeSigned(type,key->u.dsa.publicValue.data,
 					key->u.dsa.publicValue.len, PR_FALSE);
     case CKA_PRIME:
 	return sftk_NewTokenAttributeSigned(type,key->u.dsa.params.prime.data,
 					key->u.dsa.params.prime.len, PR_FALSE);
     case CKA_SUBPRIME:
 	return sftk_NewTokenAttributeSigned(type,
@@ -472,22 +476,22 @@ sftk_FindDHPublicKeyAttribute(NSSLOWKEYP
 
     switch (type) {
     case CKA_KEY_TYPE:
 	return sftk_NewTokenAttribute(type,&keyType,sizeof(keyType), PR_TRUE);
     case CKA_ID:
 	SHA1_HashBuf(hash,key->u.dh.publicValue.data,key->u.dh.publicValue.len);
 	return sftk_NewTokenAttribute(type,hash,SHA1_LENGTH, PR_TRUE);
     case CKA_DERIVE:
-	return (SFTKAttribute *) &sftk_StaticTrueAttr;
+	return SFTK_CLONE_ATTR(type,sftk_StaticTrueAttr);
     case CKA_ENCRYPT:
     case CKA_VERIFY:
     case CKA_VERIFY_RECOVER:
     case CKA_WRAP:
-	return (SFTKAttribute *) &sftk_StaticFalseAttr;
+	return SFTK_CLONE_ATTR(type,sftk_StaticFalseAttr);
     case CKA_VALUE:
 	return sftk_NewTokenAttributeSigned(type,key->u.dh.publicValue.data,
 					key->u.dh.publicValue.len, PR_FALSE);
     case CKA_PRIME:
 	return sftk_NewTokenAttributeSigned(type,key->u.dh.prime.data,
 					key->u.dh.prime.len, PR_FALSE);
     case CKA_BASE:
 	return sftk_NewTokenAttributeSigned(type,key->u.dh.base.data,
@@ -509,21 +513,21 @@ sftk_FindECPublicKeyAttribute(NSSLOWKEYP
     case CKA_KEY_TYPE:
 	return sftk_NewTokenAttribute(type,&keyType,sizeof(keyType), PR_TRUE);
     case CKA_ID:
 	SHA1_HashBuf(hash, key->u.ec.publicValue.data,
 		     key->u.ec.publicValue.len);
 	return sftk_NewTokenAttribute(type,hash,SHA1_LENGTH, PR_TRUE);
     case CKA_DERIVE:
     case CKA_VERIFY:
-	return (SFTKAttribute *) &sftk_StaticTrueAttr;
+	return SFTK_CLONE_ATTR(type,sftk_StaticTrueAttr);
     case CKA_ENCRYPT:
     case CKA_VERIFY_RECOVER:
     case CKA_WRAP:
-	return (SFTKAttribute *) &sftk_StaticFalseAttr;
+	return SFTK_CLONE_ATTR(type,sftk_StaticFalseAttr);
     case CKA_EC_PARAMS:
         /* XXX Why is the last arg PR_FALSE? */
 	return sftk_NewTokenAttributeSigned(type,
 					key->u.ec.ecParams.DEREncoding.data,
 					key->u.ec.ecParams.DEREncoding.len,
 					PR_FALSE);
     case CKA_EC_POINT:
         /* XXX Why is the last arg PR_FALSE? */
@@ -543,25 +547,25 @@ sftk_FindPublicKeyAttribute(SFTKTokenObj
     SFTKAttribute *att = NULL;
     char *label;
 
     switch (type) {
     case CKA_PRIVATE:
     case CKA_SENSITIVE:
     case CKA_ALWAYS_SENSITIVE:
     case CKA_NEVER_EXTRACTABLE:
-	return (SFTKAttribute *) &sftk_StaticFalseAttr;
+	return SFTK_CLONE_ATTR(type,sftk_StaticFalseAttr);
     case CKA_MODIFIABLE:
     case CKA_EXTRACTABLE:
-	return (SFTKAttribute *) &sftk_StaticTrueAttr;
+	return SFTK_CLONE_ATTR(type,sftk_StaticTrueAttr);
     case CKA_LABEL:
         label = nsslowkey_FindKeyNicknameByPublicKey(object->obj.slot->keyDB,
 				&object->dbKey, object->obj.slot->password);
 	if (label == NULL) {
-	   return (SFTKAttribute *)&sftk_StaticOneAttr;
+	   return SFTK_CLONE_ATTR(type,sftk_StaticOneAttr);
 	}
 	att = sftk_NewTokenAttribute(type,label,PORT_Strlen(label), PR_TRUE);
 	PORT_Free(label);
 	return att;
     default:
 	break;
     }
 
@@ -608,24 +612,24 @@ sftk_FindSecretKeyAttribute(SFTKTokenObj
     case CKA_DERIVE:
     case CKA_ENCRYPT:
     case CKA_DECRYPT:
     case CKA_SIGN:
     case CKA_VERIFY:
     case CKA_WRAP:
     case CKA_UNWRAP:
     case CKA_MODIFIABLE:
-	return (SFTKAttribute *) &sftk_StaticTrueAttr;
+	return SFTK_CLONE_ATTR(type,sftk_StaticTrueAttr);
     case CKA_NEVER_EXTRACTABLE:
-	return (SFTKAttribute *) &sftk_StaticFalseAttr;
+	return SFTK_CLONE_ATTR(type,sftk_StaticFalseAttr);
     case CKA_LABEL:
         label = nsslowkey_FindKeyNicknameByPublicKey(object->obj.slot->keyDB,
 				&object->dbKey, object->obj.slot->password);
 	if (label == NULL) {
-	   return (SFTKAttribute *)&sftk_StaticNullAttr;
+	   return SFTK_CLONE_ATTR(type,sftk_StaticNullAttr);
 	}
 	att = sftk_NewTokenAttribute(type,label,PORT_Strlen(label), PR_TRUE);
 	PORT_Free(label);
 	return att;
     case CKA_KEY_TYPE:
     case CKA_VALUE_LEN:
     case CKA_VALUE:
 	break;
@@ -718,47 +722,59 @@ sftk_FindSecretKeyAttribute(SFTKTokenObj
 	return sftk_NewTokenAttribute(type, &keyLen, sizeof(CK_ULONG), PR_TRUE);
     }
 
     return NULL;
 }
 
 static SFTKAttribute *
 sftk_FindRSAPrivateKeyAttribute(NSSLOWKEYPrivateKey *key,
-							 CK_ATTRIBUTE_TYPE type)
+				CK_ATTRIBUTE_TYPE type)
 {
     unsigned char hash[SHA1_LENGTH];
     CK_KEY_TYPE keyType = CKK_RSA;
 
     switch (type) {
     case CKA_KEY_TYPE:
 	return sftk_NewTokenAttribute(type,&keyType,sizeof(keyType), PR_TRUE);
     case CKA_ID:
 	SHA1_HashBuf(hash,key->u.rsa.modulus.data,key->u.rsa.modulus.len);
 	return sftk_NewTokenAttribute(type,hash,SHA1_LENGTH, PR_TRUE);
     case CKA_DERIVE:
-	return (SFTKAttribute *) &sftk_StaticFalseAttr;
+	return SFTK_CLONE_ATTR(type,sftk_StaticFalseAttr);
     case CKA_DECRYPT:
     case CKA_SIGN:
     case CKA_SIGN_RECOVER:
     case CKA_UNWRAP:
-	return (SFTKAttribute *) &sftk_StaticTrueAttr;
+	return SFTK_CLONE_ATTR(type,sftk_StaticTrueAttr);
     case CKA_MODULUS:
 	return sftk_NewTokenAttributeSigned(type,key->u.rsa.modulus.data,
 					key->u.rsa.modulus.len, PR_FALSE);
     case CKA_PUBLIC_EXPONENT:
 	return sftk_NewTokenAttributeSigned(type,key->u.rsa.publicExponent.data,
 				key->u.rsa.publicExponent.len, PR_FALSE);
     case CKA_PRIVATE_EXPONENT:
+	return sftk_NewTokenAttributeSigned(type,
+				key->u.rsa.privateExponent.data,
+				key->u.rsa.privateExponent.len, PR_FALSE);
     case CKA_PRIME_1:
+	return sftk_NewTokenAttributeSigned(type, key->u.rsa.prime1.data,
+				key->u.rsa.prime1.len, PR_FALSE);
     case CKA_PRIME_2:
+	return sftk_NewTokenAttributeSigned(type, key->u.rsa.prime2.data,
+				key->u.rsa.prime2.len, PR_FALSE);
     case CKA_EXPONENT_1:
+	return sftk_NewTokenAttributeSigned(type, key->u.rsa.exponent1.data,
+				key->u.rsa.exponent1.len, PR_FALSE);
     case CKA_EXPONENT_2:
+	return sftk_NewTokenAttributeSigned(type, key->u.rsa.exponent2.data,
+				key->u.rsa.exponent2.len, PR_FALSE);
     case CKA_COEFFICIENT:
-	return (SFTKAttribute *) &sftk_StaticNullAttr;
+	return sftk_NewTokenAttributeSigned(type, key->u.rsa.coefficient.data,
+				key->u.rsa.coefficient.len, PR_FALSE);
     default:
 	break;
     }
     return NULL;
 }
 
 static SFTKAttribute *
 sftk_FindDSAPrivateKeyAttribute(NSSLOWKEYPrivateKey *key, 
@@ -767,27 +783,28 @@ sftk_FindDSAPrivateKeyAttribute(NSSLOWKE
     unsigned char hash[SHA1_LENGTH];
     CK_KEY_TYPE keyType = CKK_DSA;
 
     switch (type) {
     case CKA_KEY_TYPE:
 	return sftk_NewTokenAttribute(type,&keyType,sizeof(keyType), PR_TRUE);
     case CKA_ID:
 	SHA1_HashBuf(hash,key->u.dsa.publicValue.data,
-						key->u.dsa.publicValue.len);
+			  key->u.dsa.publicValue.len);
 	return sftk_NewTokenAttribute(type,hash,SHA1_LENGTH, PR_TRUE);
     case CKA_DERIVE:
     case CKA_DECRYPT:
     case CKA_SIGN_RECOVER:
     case CKA_UNWRAP:
-	return (SFTKAttribute *) &sftk_StaticFalseAttr;
+	return SFTK_CLONE_ATTR(type,sftk_StaticFalseAttr);
     case CKA_SIGN:
-	return (SFTKAttribute *) &sftk_StaticTrueAttr;
+	return SFTK_CLONE_ATTR(type,sftk_StaticTrueAttr);
     case CKA_VALUE:
-	return (SFTKAttribute *) &sftk_StaticNullAttr;
+	return sftk_NewTokenAttributeSigned(type, key->u.dsa.privateValue.data,
+				key->u.dsa.privateValue.len, PR_FALSE);
     case CKA_PRIME:
 	return sftk_NewTokenAttributeSigned(type,key->u.dsa.params.prime.data,
 					key->u.dsa.params.prime.len, PR_FALSE);
     case CKA_SUBPRIME:
 	return sftk_NewTokenAttributeSigned(type,
 				key->u.dsa.params.subPrime.data,
 				key->u.dsa.params.subPrime.len, PR_FALSE);
     case CKA_BASE:
@@ -807,24 +824,25 @@ sftk_FindDHPrivateKeyAttribute(NSSLOWKEY
 
     switch (type) {
     case CKA_KEY_TYPE:
 	return sftk_NewTokenAttribute(type,&keyType,sizeof(keyType), PR_TRUE);
     case CKA_ID:
 	SHA1_HashBuf(hash,key->u.dh.publicValue.data,key->u.dh.publicValue.len);
 	return sftk_NewTokenAttribute(type,hash,SHA1_LENGTH, PR_TRUE);
     case CKA_DERIVE:
-	return (SFTKAttribute *) &sftk_StaticTrueAttr;
+	return SFTK_CLONE_ATTR(type,sftk_StaticTrueAttr);
     case CKA_DECRYPT:
     case CKA_SIGN:
     case CKA_SIGN_RECOVER:
     case CKA_UNWRAP:
-	return (SFTKAttribute *) &sftk_StaticFalseAttr;
+	return SFTK_CLONE_ATTR(type,sftk_StaticFalseAttr);
     case CKA_VALUE:
-	return (SFTKAttribute *) &sftk_StaticNullAttr;
+	return sftk_NewTokenAttributeSigned(type,key->u.dh.privateValue.data,
+					key->u.dh.privateValue.len, PR_FALSE);
     case CKA_PRIME:
 	return sftk_NewTokenAttributeSigned(type,key->u.dh.prime.data,
 					key->u.dh.prime.len, PR_FALSE);
     case CKA_BASE:
 	return sftk_NewTokenAttributeSigned(type,key->u.dh.base.data,
 					key->u.dh.base.len, PR_FALSE);
     default:
 	break;
@@ -842,23 +860,24 @@ sftk_FindECPrivateKeyAttribute(NSSLOWKEY
     switch (type) {
     case CKA_KEY_TYPE:
 	return sftk_NewTokenAttribute(type,&keyType,sizeof(keyType), PR_TRUE);
     case CKA_ID:
 	SHA1_HashBuf(hash,key->u.ec.publicValue.data,key->u.ec.publicValue.len);
 	return sftk_NewTokenAttribute(type,hash,SHA1_LENGTH, PR_TRUE);
     case CKA_DERIVE:
     case CKA_SIGN:
-	return (SFTKAttribute *) &sftk_StaticTrueAttr;
+	return SFTK_CLONE_ATTR(type,sftk_StaticTrueAttr);
     case CKA_DECRYPT:
     case CKA_SIGN_RECOVER:
     case CKA_UNWRAP:
-	return (SFTKAttribute *) &sftk_StaticFalseAttr;
+	return SFTK_CLONE_ATTR(type,sftk_StaticFalseAttr);
     case CKA_VALUE:
-	return (SFTKAttribute *) &sftk_StaticNullAttr;
+	return sftk_NewTokenAttributeSigned(type, key->u.ec.privateValue.data,
+					key->u.ec.privateValue.len, PR_FALSE);
     case CKA_EC_PARAMS:
         /* XXX Why is the last arg PR_FALSE? */
 	return sftk_NewTokenAttributeSigned(type,
 					key->u.ec.ecParams.DEREncoding.data,
 					key->u.ec.ecParams.DEREncoding.len,
 					PR_FALSE);
     default:
 	break;
@@ -875,26 +894,26 @@ sftk_FindPrivateKeyAttribute(SFTKTokenOb
     SFTKAttribute *att;
 
     switch (type) {
     case CKA_PRIVATE:
     case CKA_SENSITIVE:
     case CKA_ALWAYS_SENSITIVE:
     case CKA_EXTRACTABLE:
     case CKA_MODIFIABLE:
-	return (SFTKAttribute *) &sftk_StaticTrueAttr;
+	return SFTK_CLONE_ATTR(type,sftk_StaticTrueAttr);
     case CKA_NEVER_EXTRACTABLE:
-	return (SFTKAttribute *) &sftk_StaticFalseAttr;
+	return SFTK_CLONE_ATTR(type,sftk_StaticFalseAttr);
     case CKA_SUBJECT:
-	   return (SFTKAttribute *)&sftk_StaticNullAttr;
+	   return SFTK_CLONE_ATTR(type,sftk_StaticNullAttr);
     case CKA_LABEL:
         label = nsslowkey_FindKeyNicknameByPublicKey(object->obj.slot->keyDB,
 				&object->dbKey, object->obj.slot->password);
 	if (label == NULL) {
-	   return (SFTKAttribute *)&sftk_StaticNullAttr;
+	   return SFTK_CLONE_ATTR(type,sftk_StaticNullAttr);
 	}
 	att = sftk_NewTokenAttribute(type,label,PORT_Strlen(label), PR_TRUE);
 	PORT_Free(label);
 	return att;
     default:
 	break;
     }
     key = sftk_GetPrivateKey(object);
@@ -921,17 +940,17 @@ sftk_FindPrivateKeyAttribute(SFTKTokenOb
 
 static SFTKAttribute *
 sftk_FindSMIMEAttribute(SFTKTokenObject *object, CK_ATTRIBUTE_TYPE type)
 {
     certDBEntrySMime *entry;
     switch (type) {
     case CKA_PRIVATE:
     case CKA_MODIFIABLE:
-	return (SFTKAttribute *) &sftk_StaticFalseAttr;
+	return SFTK_CLONE_ATTR(type,sftk_StaticFalseAttr);
     case CKA_NETSCAPE_EMAIL:
 	return sftk_NewTokenAttribute(type,object->dbKey.data,
 						object->dbKey.len-1, PR_FALSE);
     case CKA_NETSCAPE_SMIME_TIMESTAMP:
     case CKA_SUBJECT:
     case CKA_VALUE:
 	break;
     default:
@@ -961,19 +980,19 @@ static SFTKAttribute *
 sftk_FindTrustAttribute(SFTKTokenObject *object, CK_ATTRIBUTE_TYPE type)
 {
     NSSLOWCERTTrust *trust;
     unsigned char hash[SHA1_LENGTH];
     unsigned int trustFlags;
 
     switch (type) {
     case CKA_PRIVATE:
-	return (SFTKAttribute *) &sftk_StaticFalseAttr;
+	return SFTK_CLONE_ATTR(type,sftk_StaticFalseAttr);
     case CKA_MODIFIABLE:
-	return (SFTKAttribute *) &sftk_StaticTrueAttr;
+	return SFTK_CLONE_ATTR(type,sftk_StaticTrueAttr);
     case CKA_CERT_SHA1_HASH:
     case CKA_CERT_MD5_HASH:
     case CKA_TRUST_CLIENT_AUTH:
     case CKA_TRUST_SERVER_AUTH:
     case CKA_TRUST_EMAIL_PROTECTION:
     case CKA_TRUST_CODE_SIGNING:
     case CKA_TRUST_STEP_UP_APPROVED:
 	break;
@@ -1000,39 +1019,39 @@ sftk_FindTrustAttribute(SFTKTokenObject 
 	goto trust;
     case CKA_TRUST_EMAIL_PROTECTION:
 	trustFlags = trust->trust->emailFlags;
 	goto trust;
     case CKA_TRUST_CODE_SIGNING:
 	trustFlags = trust->trust->objectSigningFlags;
 trust:
 	if (trustFlags & CERTDB_TRUSTED_CA ) {
-	    return (SFTKAttribute *)&sftk_StaticTrustedDelegatorAttr;
+	    return SFTK_CLONE_ATTR(type,sftk_StaticTrustedDelegatorAttr);
 	}
 	if (trustFlags & CERTDB_TRUSTED) {
-	    return (SFTKAttribute *)&sftk_StaticTrustedAttr;
+	    return SFTK_CLONE_ATTR(type,sftk_StaticTrustedAttr);
 	}
 	if (trustFlags & CERTDB_NOT_TRUSTED) {
-	    return (SFTKAttribute *)&sftk_StaticUnTrustedAttr;
+	    return SFTK_CLONE_ATTR(type,sftk_StaticUnTrustedAttr);
 	}
 	if (trustFlags & CERTDB_TRUSTED_UNKNOWN) {
-	    return (SFTKAttribute *)&sftk_StaticTrustUnknownAttr;
+	    return SFTK_CLONE_ATTR(type,sftk_StaticTrustUnknownAttr);
 	}
 	if (trustFlags & CERTDB_VALID_CA) {
-	    return (SFTKAttribute *)&sftk_StaticValidDelegatorAttr;
+	    return SFTK_CLONE_ATTR(type,sftk_StaticValidDelegatorAttr);
 	}
 	if (trustFlags & CERTDB_VALID_PEER) {
-	    return (SFTKAttribute *)&sftk_StaticValidPeerAttr;
+	    return SFTK_CLONE_ATTR(type,sftk_StaticValidPeerAttr);
 	}
-	return (SFTKAttribute *)&sftk_StaticMustVerifyAttr;
+	return SFTK_CLONE_ATTR(type,sftk_StaticMustVerifyAttr);
     case CKA_TRUST_STEP_UP_APPROVED:
 	if (trust->trust->sslFlags & CERTDB_GOVT_APPROVED_CA) {
-	    return (SFTKAttribute *)&sftk_StaticTrueAttr;
+	    return SFTK_CLONE_ATTR(type,sftk_StaticTrueAttr);
 	} else {
-	    return (SFTKAttribute *)&sftk_StaticFalseAttr;
+	    return SFTK_CLONE_ATTR(type,sftk_StaticFalseAttr);
 	}
     default:
 	break;
     }
 
 #ifdef notdef
     switch (type) {
     case CKA_ISSUER:
@@ -1060,20 +1079,21 @@ trust:
 static SFTKAttribute *
 sftk_FindCrlAttribute(SFTKTokenObject *object, CK_ATTRIBUTE_TYPE type)
 {
     certDBEntryRevocation *crl;
 
     switch (type) {
     case CKA_PRIVATE:
     case CKA_MODIFIABLE:
-	return (SFTKAttribute *) &sftk_StaticFalseAttr;
+	return SFTK_CLONE_ATTR(type,sftk_StaticFalseAttr);
     case CKA_NETSCAPE_KRL:
-	return (SFTKAttribute *) ((object->obj.handle == SFTK_TOKEN_KRL_HANDLE) 
-			? &sftk_StaticTrueAttr : &sftk_StaticFalseAttr);
+	return ((object->obj.handle == SFTK_TOKEN_KRL_HANDLE) 
+		? SFTK_CLONE_ATTR(type,sftk_StaticTrueAttr)
+		: SFTK_CLONE_ATTR(type,sftk_StaticFalseAttr));
     case CKA_SUBJECT:
 	return sftk_NewTokenAttribute(type,object->dbKey.data,
 						object->dbKey.len, PR_FALSE);	
     case CKA_NETSCAPE_URL:
     case CKA_VALUE:
 	break;
     default:
 	PORT_SetError(SEC_ERROR_INVALID_ARGS);
@@ -1081,17 +1101,17 @@ sftk_FindCrlAttribute(SFTKTokenObject *o
     }
     crl =  sftk_getCrl(object);
     if (!crl) {
 	return NULL;
     }
     switch (type) {
     case CKA_NETSCAPE_URL:
 	if (crl->url == NULL) {
-	    return (SFTKAttribute *) &sftk_StaticNullAttr;
+	    return SFTK_CLONE_ATTR(type,sftk_StaticNullAttr);
 	}
 	return sftk_NewTokenAttribute(type, crl->url, 
 					PORT_Strlen(crl->url)+1, PR_TRUE);
     case CKA_VALUE:
 	return sftk_NewTokenAttribute(type, crl->derCrl.data, 
 						crl->derCrl.len, PR_FALSE);
     default:
 	break;
@@ -1104,22 +1124,22 @@ sftk_FindCertAttribute(SFTKTokenObject *
 {
     NSSLOWCERTCertificate *cert;
     NSSLOWKEYPublicKey  *pubKey;
     unsigned char hash[SHA1_LENGTH];
     SECItem *item;
 
     switch (type) {
     case CKA_PRIVATE:
-	return (SFTKAttribute *) &sftk_StaticFalseAttr;
+	return SFTK_CLONE_ATTR(type,sftk_StaticFalseAttr);
     case CKA_MODIFIABLE:
-	return (SFTKAttribute *) &sftk_StaticTrueAttr;
+	return SFTK_CLONE_ATTR(type,sftk_StaticTrueAttr);
     case CKA_CERTIFICATE_TYPE:
         /* hardcoding X.509 into here */
-        return (SFTKAttribute *)&sftk_StaticX509Attr;
+        return SFTK_CLONE_ATTR(type,sftk_StaticX509Attr);
     case CKA_VALUE:
     case CKA_ID:
     case CKA_LABEL:
     case CKA_SUBJECT:
     case CKA_ISSUER:
     case CKA_SERIAL_NUMBER:
     case CKA_NETSCAPE_EMAIL:
 	break;
@@ -1133,71 +1153,72 @@ sftk_FindCertAttribute(SFTKTokenObject *
     switch (type) {
     case CKA_VALUE:
 	return sftk_NewTokenAttribute(type,cert->derCert.data,
 						cert->derCert.len,PR_FALSE);
     case CKA_ID:
 	if (((cert->trust->sslFlags & CERTDB_USER) == 0) &&
 		((cert->trust->emailFlags & CERTDB_USER) == 0) &&
 		((cert->trust->objectSigningFlags & CERTDB_USER) == 0)) {
-	    return (SFTKAttribute *) &sftk_StaticNullAttr;
+	    return SFTK_CLONE_ATTR(type,sftk_StaticNullAttr);
 	}
 	pubKey = nsslowcert_ExtractPublicKey(cert);
 	if (pubKey == NULL) break;
 	item = sftk_GetPubItem(pubKey);
 	if (item == NULL) {
 	    nsslowkey_DestroyPublicKey(pubKey);
 	    break;
 	}
 	SHA1_HashBuf(hash,item->data,item->len);
 	/* item is imbedded in pubKey, just free the key */
 	nsslowkey_DestroyPublicKey(pubKey);
 	return sftk_NewTokenAttribute(type, hash, SHA1_LENGTH, PR_TRUE);
     case CKA_LABEL:
-	return cert->nickname ? sftk_NewTokenAttribute(type, cert->nickname,
-				PORT_Strlen(cert->nickname), PR_FALSE) :
-					(SFTKAttribute *) &sftk_StaticNullAttr;
+	return cert->nickname 
+	       ? sftk_NewTokenAttribute(type, cert->nickname,
+				        PORT_Strlen(cert->nickname), PR_FALSE) 
+	       : SFTK_CLONE_ATTR(type,sftk_StaticNullAttr);
     case CKA_SUBJECT:
 	return sftk_NewTokenAttribute(type,cert->derSubject.data,
 						cert->derSubject.len, PR_FALSE);
     case CKA_ISSUER:
 	return sftk_NewTokenAttribute(type,cert->derIssuer.data,
 						cert->derIssuer.len, PR_FALSE);
     case CKA_SERIAL_NUMBER:
 	return sftk_NewTokenAttribute(type,cert->derSN.data,
 						cert->derSN.len, PR_FALSE);
     case CKA_NETSCAPE_EMAIL:
 	return (cert->emailAddr && cert->emailAddr[0])
 	    ? sftk_NewTokenAttribute(type, cert->emailAddr,
 	                             PORT_Strlen(cert->emailAddr), PR_FALSE) 
-	    : (SFTKAttribute *) &sftk_StaticNullAttr;
+	    : SFTK_CLONE_ATTR(type,sftk_StaticNullAttr);
     default:
 	break;
     }
     return NULL;
 }
     
 static SFTKAttribute *    
 sftk_FindTokenAttribute(SFTKTokenObject *object,CK_ATTRIBUTE_TYPE type)
 {
     /* handle the common ones */
     switch (type) {
     case CKA_CLASS:
 	return sftk_NewTokenAttribute(type,&object->obj.objclass,
 					sizeof(object->obj.objclass),PR_FALSE);
     case CKA_TOKEN:
-	return (SFTKAttribute *) &sftk_StaticTrueAttr;
+	return SFTK_CLONE_ATTR(type,sftk_StaticTrueAttr);
     case CKA_LABEL:
 	if (  (object->obj.objclass == CKO_CERTIFICATE) 
 	   || (object->obj.objclass == CKO_PRIVATE_KEY)
 	   || (object->obj.objclass == CKO_PUBLIC_KEY)
 	   || (object->obj.objclass == CKO_SECRET_KEY)) {
 	    break;
 	}
-	return (SFTKAttribute *) &sftk_StaticNullAttr;
+	return SFTK_CLONE_ATTR(type,sftk_StaticNullAttr);
     default:
 	break;
     }
     switch (object->obj.objclass) {
     case CKO_CERTIFICATE:
 	return sftk_FindCertAttribute(object,type);
     case CKO_NETSCAPE_CRL:
 	return sftk_FindCrlAttribute(object,type);
@@ -2379,29 +2400,365 @@ sftk_DeleteObject(SFTKSession *session, 
 	sftk_tokenKeyLock(object->slot);
 	sftk_deleteTokenKeyByHandle(object->slot,object->handle);
 	sftk_tokenKeyUnlock(object->slot);
     } 
     return crv;
 }
 
 /*
+ * Token objects don't explicitly store their attributes, so we need to know
+ * what attributes make up a particular token object before we can copy it.
+ * below are the tables by object type.
+ */
+static const CK_ATTRIBUTE_TYPE commonAttrs[] = {
+    CKA_CLASS, CKA_TOKEN, CKA_PRIVATE, CKA_LABEL, CKA_MODIFIABLE
+};
+static const CK_ULONG commonAttrsCount = 
+			sizeof(commonAttrs)/sizeof(commonAttrs[0]);
+
+static const CK_ATTRIBUTE_TYPE commonKeyAttrs[] = {
+    CKA_ID, CKA_START_DATE, CKA_END_DATE, CKA_DERIVE, CKA_LOCAL, CKA_KEY_TYPE
+};
+static const CK_ULONG commonKeyAttrsCount = 
+			sizeof(commonKeyAttrs)/sizeof(commonKeyAttrs[0]);
+
+static const CK_ATTRIBUTE_TYPE secretKeyAttrs[] = {
+    CKA_SENSITIVE, CKA_EXTRACTABLE, CKA_ENCRYPT, CKA_DECRYPT, CKA_SIGN,
+    CKA_VERIFY, CKA_WRAP, CKA_UNWRAP, CKA_VALUE
+};
+static const CK_ULONG secretKeyAttrsCount = 
+			sizeof(secretKeyAttrs)/sizeof(secretKeyAttrs[0]);
+
+static const CK_ATTRIBUTE_TYPE commonPubKeyAttrs[] = {
+    CKA_ENCRYPT, CKA_VERIFY, CKA_VERIFY_RECOVER, CKA_WRAP, CKA_SUBJECT
+};
+static const CK_ULONG commonPubKeyAttrsCount = 
+			sizeof(commonPubKeyAttrs)/sizeof(commonPubKeyAttrs[0]);
+
+static const CK_ATTRIBUTE_TYPE rsaPubKeyAttrs[] = {
+    CKA_MODULUS, CKA_PUBLIC_EXPONENT
+};
+static const CK_ULONG rsaPubKeyAttrsCount = 
+			sizeof(rsaPubKeyAttrs)/sizeof(rsaPubKeyAttrs[0]);
+
+static const CK_ATTRIBUTE_TYPE dsaPubKeyAttrs[] = {
+    CKA_SUBPRIME, CKA_PRIME, CKA_BASE, CKA_VALUE
+};
+static const CK_ULONG dsaPubKeyAttrsCount = 
+			sizeof(dsaPubKeyAttrs)/sizeof(dsaPubKeyAttrs[0]);
+
+static const CK_ATTRIBUTE_TYPE dhPubKeyAttrs[] = {
+    CKA_PRIME, CKA_BASE, CKA_VALUE
+};
+static const CK_ULONG dhPubKeyAttrsCount = 
+			sizeof(dhPubKeyAttrs)/sizeof(dhPubKeyAttrs[0]);
+#ifdef NSS_ENABLE_ECC
+static const CK_ATTRIBUTE_TYPE ecPubKeyAttrs[] = {
+    CKA_EC_PARAMS, CKA_EC_POINT
+};
+static const CK_ULONG ecPubKeyAttrsCount = 
+			sizeof(ecPubKeyAttrs)/sizeof(ecPubKeyAttrs[0]);
+#endif
+
+static const CK_ATTRIBUTE_TYPE commonPrivKeyAttrs[] = {
+    CKA_DECRYPT, CKA_SIGN, CKA_SIGN_RECOVER, CKA_UNWRAP, CKA_SUBJECT,
+    CKA_SENSITIVE, CKA_EXTRACTABLE, CKA_NETSCAPE_DB
+};
+static const CK_ULONG commonPrivKeyAttrsCount = 
+		sizeof(commonPrivKeyAttrs)/sizeof(commonPrivKeyAttrs[0]);
+
+static const CK_ATTRIBUTE_TYPE rsaPrivKeyAttrs[] = {
+    CKA_MODULUS, CKA_PUBLIC_EXPONENT, CKA_PRIVATE_EXPONENT, 
+    CKA_PRIME_1, CKA_PRIME_2, CKA_EXPONENT_1, CKA_EXPONENT_2, CKA_COEFFICIENT
+};
+static const CK_ULONG rsaPrivKeyAttrsCount = 
+			sizeof(rsaPrivKeyAttrs)/sizeof(rsaPrivKeyAttrs[0]);
+
+static const CK_ATTRIBUTE_TYPE dsaPrivKeyAttrs[] = {
+    CKA_SUBPRIME, CKA_PRIME, CKA_BASE, CKA_VALUE
+};
+static const CK_ULONG dsaPrivKeyAttrsCount = 
+			sizeof(dsaPrivKeyAttrs)/sizeof(dsaPrivKeyAttrs[0]);
+
+static const CK_ATTRIBUTE_TYPE dhPrivKeyAttrs[] = {
+    CKA_PRIME, CKA_BASE, CKA_VALUE
+};
+static const CK_ULONG dhPrivKeyAttrsCount = 
+			sizeof(dhPrivKeyAttrs)/sizeof(dhPrivKeyAttrs[0]);
+#ifdef NSS_ENABLE_ECC
+static const CK_ATTRIBUTE_TYPE ecPrivKeyAttrs[] = {
+    CKA_EC_PARAMS, CKA_VALUE
+};
+static const CK_ULONG ecPrivKeyAttrsCount = 
+			sizeof(ecPrivKeyAttrs)/sizeof(ecPrivKeyAttrs[0]);
+#endif
+
+static const CK_ATTRIBUTE_TYPE certAttrs[] = {
+    CKA_CERTIFICATE_TYPE, CKA_VALUE, CKA_SUBJECT, CKA_ISSUER, CKA_SERIAL_NUMBER
+};
+static const CK_ULONG certAttrsCount = 
+		sizeof(certAttrs)/sizeof(certAttrs[0]);
+
+static const CK_ATTRIBUTE_TYPE trustAttrs[] = {
+    CKA_ISSUER, CKA_SERIAL_NUMBER, CKA_CERT_SHA1_HASH, CKA_CERT_MD5_HASH,
+    CKA_TRUST_SERVER_AUTH, CKA_TRUST_CLIENT_AUTH, CKA_TRUST_EMAIL_PROTECTION,
+    CKA_TRUST_CODE_SIGNING, CKA_TRUST_STEP_UP_APPROVED
+};
+static const CK_ULONG trustAttrsCount = 
+		sizeof(trustAttrs)/sizeof(trustAttrs[0]);
+
+static const CK_ATTRIBUTE_TYPE smimeAttrs[] = {
+    CKA_SUBJECT, CKA_NETSCAPE_EMAIL, CKA_NETSCAPE_SMIME_TIMESTAMP, CKA_VALUE
+};
+static const CK_ULONG smimeAttrsCount = 
+		sizeof(smimeAttrs)/sizeof(smimeAttrs[0]);
+
+static const CK_ATTRIBUTE_TYPE crlAttrs[] = {
+    CKA_SUBJECT, CKA_VALUE, CKA_NETSCAPE_URL, CKA_NETSCAPE_KRL
+};
+static const CK_ULONG crlAttrsCount = 
+		sizeof(crlAttrs)/sizeof(crlAttrs[0]);
+
+/* copy an object based on it's table */
+CK_RV
+stfk_CopyTokenAttributes(SFTKObject *destObject,SFTKTokenObject *src_to,
+	const CK_ATTRIBUTE_TYPE *attrArray, CK_ULONG attrCount)
+{
+    SFTKAttribute *attribute;
+    SFTKAttribute *newAttribute;
+    CK_RV crv = CKR_OK;
+    int i;
+
+    for (i=0; i < attrCount; i++) {
+	if (!sftk_hasAttribute(destObject,attrArray[i])) {
+	    attribute =sftk_FindAttribute(&src_to->obj, attrArray[i]);
+	    if (!attribute) {
+		continue; /* return CKR_ATTRIBUTE_VALUE_INVALID; */
+	    }
+	    /* we need to copy the attribute since each attribute
+	     * only has one set of link list pointers */
+	    newAttribute = sftk_NewAttribute( destObject,
+				sftk_attr_expand(&attribute->attrib));
+	    sftk_FreeAttribute(attribute); /* free the old attribute */
+	    if (!newAttribute) {
+		return CKR_HOST_MEMORY;
+	    }
+	    sftk_AddAttribute(destObject,newAttribute);
+	}
+    }
+    return crv;
+}
+
+CK_RV
+stfk_CopyTokenPrivateKey(SFTKObject *destObject,SFTKTokenObject *src_to)
+{
+    CK_RV crv;
+    CK_KEY_TYPE key_type;
+    SFTKAttribute *attribute;
+
+    /* copy the common attributes for all keys first */
+    crv = stfk_CopyTokenAttributes(destObject, src_to, commonKeyAttrs,
+							commonKeyAttrsCount);
+    if (crv != CKR_OK) {
+	goto fail;
+    }
+    /* copy the common attributes for all private keys next */
+    crv = stfk_CopyTokenAttributes(destObject, src_to, commonPrivKeyAttrs,
+							commonKeyAttrsCount);
+    if (crv != CKR_OK) {
+	goto fail;
+    }
+    attribute =sftk_FindAttribute(&src_to->obj, CKA_KEY_TYPE);
+    PORT_Assert(attribute); /* if it wasn't here, ww should have failed
+			     * copying the common attributes */
+    if (!attribute) {
+	/* OK, so CKR_ATTRIBUTE_VALUE_INVALID is the immediate error, but
+	 * the fact is, the only reason we couldn't get the attribute would
+	 * be a memory error or database error (an error in the 'device').
+	 * if we have a database error code, we could return it here */
+	crv = CKR_DEVICE_ERROR;
+	goto fail;
+    }
+    key_type = *(CK_KEY_TYPE *)attribute->attrib.pValue;
+    sftk_FreeAttribute(attribute);
+    
+    /* finally copy the attributes for various private key types */
+    switch (key_type) {
+    case CKK_RSA:
+	crv = stfk_CopyTokenAttributes(destObject, src_to, rsaPrivKeyAttrs,
+							rsaPrivKeyAttrsCount);
+	break;
+    case CKK_DSA:
+	crv = stfk_CopyTokenAttributes(destObject, src_to, dsaPrivKeyAttrs,
+							dsaPrivKeyAttrsCount);
+	break;
+    case CKK_DH:
+	crv = stfk_CopyTokenAttributes(destObject, src_to, dhPrivKeyAttrs,
+							dhPrivKeyAttrsCount);
+	break;
+#ifdef NSS_ENABLE_ECC
+    case CKK_ECC:
+	crv = stfk_CopyTokenAttributes(destObject, src_to, eccPrivKeyAttrs,
+							eccPrivKeyAttrsCount);
+	break;
+#endif
+     default:
+	crv = CKR_DEVICE_ERROR; /* shouldn't happen unless we store more types
+				* of token keys into our database. */
+    }
+fail:
+    return crv;
+}
+
+CK_RV
+stfk_CopyTokenPublicKey(SFTKObject *destObject,SFTKTokenObject *src_to)
+{
+    CK_RV crv;
+    CK_KEY_TYPE key_type;
+    SFTKAttribute *attribute;
+
+    /* copy the common attributes for all keys first */
+    crv = stfk_CopyTokenAttributes(destObject, src_to, commonKeyAttrs,
+							commonKeyAttrsCount);
+    if (crv != CKR_OK) {
+	goto fail;
+    }
+
+    /* copy the common attributes for all public keys next */
+    crv = stfk_CopyTokenAttributes(destObject, src_to, commonPubKeyAttrs,
+							commonPubKeyAttrsCount);
+    if (crv != CKR_OK) {
+	goto fail;
+    }
+    attribute =sftk_FindAttribute(&src_to->obj, CKA_KEY_TYPE);
+    PORT_Assert(attribute); /* if it wasn't here, ww should have failed
+			     * copying the common attributes */
+    if (!attribute) {
+	/* OK, so CKR_ATTRIBUTE_VALUE_INVALID is the immediate error, but
+	 * the fact is, the only reason we couldn't get the attribute would
+	 * be a memory error or database error (an error in the 'device').
+	 * if we have a database error code, we could return it here */
+	crv = CKR_DEVICE_ERROR;
+	goto fail;
+    }
+    key_type = *(CK_KEY_TYPE *)attribute->attrib.pValue;
+    sftk_FreeAttribute(attribute);
+    
+    /* finally copy the attributes for various public key types */
+    switch (key_type) {
+    case CKK_RSA:
+	crv = stfk_CopyTokenAttributes(destObject, src_to, rsaPubKeyAttrs,
+							rsaPubKeyAttrsCount);
+	break;
+    case CKK_DSA:
+	crv = stfk_CopyTokenAttributes(destObject, src_to, dsaPubKeyAttrs,
+							dsaPubKeyAttrsCount);
+	break;
+    case CKK_DH:
+	crv = stfk_CopyTokenAttributes(destObject, src_to, dhPubKeyAttrs,
+							dhPubKeyAttrsCount);
+	break;
+#ifdef NSS_ENABLE_ECC
+    case CKK_ECC:
+	crv = stfk_CopyTokenAttributes(destObject, src_to, eccPubKeyAttrs,
+							eccPubKeyAttrsCount);
+	break;
+#endif
+     default:
+	crv = CKR_DEVICE_ERROR; /* shouldn't happen unless we store more types
+				* of token keys into our database. */
+    }
+fail:
+    return crv;
+}
+CK_RV
+stfk_CopyTokenSecretKey(SFTKObject *destObject,SFTKTokenObject *src_to)
+{
+    CK_RV crv;
+    crv = stfk_CopyTokenAttributes(destObject, src_to, commonKeyAttrs,
+							commonKeyAttrsCount);
+    if (crv != CKR_OK) {
+	goto fail;
+    }
+    crv = stfk_CopyTokenAttributes(destObject, src_to, secretKeyAttrs,
+							secretKeyAttrsCount);
+fail:
+    return crv;
+}
+
+/*
+ * Copy a token object. We need to explicitly copy the relevant
+ * attributes since token objects don't store those attributes in
+ * the token itself.
+ */
+CK_RV
+sftk_CopyTokenObject(SFTKObject *destObject,SFTKObject *srcObject)
+{
+    SFTKTokenObject *src_to = sftk_narrowToTokenObject(srcObject);
+    CK_RV crv;
+
+    PORT_Assert(src_to);
+    if (src_to == NULL) {
+	return CKR_DEVICE_ERROR; /* internal state inconsistant */
+    }
+
+    crv = stfk_CopyTokenAttributes(destObject, src_to, commonAttrs,
+							commonAttrsCount);
+    if (crv != CKR_OK) {
+	goto fail;
+    }
+    switch (src_to->obj.objclass) {
+    case CKO_CERTIFICATE:
+	crv = stfk_CopyTokenAttributes(destObject, src_to, certAttrs,
+							certAttrsCount);
+ 	break;
+    case CKO_NETSCAPE_TRUST:
+	crv = stfk_CopyTokenAttributes(destObject, src_to, trustAttrs,
+							trustAttrsCount);
+	break;
+    case CKO_NETSCAPE_SMIME:
+	crv = stfk_CopyTokenAttributes(destObject, src_to, smimeAttrs,
+							smimeAttrsCount);
+	break;
+    case CKO_NETSCAPE_CRL:
+	crv = stfk_CopyTokenAttributes(destObject, src_to, crlAttrs,
+							crlAttrsCount);
+	break;
+    case CKO_PRIVATE_KEY:
+	crv = stfk_CopyTokenPrivateKey(destObject,src_to);
+	break;
+    case CKO_PUBLIC_KEY:
+	crv = stfk_CopyTokenPublicKey(destObject,src_to);
+	break;
+    case CKO_SECRET_KEY:
+	crv = stfk_CopyTokenSecretKey(destObject,src_to);
+	break;
+    default:
+	crv = CKR_DEVICE_ERROR; /* shouldn't happen unless we store more types
+				* of token keys into our database. */
+    }
+fail:
+    return crv;
+}
+
+/*
  * copy the attributes from one object to another. Don't overwrite existing
  * attributes. NOTE: This is a pretty expensive operation since it
  * grabs the attribute locks for the src object for a *long* time.
  */
 CK_RV
 sftk_CopyObject(SFTKObject *destObject,SFTKObject *srcObject)
 {
     SFTKAttribute *attribute;
     SFTKSessionObject *src_so = sftk_narrowToSessionObject(srcObject);
     unsigned int i;
 
     if (src_so == NULL) {
-	return CKR_DEVICE_ERROR; /* can't copy token objects yet */
+	return sftk_CopyTokenObject(destObject,srcObject); 
     }
 
     PZ_Lock(src_so->attributeLock);
     for(i=0; i < src_so->hashSize; i++) {
 	attribute = src_so->head[i];
 	do {
 	    if (attribute) {
 		if (!sftk_hasAttribute(destObject,attribute->handle)) {
@@ -2415,16 +2772,17 @@ sftk_CopyObject(SFTKObject *destObject,S
 		    }
 		    sftk_AddAttribute(destObject,newAttribute);
 		}
 		attribute=attribute->next;
 	    }
 	} while (attribute != NULL);
     }
     PZ_Unlock(src_so->attributeLock);
+
     return CKR_OK;
 }
 
 /*
  * ******************** Search Utilities *******************************
  */
 
 /* add an object to a search list */