Back to index

lightning-sunbird  0.9+nobinonly
pkcs11u.c
Go to the documentation of this file.
00001 /* ***** BEGIN LICENSE BLOCK *****
00002  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00003  *
00004  * The contents of this file are subject to the Mozilla Public License Version
00005  * 1.1 (the "License"); you may not use this file except in compliance with
00006  * the License. You may obtain a copy of the License at
00007  * http://www.mozilla.org/MPL/
00008  *
00009  * Software distributed under the License is distributed on an "AS IS" basis,
00010  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00011  * for the specific language governing rights and limitations under the
00012  * License.
00013  *
00014  * The Original Code is the Netscape security libraries.
00015  *
00016  * The Initial Developer of the Original Code is
00017  * Netscape Communications Corporation.
00018  * Portions created by the Initial Developer are Copyright (C) 1994-2000
00019  * the Initial Developer. All Rights Reserved.
00020  *
00021  * Contributor(s):
00022  *   Dr Vipul Gupta <vipul.gupta@sun.com>, Sun Microsystems Laboratories
00023  *
00024  * Alternatively, the contents of this file may be used under the terms of
00025  * either the GNU General Public License Version 2 or later (the "GPL"), or
00026  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00027  * in which case the provisions of the GPL or the LGPL are applicable instead
00028  * of those above. If you wish to allow use of your version of this file only
00029  * under the terms of either the GPL or the LGPL, and not to allow others to
00030  * use your version of this file under the terms of the MPL, indicate your
00031  * decision by deleting the provisions above and replace them with the notice
00032  * and other provisions required by the GPL or the LGPL. If you do not delete
00033  * the provisions above, a recipient may use your version of this file under
00034  * the terms of any one of the MPL, the GPL or the LGPL.
00035  *
00036  * ***** END LICENSE BLOCK ***** */
00037 /*
00038  * Internal PKCS #11 functions. Should only be called by pkcs11.c
00039  */
00040 #include "pkcs11.h"
00041 #include "pkcs11i.h"
00042 #include "pcertt.h"
00043 #include "lowkeyi.h"
00044 #include "pcert.h"
00045 #include "secasn1.h"
00046 #include "blapi.h"
00047 #include "secerr.h"
00048 #include "prnetdb.h" /* for PR_ntohl */
00049 
00050 /*
00051  * ******************** Attribute Utilities *******************************
00052  */
00053 
00054 /*
00055  * create a new attribute with type, value, and length. Space is allocated
00056  * to hold value.
00057  */
00058 static SFTKAttribute *
00059 sftk_NewAttribute(SFTKObject *object,
00060        CK_ATTRIBUTE_TYPE type, CK_VOID_PTR value, CK_ULONG len)
00061 {
00062     SFTKAttribute *attribute;
00063 
00064     SFTKSessionObject *so = sftk_narrowToSessionObject(object);
00065     int index;
00066 
00067     if (so == NULL)  {
00068        /* allocate new attribute in a buffer */
00069        PORT_Assert(0);
00070        return NULL;
00071     }
00072     /* 
00073      * We attempt to keep down contention on Malloc and Arena locks by
00074      * limiting the number of these calls on high traversed paths. This
00075      * is done for attributes by 'allocating' them from a pool already
00076      * allocated by the parent object.
00077      */
00078     PZ_Lock(so->attributeLock);
00079     index = so->nextAttr++;
00080     PZ_Unlock(so->attributeLock);
00081     PORT_Assert(index < MAX_OBJS_ATTRS);
00082     if (index >= MAX_OBJS_ATTRS) return NULL;
00083 
00084     attribute = &so->attrList[index];
00085     attribute->attrib.type = type;
00086     attribute->freeAttr = PR_FALSE;
00087     attribute->freeData = PR_FALSE;
00088     if (value) {
00089         if (len <= ATTR_SPACE) {
00090            attribute->attrib.pValue = attribute->space;
00091        } else {
00092            attribute->attrib.pValue = PORT_Alloc(len);
00093            attribute->freeData = PR_TRUE;
00094        }
00095        if (attribute->attrib.pValue == NULL) {
00096            return NULL;
00097        }
00098        PORT_Memcpy(attribute->attrib.pValue,value,len);
00099        attribute->attrib.ulValueLen = len;
00100     } else {
00101        attribute->attrib.pValue = NULL;
00102        attribute->attrib.ulValueLen = 0;
00103     }
00104     attribute->attrib.type = type;
00105     attribute->handle = type;
00106     attribute->next = attribute->prev = NULL;
00107     return attribute;
00108 }
00109 
00110 static SFTKAttribute *
00111 sftk_NewTokenAttribute(CK_ATTRIBUTE_TYPE type, CK_VOID_PTR value,
00112                                           CK_ULONG len, PRBool copy)
00113 {
00114     SFTKAttribute *attribute;
00115 
00116     attribute = (SFTKAttribute*)PORT_Alloc(sizeof(SFTKAttribute));
00117 
00118     if (attribute == NULL) return NULL;
00119     attribute->attrib.type = type;
00120     attribute->handle = type;
00121     attribute->next = attribute->prev = NULL;
00122     attribute->freeAttr = PR_TRUE;
00123     attribute->freeData = PR_FALSE;
00124     attribute->attrib.type = type;
00125     if (!copy) {
00126        attribute->attrib.pValue = value;
00127        attribute->attrib.ulValueLen = len;
00128        return attribute;
00129     }
00130 
00131     if (value) {
00132         if (len <= ATTR_SPACE) {
00133            attribute->attrib.pValue = attribute->space;
00134        } else {
00135            attribute->attrib.pValue = PORT_Alloc(len);
00136            attribute->freeData = PR_TRUE;
00137        }
00138        if (attribute->attrib.pValue == NULL) {
00139            PORT_Free(attribute);
00140            return NULL;
00141        }
00142        PORT_Memcpy(attribute->attrib.pValue,value,len);
00143        attribute->attrib.ulValueLen = len;
00144     } else {
00145        attribute->attrib.pValue = NULL;
00146        attribute->attrib.ulValueLen = 0;
00147     }
00148     return attribute;
00149 }
00150 
00151 static SFTKAttribute *
00152 sftk_NewTokenAttributeSigned(CK_ATTRIBUTE_TYPE type, CK_VOID_PTR value, 
00153                                           CK_ULONG len, PRBool copy)
00154 {
00155     unsigned char * dval = (unsigned char *)value;
00156     if (*dval == 0) {
00157        dval++;
00158        len--;
00159     }
00160     return sftk_NewTokenAttribute(type,dval,len,copy);
00161 }
00162 
00163 /*
00164  * Free up all the memory associated with an attribute. Reference count
00165  * must be zero to call this.
00166  */
00167 static void
00168 sftk_DestroyAttribute(SFTKAttribute *attribute)
00169 {
00170     if (attribute->freeData) {
00171        if (attribute->attrib.pValue) {
00172            /* clear out the data in the attribute value... it may have been
00173             * sensitive data */
00174            PORT_Memset(attribute->attrib.pValue, 0,
00175                                           attribute->attrib.ulValueLen);
00176        }
00177        PORT_Free(attribute->attrib.pValue);
00178     }
00179     PORT_Free(attribute);
00180 }
00181 
00182 /*
00183  * release a reference to an attribute structure
00184  */
00185 void
00186 sftk_FreeAttribute(SFTKAttribute *attribute)
00187 {
00188     if (attribute->freeAttr) {
00189        sftk_DestroyAttribute(attribute);
00190        return;
00191     }
00192 }
00193 
00194 #define SFTK_DEF_ATTRIBUTE(value,len) \
00195    { NULL, NULL, PR_FALSE, PR_FALSE, 0, { 0, value, len } }
00196 
00197 #define SFTK_CLONE_ATTR(type, staticAttr) \
00198     sftk_NewTokenAttribute( type, staticAttr.attrib.pValue, \
00199     staticAttr.attrib.ulValueLen, PR_FALSE)
00200 
00201 CK_BBOOL sftk_staticTrueValue = CK_TRUE;
00202 CK_BBOOL sftk_staticFalseValue = CK_FALSE;
00203 static const SFTKAttribute sftk_StaticTrueAttr = 
00204   SFTK_DEF_ATTRIBUTE(&sftk_staticTrueValue,sizeof(sftk_staticTrueValue));
00205 static const SFTKAttribute sftk_StaticFalseAttr = 
00206   SFTK_DEF_ATTRIBUTE(&sftk_staticFalseValue,sizeof(sftk_staticFalseValue));
00207 static const SFTKAttribute sftk_StaticNullAttr = SFTK_DEF_ATTRIBUTE(NULL,0);
00208 char sftk_StaticOneValue = 1;
00209 static const SFTKAttribute sftk_StaticOneAttr = 
00210   SFTK_DEF_ATTRIBUTE(&sftk_StaticOneValue,sizeof(sftk_StaticOneValue));
00211 
00212 CK_CERTIFICATE_TYPE sftk_staticX509Value = CKC_X_509;
00213 static const SFTKAttribute sftk_StaticX509Attr =
00214   SFTK_DEF_ATTRIBUTE(&sftk_staticX509Value, sizeof(sftk_staticX509Value));
00215 CK_TRUST sftk_staticTrustedValue = CKT_NETSCAPE_TRUSTED;
00216 CK_TRUST sftk_staticTrustedDelegatorValue = CKT_NETSCAPE_TRUSTED_DELEGATOR;
00217 CK_TRUST sftk_staticValidDelegatorValue = CKT_NETSCAPE_VALID_DELEGATOR;
00218 CK_TRUST sftk_staticUnTrustedValue = CKT_NETSCAPE_UNTRUSTED;
00219 CK_TRUST sftk_staticTrustUnknownValue = CKT_NETSCAPE_TRUST_UNKNOWN;
00220 CK_TRUST sftk_staticValidPeerValue = CKT_NETSCAPE_VALID;
00221 CK_TRUST sftk_staticMustVerifyValue = CKT_NETSCAPE_MUST_VERIFY;
00222 static const SFTKAttribute sftk_StaticTrustedAttr =
00223   SFTK_DEF_ATTRIBUTE(&sftk_staticTrustedValue,
00224                             sizeof(sftk_staticTrustedValue));
00225 static const SFTKAttribute sftk_StaticTrustedDelegatorAttr =
00226   SFTK_DEF_ATTRIBUTE(&sftk_staticTrustedDelegatorValue,
00227                             sizeof(sftk_staticTrustedDelegatorValue));
00228 static const SFTKAttribute sftk_StaticValidDelegatorAttr =
00229   SFTK_DEF_ATTRIBUTE(&sftk_staticValidDelegatorValue,
00230                             sizeof(sftk_staticValidDelegatorValue));
00231 static const SFTKAttribute sftk_StaticUnTrustedAttr =
00232   SFTK_DEF_ATTRIBUTE(&sftk_staticUnTrustedValue,
00233                             sizeof(sftk_staticUnTrustedValue));
00234 static const SFTKAttribute sftk_StaticTrustUnknownAttr =
00235   SFTK_DEF_ATTRIBUTE(&sftk_staticTrustUnknownValue,
00236                             sizeof(sftk_staticTrustUnknownValue));
00237 static const SFTKAttribute sftk_StaticValidPeerAttr =
00238   SFTK_DEF_ATTRIBUTE(&sftk_staticValidPeerValue,
00239                             sizeof(sftk_staticValidPeerValue));
00240 static const SFTKAttribute sftk_StaticMustVerifyAttr =
00241   SFTK_DEF_ATTRIBUTE(&sftk_staticMustVerifyValue,
00242                             sizeof(sftk_staticMustVerifyValue));
00243 
00244 /*
00245  * helper functions which get the database and call the underlying 
00246  * low level database function.
00247  */
00248 static char *
00249 sftk_FindKeyNicknameByPublicKey(SFTKSlot *slot, SECItem *dbKey)
00250 {
00251     NSSLOWKEYDBHandle *keyHandle;
00252     char * label;
00253 
00254     keyHandle = sftk_getKeyDB(slot);
00255     if (!keyHandle) {
00256        return NULL;
00257     }
00258 
00259     label = nsslowkey_FindKeyNicknameByPublicKey(keyHandle, dbKey, 
00260                                            slot->password);
00261     sftk_freeKeyDB(keyHandle);
00262     return label;
00263 }
00264 
00265 
00266 NSSLOWKEYPrivateKey *
00267 sftk_FindKeyByPublicKey(SFTKSlot *slot, SECItem *dbKey)
00268 {
00269     NSSLOWKEYPrivateKey *privKey;
00270     NSSLOWKEYDBHandle   *keyHandle;
00271 
00272     keyHandle = sftk_getKeyDB(slot);
00273     if (keyHandle == NULL) {
00274        return NULL;
00275     }
00276     privKey = nsslowkey_FindKeyByPublicKey(keyHandle, dbKey, slot->password);
00277     sftk_freeKeyDB(keyHandle);
00278     if (privKey == NULL) {
00279        return NULL;
00280     }
00281     return privKey;
00282 }
00283 
00284 static certDBEntrySMime *
00285 sftk_getSMime(SFTKTokenObject *object)
00286 {
00287     certDBEntrySMime *entry;
00288     NSSLOWCERTCertDBHandle *certHandle;
00289 
00290     if (object->obj.objclass != CKO_NETSCAPE_SMIME) {
00291        return NULL;
00292     }
00293     if (object->obj.objectInfo) {
00294        return (certDBEntrySMime *)object->obj.objectInfo;
00295     }
00296 
00297     certHandle = sftk_getCertDB(object->obj.slot);
00298     if (!certHandle) {
00299        return NULL;
00300     }
00301     entry = nsslowcert_ReadDBSMimeEntry(certHandle, (char *)object->dbKey.data);
00302     object->obj.objectInfo = (void *)entry;
00303     object->obj.infoFree = (SFTKFree) nsslowcert_DestroyDBEntry;
00304     sftk_freeCertDB(certHandle);
00305     return entry;
00306 }
00307 
00308 static certDBEntryRevocation *
00309 sftk_getCrl(SFTKTokenObject *object)
00310 {
00311     certDBEntryRevocation *crl;
00312     PRBool isKrl;
00313     NSSLOWCERTCertDBHandle *certHandle;
00314 
00315     if (object->obj.objclass != CKO_NETSCAPE_CRL) {
00316        return NULL;
00317     }
00318     if (object->obj.objectInfo) {
00319        return (certDBEntryRevocation *)object->obj.objectInfo;
00320     }
00321 
00322     isKrl = (PRBool) (object->obj.handle == SFTK_TOKEN_KRL_HANDLE);
00323     certHandle = sftk_getCertDB(object->obj.slot);
00324     if (!certHandle) {
00325        return NULL;
00326     }
00327 
00328     crl = nsslowcert_FindCrlByKey(certHandle, &object->dbKey, isKrl);
00329     object->obj.objectInfo = (void *)crl;
00330     object->obj.infoFree = (SFTKFree) nsslowcert_DestroyDBEntry;
00331     sftk_freeCertDB(certHandle);
00332     return crl;
00333 }
00334 
00335 static NSSLOWCERTCertificate *
00336 sftk_getCert(SFTKTokenObject *object, NSSLOWCERTCertDBHandle *certHandle)
00337 {
00338     NSSLOWCERTCertificate *cert;
00339     CK_OBJECT_CLASS objClass = object->obj.objclass;
00340 
00341     if ((objClass != CKO_CERTIFICATE) && (objClass != CKO_NETSCAPE_TRUST)) {
00342        return NULL;
00343     }
00344     if (objClass == CKO_CERTIFICATE && object->obj.objectInfo) {
00345        return (NSSLOWCERTCertificate *)object->obj.objectInfo;
00346     }
00347     cert = nsslowcert_FindCertByKey(certHandle, &object->dbKey);
00348     if (objClass == CKO_CERTIFICATE) {
00349        object->obj.objectInfo = (void *)cert;
00350        object->obj.infoFree = (SFTKFree) nsslowcert_DestroyCertificate ;
00351     }
00352     return cert;
00353 }
00354 
00355 static NSSLOWCERTTrust *
00356 sftk_getTrust(SFTKTokenObject *object)
00357 {
00358     NSSLOWCERTTrust *trust;
00359     NSSLOWCERTCertDBHandle *certHandle;
00360 
00361     if (object->obj.objclass != CKO_NETSCAPE_TRUST) {
00362        return NULL;
00363     }
00364     if (object->obj.objectInfo) {
00365        return (NSSLOWCERTTrust *)object->obj.objectInfo;
00366     }
00367     certHandle = sftk_getCertDB(object->obj.slot);
00368     if (!certHandle) {
00369        return NULL;
00370     }
00371     trust = nsslowcert_FindTrustByKey(certHandle, &object->dbKey);
00372     object->obj.objectInfo = (void *)trust;
00373     object->obj.infoFree = (SFTKFree) nsslowcert_DestroyTrust ;
00374     sftk_freeCertDB(certHandle);
00375     return trust;
00376 }
00377 
00378 static NSSLOWKEYPublicKey *
00379 sftk_GetPublicKey(SFTKTokenObject *object)
00380 {
00381     NSSLOWKEYPublicKey *pubKey;
00382     NSSLOWKEYPrivateKey *privKey;
00383 
00384     if (object->obj.objclass != CKO_PUBLIC_KEY) {
00385        return NULL;
00386     }
00387     if (object->obj.objectInfo) {
00388        return (NSSLOWKEYPublicKey *)object->obj.objectInfo;
00389     }
00390     privKey = sftk_FindKeyByPublicKey(object->obj.slot, &object->dbKey);
00391     if (privKey == NULL) {
00392        return NULL;
00393     }
00394     pubKey = nsslowkey_ConvertToPublicKey(privKey);
00395     nsslowkey_DestroyPrivateKey(privKey);
00396     object->obj.objectInfo = (void *) pubKey;
00397     object->obj.infoFree = (SFTKFree) nsslowkey_DestroyPublicKey ;
00398     return pubKey;
00399 }
00400 
00401 /*
00402  * we need two versions of sftk_GetPrivateKey. One version that takes the 
00403  * DB handle so we can pass the handle we have already acquired in,
00404  *  rather than going through the 'getKeyDB' code again, 
00405  *  which may fail the second time and another which just aquires
00406  *  the key handle from the slot (where we don't already have a key handle.
00407  * This version does the former.
00408  */
00409 static NSSLOWKEYPrivateKey *
00410 sftk_GetPrivateKeyWithDB(SFTKTokenObject *object, NSSLOWKEYDBHandle *keyHandle)
00411 {
00412     NSSLOWKEYPrivateKey *privKey;
00413 
00414     if ((object->obj.objclass != CKO_PRIVATE_KEY) && 
00415                      (object->obj.objclass != CKO_SECRET_KEY)) {
00416        return NULL;
00417     }
00418     if (object->obj.objectInfo) {
00419        return (NSSLOWKEYPrivateKey *)object->obj.objectInfo;
00420     }
00421     privKey = nsslowkey_FindKeyByPublicKey(keyHandle, &object->dbKey,
00422                                        object->obj.slot->password);
00423     if (privKey == NULL) {
00424        return NULL;
00425     }
00426     object->obj.objectInfo = (void *) privKey;
00427     object->obj.infoFree = (SFTKFree) nsslowkey_DestroyPrivateKey ;
00428     return privKey;
00429 }
00430 
00431 /* this version does the latter */
00432 static NSSLOWKEYPrivateKey *
00433 sftk_GetPrivateKey(SFTKTokenObject *object)
00434 {
00435     NSSLOWKEYDBHandle *keyHandle;
00436     NSSLOWKEYPrivateKey *privKey;
00437 
00438     keyHandle = sftk_getKeyDB(object->obj.slot);
00439     if (!keyHandle) {
00440        return NULL;
00441     }
00442     privKey = sftk_GetPrivateKeyWithDB(object, keyHandle);
00443     sftk_freeKeyDB(keyHandle);
00444     return privKey;
00445 }
00446 
00447 /* sftk_GetPubItem returns data associated with the public key.
00448  * one only needs to free the public key. This comment is here
00449  * because this sematic would be non-obvious otherwise. All callers
00450  * should include this comment.
00451  */
00452 static SECItem *
00453 sftk_GetPubItem(NSSLOWKEYPublicKey *pubKey) {
00454     SECItem *pubItem = NULL;
00455     /* get value to compare from the cert's public key */
00456     switch ( pubKey->keyType ) {
00457     case NSSLOWKEYRSAKey:
00458            pubItem = &pubKey->u.rsa.modulus;
00459            break;
00460     case NSSLOWKEYDSAKey:
00461            pubItem = &pubKey->u.dsa.publicValue;
00462            break;
00463     case NSSLOWKEYDHKey:
00464            pubItem = &pubKey->u.dh.publicValue;
00465            break;
00466 #ifdef NSS_ENABLE_ECC
00467     case NSSLOWKEYECKey:
00468            pubItem = &pubKey->u.ec.publicValue;
00469            break;
00470 #endif /* NSS_ENABLE_ECC */
00471     default:
00472            break;
00473     }
00474     return pubItem;
00475 }
00476 
00477 static const SEC_ASN1Template sftk_SerialTemplate[] = {
00478     { SEC_ASN1_INTEGER, offsetof(NSSLOWCERTCertificate,serialNumber) },
00479     { 0 }
00480 };
00481 
00482 static SFTKAttribute *
00483 sftk_FindRSAPublicKeyAttribute(NSSLOWKEYPublicKey *key, CK_ATTRIBUTE_TYPE type)
00484 {
00485     unsigned char hash[SHA1_LENGTH];
00486     CK_KEY_TYPE keyType = CKK_RSA;
00487 
00488     switch (type) {
00489     case CKA_KEY_TYPE:
00490        return sftk_NewTokenAttribute(type,&keyType,sizeof(keyType), PR_TRUE);
00491     case CKA_ID:
00492        SHA1_HashBuf(hash,key->u.rsa.modulus.data,key->u.rsa.modulus.len);
00493        return sftk_NewTokenAttribute(type,hash,SHA1_LENGTH, PR_TRUE);
00494     case CKA_DERIVE:
00495        return SFTK_CLONE_ATTR(type,sftk_StaticFalseAttr);
00496     case CKA_ENCRYPT:
00497     case CKA_VERIFY:
00498     case CKA_VERIFY_RECOVER:
00499     case CKA_WRAP:
00500        return SFTK_CLONE_ATTR(type,sftk_StaticTrueAttr);
00501     case CKA_MODULUS:
00502        return sftk_NewTokenAttributeSigned(type,key->u.rsa.modulus.data,
00503                                    key->u.rsa.modulus.len, PR_FALSE);
00504     case CKA_PUBLIC_EXPONENT:
00505        return sftk_NewTokenAttributeSigned(type,key->u.rsa.publicExponent.data,
00506                             key->u.rsa.publicExponent.len, PR_FALSE);
00507     default:
00508        break;
00509     }
00510     return NULL;
00511 }
00512 
00513 static SFTKAttribute *
00514 sftk_FindDSAPublicKeyAttribute(NSSLOWKEYPublicKey *key, CK_ATTRIBUTE_TYPE type)
00515 {
00516     unsigned char hash[SHA1_LENGTH];
00517     CK_KEY_TYPE keyType = CKK_DSA;
00518 
00519     switch (type) {
00520     case CKA_KEY_TYPE:
00521        return sftk_NewTokenAttribute(type,&keyType,sizeof(keyType), PR_TRUE);
00522     case CKA_ID:
00523        SHA1_HashBuf(hash,key->u.dsa.publicValue.data,
00524                                           key->u.dsa.publicValue.len);
00525        return sftk_NewTokenAttribute(type,hash,SHA1_LENGTH, PR_TRUE);
00526     case CKA_DERIVE:
00527     case CKA_ENCRYPT:
00528     case CKA_VERIFY_RECOVER:
00529     case CKA_WRAP:
00530        return SFTK_CLONE_ATTR(type,sftk_StaticFalseAttr);
00531     case CKA_VERIFY:
00532        return SFTK_CLONE_ATTR(type,sftk_StaticTrueAttr);
00533     case CKA_VALUE:
00534        return sftk_NewTokenAttributeSigned(type,key->u.dsa.publicValue.data,
00535                                    key->u.dsa.publicValue.len, PR_FALSE);
00536     case CKA_PRIME:
00537        return sftk_NewTokenAttributeSigned(type,key->u.dsa.params.prime.data,
00538                                    key->u.dsa.params.prime.len, PR_FALSE);
00539     case CKA_SUBPRIME:
00540        return sftk_NewTokenAttributeSigned(type,
00541                             key->u.dsa.params.subPrime.data,
00542                             key->u.dsa.params.subPrime.len, PR_FALSE);
00543     case CKA_BASE:
00544        return sftk_NewTokenAttributeSigned(type,key->u.dsa.params.base.data,
00545                                    key->u.dsa.params.base.len, PR_FALSE);
00546     default:
00547        break;
00548     }
00549     return NULL;
00550 }
00551 
00552 static SFTKAttribute *
00553 sftk_FindDHPublicKeyAttribute(NSSLOWKEYPublicKey *key, CK_ATTRIBUTE_TYPE type)
00554 {
00555     unsigned char hash[SHA1_LENGTH];
00556     CK_KEY_TYPE keyType = CKK_DH;
00557 
00558     switch (type) {
00559     case CKA_KEY_TYPE:
00560        return sftk_NewTokenAttribute(type,&keyType,sizeof(keyType), PR_TRUE);
00561     case CKA_ID:
00562        SHA1_HashBuf(hash,key->u.dh.publicValue.data,key->u.dh.publicValue.len);
00563        return sftk_NewTokenAttribute(type,hash,SHA1_LENGTH, PR_TRUE);
00564     case CKA_DERIVE:
00565        return SFTK_CLONE_ATTR(type,sftk_StaticTrueAttr);
00566     case CKA_ENCRYPT:
00567     case CKA_VERIFY:
00568     case CKA_VERIFY_RECOVER:
00569     case CKA_WRAP:
00570        return SFTK_CLONE_ATTR(type,sftk_StaticFalseAttr);
00571     case CKA_VALUE:
00572        return sftk_NewTokenAttributeSigned(type,key->u.dh.publicValue.data,
00573                                    key->u.dh.publicValue.len, PR_FALSE);
00574     case CKA_PRIME:
00575        return sftk_NewTokenAttributeSigned(type,key->u.dh.prime.data,
00576                                    key->u.dh.prime.len, PR_FALSE);
00577     case CKA_BASE:
00578        return sftk_NewTokenAttributeSigned(type,key->u.dh.base.data,
00579                                    key->u.dh.base.len, PR_FALSE);
00580     default:
00581        break;
00582     }
00583     return NULL;
00584 }
00585 
00586 #ifdef NSS_ENABLE_ECC
00587 static SFTKAttribute *
00588 sftk_FindECPublicKeyAttribute(NSSLOWKEYPublicKey *key, CK_ATTRIBUTE_TYPE type)
00589 {
00590     unsigned char hash[SHA1_LENGTH];
00591     CK_KEY_TYPE keyType = CKK_EC;
00592 
00593     switch (type) {
00594     case CKA_KEY_TYPE:
00595        return sftk_NewTokenAttribute(type,&keyType,sizeof(keyType), PR_TRUE);
00596     case CKA_ID:
00597        SHA1_HashBuf(hash, key->u.ec.publicValue.data,
00598                    key->u.ec.publicValue.len);
00599        return sftk_NewTokenAttribute(type,hash,SHA1_LENGTH, PR_TRUE);
00600     case CKA_DERIVE:
00601     case CKA_VERIFY:
00602        return SFTK_CLONE_ATTR(type,sftk_StaticTrueAttr);
00603     case CKA_ENCRYPT:
00604     case CKA_VERIFY_RECOVER:
00605     case CKA_WRAP:
00606        return SFTK_CLONE_ATTR(type,sftk_StaticFalseAttr);
00607     case CKA_EC_PARAMS:
00608         /* XXX Why is the last arg PR_FALSE? */
00609        return sftk_NewTokenAttributeSigned(type,
00610                                    key->u.ec.ecParams.DEREncoding.data,
00611                                    key->u.ec.ecParams.DEREncoding.len,
00612                                    PR_FALSE);
00613     case CKA_EC_POINT:
00614         /* XXX Why is the last arg PR_FALSE? */
00615        return sftk_NewTokenAttributeSigned(type,key->u.ec.publicValue.data,
00616                                    key->u.ec.publicValue.len, PR_FALSE);
00617     default:
00618        break;
00619     }
00620     return NULL;
00621 }
00622 #endif /* NSS_ENABLE_ECC */
00623 
00624 
00625 static SFTKAttribute *
00626 sftk_FindPublicKeyAttribute(SFTKTokenObject *object, CK_ATTRIBUTE_TYPE type)
00627 {
00628     NSSLOWKEYPublicKey   *key;
00629     SFTKAttribute *att = NULL;
00630     char *label;
00631 
00632     switch (type) {
00633     case CKA_PRIVATE:
00634     case CKA_SENSITIVE:
00635     case CKA_ALWAYS_SENSITIVE:
00636     case CKA_NEVER_EXTRACTABLE:
00637        return SFTK_CLONE_ATTR(type,sftk_StaticFalseAttr);
00638     case CKA_MODIFIABLE:
00639     case CKA_EXTRACTABLE:
00640        return SFTK_CLONE_ATTR(type,sftk_StaticTrueAttr);
00641     case CKA_LABEL:
00642         label = sftk_FindKeyNicknameByPublicKey(object->obj.slot,
00643                                           &object->dbKey);
00644        if (label == NULL) {
00645           return SFTK_CLONE_ATTR(type,sftk_StaticOneAttr);
00646        }
00647        att = sftk_NewTokenAttribute(type,label,PORT_Strlen(label), PR_TRUE);
00648        PORT_Free(label);
00649        return att;
00650     default:
00651        break;
00652     }
00653 
00654     key = sftk_GetPublicKey(object);
00655     if (key == NULL) {
00656        return NULL;
00657     }
00658 
00659     switch (key->keyType) {
00660     case NSSLOWKEYRSAKey:
00661        return sftk_FindRSAPublicKeyAttribute(key,type);
00662     case NSSLOWKEYDSAKey:
00663        return sftk_FindDSAPublicKeyAttribute(key,type);
00664     case NSSLOWKEYDHKey:
00665        return sftk_FindDHPublicKeyAttribute(key,type);
00666 #ifdef NSS_ENABLE_ECC
00667     case NSSLOWKEYECKey:
00668        return sftk_FindECPublicKeyAttribute(key,type);
00669 #endif /* NSS_ENABLE_ECC */
00670     default:
00671        break;
00672     }
00673 
00674     return NULL;
00675 }
00676 
00677 static SFTKAttribute *
00678 sftk_FindSecretKeyAttribute(SFTKTokenObject *object, CK_ATTRIBUTE_TYPE type)
00679 {
00680     NSSLOWKEYPrivateKey  *key;
00681     char *label;
00682     unsigned char *keyString;
00683     SFTKAttribute *att;
00684     int keyTypeLen;
00685     CK_ULONG keyLen;
00686     CK_KEY_TYPE keyType;
00687     PRUint32 keyTypeStorage;
00688 
00689     switch (type) {
00690     case CKA_PRIVATE:
00691     case CKA_SENSITIVE:
00692     case CKA_ALWAYS_SENSITIVE:
00693     case CKA_EXTRACTABLE:
00694     case CKA_DERIVE:
00695     case CKA_ENCRYPT:
00696     case CKA_DECRYPT:
00697     case CKA_SIGN:
00698     case CKA_VERIFY:
00699     case CKA_WRAP:
00700     case CKA_UNWRAP:
00701     case CKA_MODIFIABLE:
00702        return SFTK_CLONE_ATTR(type,sftk_StaticTrueAttr);
00703     case CKA_NEVER_EXTRACTABLE:
00704        return SFTK_CLONE_ATTR(type,sftk_StaticFalseAttr);
00705     case CKA_LABEL:
00706         label = sftk_FindKeyNicknameByPublicKey(object->obj.slot,
00707                                           &object->dbKey);
00708        if (label == NULL) {
00709           return SFTK_CLONE_ATTR(type,sftk_StaticNullAttr);
00710        }
00711        att = sftk_NewTokenAttribute(type,label,PORT_Strlen(label), PR_TRUE);
00712        PORT_Free(label);
00713        return att;
00714     case CKA_KEY_TYPE:
00715     case CKA_VALUE_LEN:
00716     case CKA_VALUE:
00717        break;
00718     default:
00719        return NULL;
00720     }
00721 
00722     key = sftk_GetPrivateKey(object);
00723     if (key == NULL) {
00724        return NULL;
00725     }
00726     switch (type) {
00727     case CKA_KEY_TYPE:
00728        /* handle legacy databases. In legacy databases key_type was stored
00729         * in host order, with any leading zeros stripped off. Only key types
00730         * under 0x1f (AES) were stored. We assume that any values which are
00731         * either 1 byte long (big endian), or have byte[0] between 0 and 
00732         * 0x7f and bytes[1]-bytes[3] equal to '0' (little endian). All other
00733         * values are assumed to be from the new database, which is always 4
00734         * bytes in network order */
00735        keyType=0;
00736        keyString = key->u.rsa.coefficient.data;
00737        keyTypeLen = key->u.rsa.coefficient.len;
00738 
00739 
00740        /*
00741         * Because of various endian and word lengths The database may have
00742         * stored the keyType value in one of the following formats:
00743         *   (kt) <= 0x1f 
00744         *                                   length data
00745         * Big Endian,     pre-3.9, all lengths: 1  (kt)
00746         * Little Endian,  pre-3.9, 32 bits:     4  (kt) 0  0  0
00747         * Little Endian,  pre-3.9, 64 bits:     8  (kt) 0  0  0   0  0  0  0
00748         * All platforms,      3.9, 32 bits:     4    0  0  0 (kt)
00749         * Big Endian,         3.9, 64 bits:     8    0  0  0 (kt) 0  0  0  0
00750         * Little  Endian,     3.9, 64 bits:     8    0  0  0  0   0  0  0 (kt)
00751         * All platforms, >= 3.9.1, all lengths: 4   (a) k1 k2 k3
00752         * where (a) is 0 or >= 0x80. currently (a) can only be 0.
00753         */
00754        /*
00755         * this key was written on a 64 bit platform with a using NSS 3.9
00756         * or earlier. Reduce the 64 bit possibilities above. We were are
00757         * through, we will only have:
00758         * 
00759         * Big Endian,     pre-3.9, all lengths: 1  (kt)
00760         * Little Endian,  pre-3.9, all lengths: 4  (kt) 0  0  0
00761         * All platforms,      3.9, all lengths: 4    0  0  0 (kt)
00762         * All platforms, => 3.9.1, all lengths: 4   (a) k1 k2 k3
00763         */
00764        if (keyTypeLen == 8) {
00765            keyTypeStorage = *(PRUint32 *) keyString;
00766            if (keyTypeStorage == 0) {
00767               keyString += sizeof(PRUint32);
00768            }
00769            keyTypeLen = 4;
00770        }
00771        /*
00772         * Now Handle:
00773         *
00774         * All platforms,      3.9, all lengths: 4    0  0  0 (kt)
00775         * All platforms, => 3.9.1, all lengths: 4   (a) k1 k2 k3
00776         *
00777         * NOTE: if  kt == 0 or ak1k2k3 == 0, the test fails and
00778         * we handle it as:
00779         *
00780         * Little Endian,  pre-3.9, all lengths: 4  (kt) 0  0  0
00781         */
00782        if (keyTypeLen == sizeof(keyTypeStorage) &&
00783             (((keyString[0] & 0x80) == 0x80) ||
00784               !((keyString[1] == 0) && (keyString[2] == 0)
00785                                        && (keyString[3] == 0))) ) {
00786            PORT_Memcpy(&keyTypeStorage, keyString, sizeof(keyTypeStorage));
00787            keyType = (CK_KEY_TYPE) PR_ntohl(keyTypeStorage);
00788        } else {
00789        /*
00790         * Now Handle:
00791         *
00792         * Big Endian,     pre-3.9, all lengths: 1  (kt)
00793         * Little Endian,  pre-3.9, all lengths: 4  (kt) 0  0  0
00794         *  -- KeyType == 0 all other cases ---: 4    0  0  0  0
00795         */
00796            keyType = (CK_KEY_TYPE) keyString[0] ;
00797         }
00798        return sftk_NewTokenAttribute(type,&keyType,sizeof(keyType),PR_TRUE);
00799     case CKA_VALUE:
00800        return sftk_NewTokenAttribute(type,key->u.rsa.privateExponent.data,
00801                             key->u.rsa.privateExponent.len, PR_FALSE);
00802     case CKA_VALUE_LEN:
00803        keyLen=key->u.rsa.privateExponent.len;
00804        return sftk_NewTokenAttribute(type, &keyLen, sizeof(CK_ULONG), PR_TRUE);
00805     }
00806 
00807     return NULL;
00808 }
00809 
00810 static SFTKAttribute *
00811 sftk_FindRSAPrivateKeyAttribute(NSSLOWKEYPrivateKey *key,
00812                             CK_ATTRIBUTE_TYPE type)
00813 {
00814     unsigned char hash[SHA1_LENGTH];
00815     CK_KEY_TYPE keyType = CKK_RSA;
00816 
00817     switch (type) {
00818     case CKA_KEY_TYPE:
00819        return sftk_NewTokenAttribute(type,&keyType,sizeof(keyType), PR_TRUE);
00820     case CKA_ID:
00821        SHA1_HashBuf(hash,key->u.rsa.modulus.data,key->u.rsa.modulus.len);
00822        return sftk_NewTokenAttribute(type,hash,SHA1_LENGTH, PR_TRUE);
00823     case CKA_DERIVE:
00824        return SFTK_CLONE_ATTR(type,sftk_StaticFalseAttr);
00825     case CKA_DECRYPT:
00826     case CKA_SIGN:
00827     case CKA_SIGN_RECOVER:
00828     case CKA_UNWRAP:
00829        return SFTK_CLONE_ATTR(type,sftk_StaticTrueAttr);
00830     case CKA_MODULUS:
00831        return sftk_NewTokenAttributeSigned(type,key->u.rsa.modulus.data,
00832                                    key->u.rsa.modulus.len, PR_FALSE);
00833     case CKA_PUBLIC_EXPONENT:
00834        return sftk_NewTokenAttributeSigned(type,key->u.rsa.publicExponent.data,
00835                             key->u.rsa.publicExponent.len, PR_FALSE);
00836     case CKA_PRIVATE_EXPONENT:
00837        return sftk_NewTokenAttributeSigned(type,
00838                             key->u.rsa.privateExponent.data,
00839                             key->u.rsa.privateExponent.len, PR_FALSE);
00840     case CKA_PRIME_1:
00841        return sftk_NewTokenAttributeSigned(type, key->u.rsa.prime1.data,
00842                             key->u.rsa.prime1.len, PR_FALSE);
00843     case CKA_PRIME_2:
00844        return sftk_NewTokenAttributeSigned(type, key->u.rsa.prime2.data,
00845                             key->u.rsa.prime2.len, PR_FALSE);
00846     case CKA_EXPONENT_1:
00847        return sftk_NewTokenAttributeSigned(type, key->u.rsa.exponent1.data,
00848                             key->u.rsa.exponent1.len, PR_FALSE);
00849     case CKA_EXPONENT_2:
00850        return sftk_NewTokenAttributeSigned(type, key->u.rsa.exponent2.data,
00851                             key->u.rsa.exponent2.len, PR_FALSE);
00852     case CKA_COEFFICIENT:
00853        return sftk_NewTokenAttributeSigned(type, key->u.rsa.coefficient.data,
00854                             key->u.rsa.coefficient.len, PR_FALSE);
00855     default:
00856        break;
00857     }
00858     return NULL;
00859 }
00860 
00861 static SFTKAttribute *
00862 sftk_FindDSAPrivateKeyAttribute(NSSLOWKEYPrivateKey *key, 
00863                                                  CK_ATTRIBUTE_TYPE type)
00864 {
00865     unsigned char hash[SHA1_LENGTH];
00866     CK_KEY_TYPE keyType = CKK_DSA;
00867 
00868     switch (type) {
00869     case CKA_KEY_TYPE:
00870        return sftk_NewTokenAttribute(type,&keyType,sizeof(keyType), PR_TRUE);
00871     case CKA_ID:
00872        SHA1_HashBuf(hash,key->u.dsa.publicValue.data,
00873                        key->u.dsa.publicValue.len);
00874        return sftk_NewTokenAttribute(type,hash,SHA1_LENGTH, PR_TRUE);
00875     case CKA_DERIVE:
00876     case CKA_DECRYPT:
00877     case CKA_SIGN_RECOVER:
00878     case CKA_UNWRAP:
00879        return SFTK_CLONE_ATTR(type,sftk_StaticFalseAttr);
00880     case CKA_SIGN:
00881        return SFTK_CLONE_ATTR(type,sftk_StaticTrueAttr);
00882     case CKA_VALUE:
00883        return sftk_NewTokenAttributeSigned(type, key->u.dsa.privateValue.data,
00884                             key->u.dsa.privateValue.len, PR_FALSE);
00885     case CKA_PRIME:
00886        return sftk_NewTokenAttributeSigned(type,key->u.dsa.params.prime.data,
00887                                    key->u.dsa.params.prime.len, PR_FALSE);
00888     case CKA_SUBPRIME:
00889        return sftk_NewTokenAttributeSigned(type,
00890                             key->u.dsa.params.subPrime.data,
00891                             key->u.dsa.params.subPrime.len, PR_FALSE);
00892     case CKA_BASE:
00893        return sftk_NewTokenAttributeSigned(type,key->u.dsa.params.base.data,
00894                                    key->u.dsa.params.base.len, PR_FALSE);
00895     case CKA_NETSCAPE_DB:
00896        return sftk_NewTokenAttributeSigned(type,
00897                                    key->u.dsa.publicValue.data,
00898                                    key->u.dsa.publicValue.len,
00899                                    PR_FALSE);
00900     default:
00901        break;
00902     }
00903     return NULL;
00904 }
00905 
00906 static SFTKAttribute *
00907 sftk_FindDHPrivateKeyAttribute(NSSLOWKEYPrivateKey *key, CK_ATTRIBUTE_TYPE type)
00908 {
00909     unsigned char hash[SHA1_LENGTH];
00910     CK_KEY_TYPE keyType = CKK_DH;
00911 
00912     switch (type) {
00913     case CKA_KEY_TYPE:
00914        return sftk_NewTokenAttribute(type,&keyType,sizeof(keyType), PR_TRUE);
00915     case CKA_ID:
00916        SHA1_HashBuf(hash,key->u.dh.publicValue.data,key->u.dh.publicValue.len);
00917        return sftk_NewTokenAttribute(type,hash,SHA1_LENGTH, PR_TRUE);
00918     case CKA_DERIVE:
00919        return SFTK_CLONE_ATTR(type,sftk_StaticTrueAttr);
00920     case CKA_DECRYPT:
00921     case CKA_SIGN:
00922     case CKA_SIGN_RECOVER:
00923     case CKA_UNWRAP:
00924        return SFTK_CLONE_ATTR(type,sftk_StaticFalseAttr);
00925     case CKA_VALUE:
00926        return sftk_NewTokenAttributeSigned(type,key->u.dh.privateValue.data,
00927                                    key->u.dh.privateValue.len, PR_FALSE);
00928     case CKA_PRIME:
00929        return sftk_NewTokenAttributeSigned(type,key->u.dh.prime.data,
00930                                    key->u.dh.prime.len, PR_FALSE);
00931     case CKA_BASE:
00932        return sftk_NewTokenAttributeSigned(type,key->u.dh.base.data,
00933                                    key->u.dh.base.len, PR_FALSE);
00934     case CKA_NETSCAPE_DB:
00935        return sftk_NewTokenAttributeSigned(type,
00936                                    key->u.dh.publicValue.data,
00937                                    key->u.dh.publicValue.len,
00938                                    PR_FALSE);
00939     default:
00940        break;
00941     }
00942     return NULL;
00943 }
00944 
00945 #ifdef NSS_ENABLE_ECC
00946 static SFTKAttribute *
00947 sftk_FindECPrivateKeyAttribute(NSSLOWKEYPrivateKey *key, CK_ATTRIBUTE_TYPE type)
00948 {
00949     unsigned char hash[SHA1_LENGTH];
00950     CK_KEY_TYPE keyType = CKK_EC;
00951 
00952     switch (type) {
00953     case CKA_KEY_TYPE:
00954        return sftk_NewTokenAttribute(type,&keyType,sizeof(keyType), PR_TRUE);
00955     case CKA_ID:
00956        SHA1_HashBuf(hash,key->u.ec.publicValue.data,key->u.ec.publicValue.len);
00957        return sftk_NewTokenAttribute(type,hash,SHA1_LENGTH, PR_TRUE);
00958     case CKA_DERIVE:
00959     case CKA_SIGN:
00960        return SFTK_CLONE_ATTR(type,sftk_StaticTrueAttr);
00961     case CKA_DECRYPT:
00962     case CKA_SIGN_RECOVER:
00963     case CKA_UNWRAP:
00964        return SFTK_CLONE_ATTR(type,sftk_StaticFalseAttr);
00965     case CKA_VALUE:
00966        return sftk_NewTokenAttributeSigned(type, key->u.ec.privateValue.data,
00967                                    key->u.ec.privateValue.len, PR_FALSE);
00968     case CKA_EC_PARAMS:
00969         /* XXX Why is the last arg PR_FALSE? */
00970        return sftk_NewTokenAttributeSigned(type,
00971                                    key->u.ec.ecParams.DEREncoding.data,
00972                                    key->u.ec.ecParams.DEREncoding.len,
00973                                    PR_FALSE);
00974     case CKA_NETSCAPE_DB:
00975        return sftk_NewTokenAttributeSigned(type,
00976                                    key->u.ec.publicValue.data,
00977                                    key->u.ec.publicValue.len,
00978                                    PR_FALSE);
00979     default:
00980        break;
00981     }
00982     return NULL;
00983 }
00984 #endif /* NSS_ENABLE_ECC */
00985 
00986 static SFTKAttribute *
00987 sftk_FindPrivateKeyAttribute(SFTKTokenObject *object, CK_ATTRIBUTE_TYPE type)
00988 {
00989     NSSLOWKEYPrivateKey  *key;
00990     char *label;
00991     SFTKAttribute *att;
00992 
00993     switch (type) {
00994     case CKA_PRIVATE:
00995     case CKA_SENSITIVE:
00996     case CKA_ALWAYS_SENSITIVE:
00997     case CKA_EXTRACTABLE:
00998     case CKA_MODIFIABLE:
00999        return SFTK_CLONE_ATTR(type,sftk_StaticTrueAttr);
01000     case CKA_NEVER_EXTRACTABLE:
01001        return SFTK_CLONE_ATTR(type,sftk_StaticFalseAttr);
01002     case CKA_SUBJECT:
01003           return SFTK_CLONE_ATTR(type,sftk_StaticNullAttr);
01004     case CKA_LABEL:
01005         label = sftk_FindKeyNicknameByPublicKey(object->obj.slot,
01006                                           &object->dbKey);
01007        if (label == NULL) {
01008           return SFTK_CLONE_ATTR(type,sftk_StaticNullAttr);
01009        }
01010        att = sftk_NewTokenAttribute(type,label,PORT_Strlen(label), PR_TRUE);
01011        PORT_Free(label);
01012        return att;
01013     default:
01014        break;
01015     }
01016     key = sftk_GetPrivateKey(object);
01017     if (key == NULL) {
01018        return NULL;
01019     }
01020     switch (key->keyType) {
01021     case NSSLOWKEYRSAKey:
01022        return sftk_FindRSAPrivateKeyAttribute(key,type);
01023     case NSSLOWKEYDSAKey:
01024        return sftk_FindDSAPrivateKeyAttribute(key,type);
01025     case NSSLOWKEYDHKey:
01026        return sftk_FindDHPrivateKeyAttribute(key,type);
01027 #ifdef NSS_ENABLE_ECC
01028     case NSSLOWKEYECKey:
01029        return sftk_FindECPrivateKeyAttribute(key,type);
01030 #endif /* NSS_ENABLE_ECC */
01031     default:
01032        break;
01033     }
01034 
01035     return NULL;
01036 }
01037 
01038 static SFTKAttribute *
01039 sftk_FindSMIMEAttribute(SFTKTokenObject *object, CK_ATTRIBUTE_TYPE type)
01040 {
01041     certDBEntrySMime *entry;
01042     switch (type) {
01043     case CKA_PRIVATE:
01044     case CKA_MODIFIABLE:
01045        return SFTK_CLONE_ATTR(type,sftk_StaticFalseAttr);
01046     case CKA_NETSCAPE_EMAIL:
01047        return sftk_NewTokenAttribute(type,object->dbKey.data,
01048                                           object->dbKey.len-1, PR_FALSE);
01049     case CKA_NETSCAPE_SMIME_TIMESTAMP:
01050     case CKA_SUBJECT:
01051     case CKA_VALUE:
01052        break;
01053     default:
01054        return NULL;
01055     }
01056     entry = sftk_getSMime(object);
01057     if (entry == NULL) {
01058        return NULL;
01059     }
01060     switch (type) {
01061     case CKA_NETSCAPE_SMIME_TIMESTAMP:
01062        return sftk_NewTokenAttribute(type,entry->optionsDate.data,
01063                                    entry->optionsDate.len, PR_FALSE);
01064     case CKA_SUBJECT:
01065        return sftk_NewTokenAttribute(type,entry->subjectName.data,
01066                                    entry->subjectName.len, PR_FALSE);
01067     case CKA_VALUE:
01068        return sftk_NewTokenAttribute(type,entry->smimeOptions.data,
01069                                    entry->smimeOptions.len, PR_FALSE);
01070     default:
01071        break;
01072     }
01073     return NULL;
01074 }
01075 
01076 static SFTKAttribute *
01077 sftk_FindTrustAttribute(SFTKTokenObject *object, CK_ATTRIBUTE_TYPE type)
01078 {
01079     NSSLOWCERTTrust *trust;
01080     unsigned char hash[SHA1_LENGTH];
01081     unsigned int trustFlags;
01082 
01083     switch (type) {
01084     case CKA_PRIVATE:
01085        return SFTK_CLONE_ATTR(type,sftk_StaticFalseAttr);
01086     case CKA_MODIFIABLE:
01087        return SFTK_CLONE_ATTR(type,sftk_StaticTrueAttr);
01088     case CKA_CERT_SHA1_HASH:
01089     case CKA_CERT_MD5_HASH:
01090     case CKA_TRUST_CLIENT_AUTH:
01091     case CKA_TRUST_SERVER_AUTH:
01092     case CKA_TRUST_EMAIL_PROTECTION:
01093     case CKA_TRUST_CODE_SIGNING:
01094     case CKA_TRUST_STEP_UP_APPROVED:
01095        break;
01096     default:
01097        return NULL;
01098     }
01099     trust = sftk_getTrust(object);
01100     if (trust == NULL) {
01101        return NULL;
01102     }
01103     switch (type) {
01104     case CKA_CERT_SHA1_HASH:
01105        SHA1_HashBuf(hash,trust->derCert->data,trust->derCert->len);
01106        return sftk_NewTokenAttribute(type, hash, SHA1_LENGTH, PR_TRUE);
01107     case CKA_CERT_MD5_HASH:
01108        MD5_HashBuf(hash,trust->derCert->data,trust->derCert->len);
01109        return sftk_NewTokenAttribute(type, hash, MD5_LENGTH, PR_TRUE);
01110     case CKA_TRUST_CLIENT_AUTH:
01111        trustFlags = trust->trust->sslFlags & CERTDB_TRUSTED_CLIENT_CA ?
01112               trust->trust->sslFlags | CERTDB_TRUSTED_CA : 0 ;
01113        goto trust;
01114     case CKA_TRUST_SERVER_AUTH:
01115        trustFlags = trust->trust->sslFlags;
01116        goto trust;
01117     case CKA_TRUST_EMAIL_PROTECTION:
01118        trustFlags = trust->trust->emailFlags;
01119        goto trust;
01120     case CKA_TRUST_CODE_SIGNING:
01121        trustFlags = trust->trust->objectSigningFlags;
01122 trust:
01123        if (trustFlags & CERTDB_TRUSTED_CA ) {
01124            return SFTK_CLONE_ATTR(type,sftk_StaticTrustedDelegatorAttr);
01125        }
01126        if (trustFlags & CERTDB_TRUSTED) {
01127            return SFTK_CLONE_ATTR(type,sftk_StaticTrustedAttr);
01128        }
01129        if (trustFlags & CERTDB_NOT_TRUSTED) {
01130            return SFTK_CLONE_ATTR(type,sftk_StaticUnTrustedAttr);
01131        }
01132        if (trustFlags & CERTDB_TRUSTED_UNKNOWN) {
01133            return SFTK_CLONE_ATTR(type,sftk_StaticTrustUnknownAttr);
01134        }
01135        if (trustFlags & CERTDB_VALID_CA) {
01136            return SFTK_CLONE_ATTR(type,sftk_StaticValidDelegatorAttr);
01137        }
01138        if (trustFlags & CERTDB_VALID_PEER) {
01139            return SFTK_CLONE_ATTR(type,sftk_StaticValidPeerAttr);
01140        }
01141        return SFTK_CLONE_ATTR(type,sftk_StaticMustVerifyAttr);
01142     case CKA_TRUST_STEP_UP_APPROVED:
01143        if (trust->trust->sslFlags & CERTDB_GOVT_APPROVED_CA) {
01144            return SFTK_CLONE_ATTR(type,sftk_StaticTrueAttr);
01145        } else {
01146            return SFTK_CLONE_ATTR(type,sftk_StaticFalseAttr);
01147        }
01148     default:
01149        break;
01150     }
01151 
01152 #ifdef notdef
01153     switch (type) {
01154     case CKA_ISSUER:
01155        cert = sftk_getCertObject(object);
01156        if (cert == NULL) break;
01157        attr = sftk_NewTokenAttribute(type,cert->derIssuer.data,
01158                                           cert->derIssuer.len, PR_FALSE);
01159        
01160     case CKA_SERIAL_NUMBER:
01161        cert = sftk_getCertObject(object);
01162        if (cert == NULL) break;
01163        item = SEC_ASN1EncodeItem(NULL,NULL,cert,sftk_SerialTemplate);
01164        if (item == NULL) break;
01165        attr = sftk_NewTokenAttribute(type, item->data, item->len, PR_TRUE);
01166        SECITEM_FreeItem(item,PR_TRUE);
01167     }
01168     if (cert) {
01169        NSSLOWCERTDestroyCertificate(cert);       
01170        return attr;
01171     }
01172 #endif
01173     return NULL;
01174 }
01175 
01176 static SFTKAttribute *
01177 sftk_FindCrlAttribute(SFTKTokenObject *object, CK_ATTRIBUTE_TYPE type)
01178 {
01179     certDBEntryRevocation *crl;
01180 
01181     switch (type) {
01182     case CKA_PRIVATE:
01183     case CKA_MODIFIABLE:
01184        return SFTK_CLONE_ATTR(type,sftk_StaticFalseAttr);
01185     case CKA_NETSCAPE_KRL:
01186        return ((object->obj.handle == SFTK_TOKEN_KRL_HANDLE) 
01187               ? SFTK_CLONE_ATTR(type,sftk_StaticTrueAttr)
01188               : SFTK_CLONE_ATTR(type,sftk_StaticFalseAttr));
01189     case CKA_SUBJECT:
01190        return sftk_NewTokenAttribute(type,object->dbKey.data,
01191                                           object->dbKey.len, PR_FALSE);      
01192     case CKA_NETSCAPE_URL:
01193     case CKA_VALUE:
01194        break;
01195     default:
01196        PORT_SetError(SEC_ERROR_INVALID_ARGS);
01197        return NULL;
01198     }
01199     crl =  sftk_getCrl(object);
01200     if (!crl) {
01201        return NULL;
01202     }
01203     switch (type) {
01204     case CKA_NETSCAPE_URL:
01205        if (crl->url == NULL) {
01206            return SFTK_CLONE_ATTR(type,sftk_StaticNullAttr);
01207        }
01208        return sftk_NewTokenAttribute(type, crl->url, 
01209                                    PORT_Strlen(crl->url)+1, PR_TRUE);
01210     case CKA_VALUE:
01211        return sftk_NewTokenAttribute(type, crl->derCrl.data, 
01212                                           crl->derCrl.len, PR_FALSE);
01213     default:
01214        break;
01215     }
01216     return NULL;
01217 }
01218 
01219 static SFTKAttribute *
01220 sftk_FindCertAttribute(SFTKTokenObject *object, CK_ATTRIBUTE_TYPE type)
01221 {
01222     NSSLOWCERTCertificate  *cert;
01223     NSSLOWCERTCertDBHandle *certHandle;
01224     NSSLOWKEYPublicKey     *pubKey;
01225     unsigned char hash[SHA1_LENGTH];
01226     SECItem *item;
01227 
01228     switch (type) {
01229     case CKA_PRIVATE:
01230        return SFTK_CLONE_ATTR(type,sftk_StaticFalseAttr);
01231     case CKA_MODIFIABLE:
01232        return SFTK_CLONE_ATTR(type,sftk_StaticTrueAttr);
01233     case CKA_CERTIFICATE_TYPE:
01234         /* hardcoding X.509 into here */
01235         return SFTK_CLONE_ATTR(type,sftk_StaticX509Attr);
01236     case CKA_VALUE:
01237     case CKA_ID:
01238     case CKA_LABEL:
01239     case CKA_SUBJECT:
01240     case CKA_ISSUER:
01241     case CKA_SERIAL_NUMBER:
01242     case CKA_NETSCAPE_EMAIL:
01243        break;
01244     default:
01245        return NULL;
01246     }
01247 
01248     certHandle = sftk_getCertDB(object->obj.slot);
01249     if (certHandle == NULL) {
01250        return NULL;
01251     }
01252 
01253     cert = sftk_getCert(object, certHandle);
01254     sftk_freeCertDB(certHandle);
01255     if (cert == NULL) {
01256        return NULL;
01257     }
01258     switch (type) {
01259     case CKA_VALUE:
01260        return sftk_NewTokenAttribute(type,cert->derCert.data,
01261                                           cert->derCert.len,PR_FALSE);
01262     case CKA_ID:
01263        if (((cert->trust->sslFlags & CERTDB_USER) == 0) &&
01264               ((cert->trust->emailFlags & CERTDB_USER) == 0) &&
01265               ((cert->trust->objectSigningFlags & CERTDB_USER) == 0)) {
01266            return SFTK_CLONE_ATTR(type,sftk_StaticNullAttr);
01267        }
01268        pubKey = nsslowcert_ExtractPublicKey(cert);
01269        if (pubKey == NULL) break;
01270        item = sftk_GetPubItem(pubKey);
01271        if (item == NULL) {
01272            nsslowkey_DestroyPublicKey(pubKey);
01273            break;
01274        }
01275        SHA1_HashBuf(hash,item->data,item->len);
01276        /* item is imbedded in pubKey, just free the key */
01277        nsslowkey_DestroyPublicKey(pubKey);
01278        return sftk_NewTokenAttribute(type, hash, SHA1_LENGTH, PR_TRUE);
01279     case CKA_LABEL:
01280        return cert->nickname 
01281               ? sftk_NewTokenAttribute(type, cert->nickname,
01282                                     PORT_Strlen(cert->nickname), PR_FALSE) 
01283               : SFTK_CLONE_ATTR(type,sftk_StaticNullAttr);
01284     case CKA_SUBJECT:
01285        return sftk_NewTokenAttribute(type,cert->derSubject.data,
01286                                           cert->derSubject.len, PR_FALSE);
01287     case CKA_ISSUER:
01288        return sftk_NewTokenAttribute(type,cert->derIssuer.data,
01289                                           cert->derIssuer.len, PR_FALSE);
01290     case CKA_SERIAL_NUMBER:
01291        return sftk_NewTokenAttribute(type,cert->derSN.data,
01292                                           cert->derSN.len, PR_FALSE);
01293     case CKA_NETSCAPE_EMAIL:
01294        return (cert->emailAddr && cert->emailAddr[0])
01295            ? sftk_NewTokenAttribute(type, cert->emailAddr,
01296                                     PORT_Strlen(cert->emailAddr), PR_FALSE) 
01297            : SFTK_CLONE_ATTR(type,sftk_StaticNullAttr);
01298     default:
01299        break;
01300     }
01301     return NULL;
01302 }
01303     
01304 static SFTKAttribute *    
01305 sftk_FindTokenAttribute(SFTKTokenObject *object,CK_ATTRIBUTE_TYPE type)
01306 {
01307     /* handle the common ones */
01308     switch (type) {
01309     case CKA_CLASS:
01310        return sftk_NewTokenAttribute(type,&object->obj.objclass,
01311                                    sizeof(object->obj.objclass),PR_FALSE);
01312     case CKA_TOKEN:
01313        return SFTK_CLONE_ATTR(type,sftk_StaticTrueAttr);
01314     case CKA_LABEL:
01315        if (  (object->obj.objclass == CKO_CERTIFICATE) 
01316           || (object->obj.objclass == CKO_PRIVATE_KEY)
01317           || (object->obj.objclass == CKO_PUBLIC_KEY)
01318           || (object->obj.objclass == CKO_SECRET_KEY)) {
01319            break;
01320        }
01321        return SFTK_CLONE_ATTR(type,sftk_StaticNullAttr);
01322     default:
01323        break;
01324     }
01325     switch (object->obj.objclass) {
01326     case CKO_CERTIFICATE:
01327        return sftk_FindCertAttribute(object,type);
01328     case CKO_NETSCAPE_CRL:
01329        return sftk_FindCrlAttribute(object,type);
01330     case CKO_NETSCAPE_TRUST:
01331        return sftk_FindTrustAttribute(object,type);
01332     case CKO_NETSCAPE_SMIME:
01333        return sftk_FindSMIMEAttribute(object,type);
01334     case CKO_PUBLIC_KEY:
01335        return sftk_FindPublicKeyAttribute(object,type);
01336     case CKO_PRIVATE_KEY:
01337        return sftk_FindPrivateKeyAttribute(object,type);
01338     case CKO_SECRET_KEY:
01339        return sftk_FindSecretKeyAttribute(object,type);
01340     default:
01341        break;
01342     }
01343     PORT_Assert(0);
01344     return NULL;
01345 } 
01346 
01347 /*
01348  * look up and attribute structure from a type and Object structure.
01349  * The returned attribute is referenced and needs to be freed when 
01350  * it is no longer needed.
01351  */
01352 SFTKAttribute *
01353 sftk_FindAttribute(SFTKObject *object,CK_ATTRIBUTE_TYPE type)
01354 {
01355     SFTKAttribute *attribute;
01356     SFTKSessionObject *sessObject = sftk_narrowToSessionObject(object);
01357 
01358     if (sessObject == NULL) {
01359        return sftk_FindTokenAttribute(sftk_narrowToTokenObject(object),type);
01360     }
01361 
01362     PZ_Lock(sessObject->attributeLock);
01363     sftkqueue_find(attribute,type,sessObject->head, sessObject->hashSize);
01364     PZ_Unlock(sessObject->attributeLock);
01365 
01366     return(attribute);
01367 }
01368 
01369 /*
01370  * Take a buffer and it's length and return it's true size in bits;
01371  */
01372 unsigned int
01373 sftk_GetLengthInBits(unsigned char *buf, unsigned int bufLen)
01374 {
01375     unsigned int size = bufLen * 8;
01376     unsigned int i;
01377 
01378     /* Get the real length in bytes */
01379     for (i=0; i < bufLen; i++) {
01380        unsigned char  c = *buf++;
01381        if (c != 0) {
01382            unsigned char m;
01383            for (m=0x80; m > 0 ;  m = m >> 1) {
01384               if ((c & m) != 0) {
01385                   break;
01386               } 
01387               size--;
01388            }
01389            break;
01390        }
01391        size-=8;
01392     }
01393     return size;
01394 }
01395 
01396 /*
01397  * Constrain a big num attribute. to size and padding
01398  * minLength means length of the object must be greater than equal to minLength
01399  * maxLength means length of the object must be less than equal to maxLength
01400  * minMultiple means that object length mod minMultiple must equal 0.
01401  * all input sizes are in bits.
01402  * if any constraint is '0' that constraint is not checked.
01403  */
01404 CK_RV
01405 sftk_ConstrainAttribute(SFTKObject *object, CK_ATTRIBUTE_TYPE type, 
01406                      int minLength, int maxLength, int minMultiple)
01407 {
01408     SFTKAttribute *attribute;
01409     int size;
01410     unsigned char *ptr;
01411 
01412     attribute = sftk_FindAttribute(object, type);
01413     if (!attribute) {
01414        return CKR_TEMPLATE_INCOMPLETE;
01415     }
01416     ptr = (unsigned char *) attribute->attrib.pValue;
01417     if (ptr == NULL) {
01418        sftk_FreeAttribute(attribute);
01419        return CKR_ATTRIBUTE_VALUE_INVALID;
01420     }
01421     size = sftk_GetLengthInBits(ptr, attribute->attrib.ulValueLen);
01422     sftk_FreeAttribute(attribute);
01423 
01424     if ((minLength != 0) && (size <  minLength)) {
01425        return CKR_ATTRIBUTE_VALUE_INVALID;
01426     }
01427     if ((maxLength != 0) && (size >  maxLength)) {
01428        return CKR_ATTRIBUTE_VALUE_INVALID;
01429     }
01430     if ((minMultiple != 0) && ((size % minMultiple) != 0)) {
01431        return CKR_ATTRIBUTE_VALUE_INVALID;
01432     }
01433     return CKR_OK;
01434 }
01435 
01436 PRBool
01437 sftk_hasAttributeToken(SFTKTokenObject *object)
01438 {
01439     return PR_FALSE;
01440 }
01441 
01442 /*
01443  * return true if object has attribute
01444  */
01445 PRBool
01446 sftk_hasAttribute(SFTKObject *object,CK_ATTRIBUTE_TYPE type)
01447 {
01448     SFTKAttribute *attribute;
01449     SFTKSessionObject *sessObject = sftk_narrowToSessionObject(object);
01450 
01451     if (sessObject == NULL) {
01452        return sftk_hasAttributeToken(sftk_narrowToTokenObject(object));
01453     }
01454 
01455     PZ_Lock(sessObject->attributeLock);
01456     sftkqueue_find(attribute,type,sessObject->head, sessObject->hashSize);
01457     PZ_Unlock(sessObject->attributeLock);
01458 
01459     return (PRBool)(attribute != NULL);
01460 }
01461 
01462 /*
01463  * add an attribute to an object
01464  */
01465 static void
01466 sftk_AddAttribute(SFTKObject *object,SFTKAttribute *attribute)
01467 {
01468     SFTKSessionObject *sessObject = sftk_narrowToSessionObject(object);
01469 
01470     if (sessObject == NULL) return;
01471     PZ_Lock(sessObject->attributeLock);
01472     sftkqueue_add(attribute,attribute->handle,
01473                             sessObject->head, sessObject->hashSize);
01474     PZ_Unlock(sessObject->attributeLock);
01475 }
01476 
01477 /* 
01478  * copy an unsigned attribute into a SECItem. Secitem is allocated in
01479  * the specified arena.
01480  */
01481 CK_RV
01482 sftk_Attribute2SSecItem(PLArenaPool *arena,SECItem *item,SFTKObject *object,
01483                                       CK_ATTRIBUTE_TYPE type)
01484 {
01485     SFTKAttribute *attribute;
01486 
01487     item->data = NULL;
01488 
01489     attribute = sftk_FindAttribute(object, type);
01490     if (attribute == NULL) return CKR_TEMPLATE_INCOMPLETE;
01491 
01492     (void)SECITEM_AllocItem(arena, item, attribute->attrib.ulValueLen);
01493     if (item->data == NULL) {
01494        sftk_FreeAttribute(attribute);
01495        return CKR_HOST_MEMORY;
01496     }
01497     PORT_Memcpy(item->data, attribute->attrib.pValue, item->len);
01498     sftk_FreeAttribute(attribute);
01499     return CKR_OK;
01500 }
01501 
01502 
01503 /*
01504  * delete an attribute from an object
01505  */
01506 static void
01507 sftk_DeleteAttribute(SFTKObject *object, SFTKAttribute *attribute)
01508 {
01509     SFTKSessionObject *sessObject = sftk_narrowToSessionObject(object);
01510 
01511     if (sessObject == NULL) {
01512        return ;
01513     }
01514     PZ_Lock(sessObject->attributeLock);
01515     if (sftkqueue_is_queued(attribute,attribute->handle,
01516                             sessObject->head, sessObject->hashSize)) {
01517        sftkqueue_delete(attribute,attribute->handle,
01518                             sessObject->head, sessObject->hashSize);
01519     }
01520     PZ_Unlock(sessObject->attributeLock);
01521 }
01522 
01523 /*
01524  * this is only valid for CK_BBOOL type attributes. Return the state
01525  * of that attribute.
01526  */
01527 PRBool
01528 sftk_isTrue(SFTKObject *object,CK_ATTRIBUTE_TYPE type)
01529 {
01530     SFTKAttribute *attribute;
01531     PRBool tok = PR_FALSE;
01532 
01533     attribute=sftk_FindAttribute(object,type);
01534     if (attribute == NULL) { return PR_FALSE; }
01535     tok = (PRBool)(*(CK_BBOOL *)attribute->attrib.pValue);
01536     sftk_FreeAttribute(attribute);
01537 
01538     return tok;
01539 }
01540 
01541 /*
01542  * force an attribute to null.
01543  * this is for sensitive keys which are stored in the database, we don't
01544  * want to keep this info around in memory in the clear.
01545  */
01546 void
01547 sftk_nullAttribute(SFTKObject *object,CK_ATTRIBUTE_TYPE type)
01548 {
01549     SFTKAttribute *attribute;
01550 
01551     attribute=sftk_FindAttribute(object,type);
01552     if (attribute == NULL) return;
01553 
01554     if (attribute->attrib.pValue != NULL) {
01555        PORT_Memset(attribute->attrib.pValue,0,attribute->attrib.ulValueLen);
01556        if (attribute->freeData) {
01557            PORT_Free(attribute->attrib.pValue);
01558        }
01559        attribute->freeData = PR_FALSE;
01560        attribute->attrib.pValue = NULL;
01561        attribute->attrib.ulValueLen = 0;
01562     }
01563     sftk_FreeAttribute(attribute);
01564 }
01565 
01566 static CK_RV
01567 sftk_SetCertAttribute(SFTKTokenObject *to, CK_ATTRIBUTE_TYPE type, 
01568                                           void *value, unsigned int len)
01569 {
01570     NSSLOWCERTCertificate  *cert;
01571     NSSLOWCERTCertDBHandle *certHandle;
01572     char *nickname = NULL;
01573     SECStatus rv;
01574     CK_RV crv;
01575 
01576     /* we can't change  the EMAIL values, but let the
01577      * upper layers feel better about the fact we tried to set these */
01578     if (type == CKA_NETSCAPE_EMAIL) {
01579        return CKR_OK;
01580     }
01581 
01582     certHandle = sftk_getCertDB(to->obj.slot);
01583     if (certHandle == NULL) {
01584        crv = CKR_TOKEN_WRITE_PROTECTED;
01585        goto done;
01586     }
01587 
01588     if ((type != CKA_LABEL)  && (type != CKA_ID)) {
01589        crv = CKR_ATTRIBUTE_READ_ONLY;
01590        goto done;
01591     }
01592 
01593     cert = sftk_getCert(to, certHandle);
01594     if (cert == NULL) {
01595        crv = CKR_OBJECT_HANDLE_INVALID;
01596        goto done;
01597     }
01598 
01599     /* if the app is trying to set CKA_ID, it's probably because it just
01600      * imported the key. Look to see if we need to set the CERTDB_USER bits.
01601      */
01602     if (type == CKA_ID) {
01603        if (((cert->trust->sslFlags & CERTDB_USER) == 0) &&
01604               ((cert->trust->emailFlags & CERTDB_USER) == 0) &&
01605               ((cert->trust->objectSigningFlags & CERTDB_USER) == 0)) {
01606            SFTKSlot *slot = to->obj.slot;
01607            NSSLOWKEYDBHandle      *keyHandle;
01608 
01609            keyHandle = sftk_getKeyDB(slot);
01610            if (keyHandle) {
01611               if (nsslowkey_KeyForCertExists(keyHandle, cert)) {
01612                   NSSLOWCERTCertTrust trust = *cert->trust;
01613                   trust.sslFlags |= CERTDB_USER;
01614                   trust.emailFlags |= CERTDB_USER;
01615                   trust.objectSigningFlags |= CERTDB_USER;
01616                   nsslowcert_ChangeCertTrust(certHandle,cert,&trust);
01617               }
01618               sftk_freeKeyDB(keyHandle);
01619            }
01620        }
01621        crv = CKR_OK;
01622        goto done;
01623     }
01624 
01625     /* must be CKA_LABEL */
01626     if (value != NULL) {
01627        nickname = PORT_ZAlloc(len+1);
01628        if (nickname == NULL) {
01629            crv = CKR_HOST_MEMORY;
01630            goto done;
01631        }
01632        PORT_Memcpy(nickname,value,len);
01633        nickname[len] = 0;
01634     }
01635     rv = nsslowcert_AddPermNickname(certHandle, cert, nickname);
01636     crv = (rv == SECSuccess) ? CKR_OK : CKR_DEVICE_ERROR;
01637 
01638 done:
01639     if (nickname) {
01640        PORT_Free(nickname);
01641     }
01642     if (certHandle) {
01643        sftk_freeCertDB(certHandle);
01644     }
01645     return crv;
01646 }
01647 
01648 static CK_RV
01649 sftk_SetPrivateKeyAttribute(SFTKTokenObject *to, CK_ATTRIBUTE_TYPE type, 
01650                                           void *value, unsigned int len)
01651 {
01652     NSSLOWKEYPrivateKey *privKey;
01653     NSSLOWKEYDBHandle   *keyHandle;
01654     char *nickname = NULL;
01655     SECStatus rv;
01656     CK_RV crv;
01657 
01658     /* we can't change the ID and we don't store the subject, but let the
01659      * upper layers feel better about the fact we tried to set these */
01660     if ((type == CKA_ID) || (type == CKA_SUBJECT)) {
01661        return CKR_OK;
01662     }
01663 
01664     keyHandle = sftk_getKeyDB(to->obj.slot);
01665     if (keyHandle == NULL) {
01666        crv = CKR_TOKEN_WRITE_PROTECTED;
01667        goto done;
01668     }
01669     if (type != CKA_LABEL) {
01670        crv = CKR_ATTRIBUTE_READ_ONLY;
01671        goto done;
01672     }
01673 
01674     privKey = sftk_GetPrivateKeyWithDB(to, keyHandle);
01675     if (privKey == NULL) {
01676        crv = CKR_OBJECT_HANDLE_INVALID;
01677        goto done;
01678     }
01679     if (value != NULL) {
01680        nickname = PORT_ZAlloc(len+1);
01681        if (nickname == NULL) {
01682            crv = CKR_HOST_MEMORY;
01683            goto done;
01684        }
01685        PORT_Memcpy(nickname,value,len);
01686        nickname[len] = 0;
01687     }
01688     rv = nsslowkey_UpdateNickname(keyHandle, privKey, &to->dbKey, 
01689                                    nickname, to->obj.slot->password);
01690     crv = (rv == SECSuccess) ? CKR_OK :  CKR_DEVICE_ERROR;
01691 done:
01692     if (nickname) {
01693        PORT_Free(nickname);
01694     }
01695     if (keyHandle) {
01696        sftk_freeKeyDB(keyHandle);
01697     }
01698     return crv;
01699 }
01700 
01701 static CK_RV
01702 sftk_SetTrustAttribute(SFTKTokenObject *to, CK_ATTRIBUTE_TYPE type, 
01703                                           void *value, unsigned int len)
01704 {
01705     unsigned int flags;
01706     CK_TRUST  trust;
01707     NSSLOWCERTCertificate  *cert;
01708     NSSLOWCERTCertDBHandle *certHandle;
01709     NSSLOWCERTCertTrust    dbTrust;
01710     SECStatus rv;
01711     CK_RV crv;
01712 
01713     if (len != sizeof (CK_TRUST)) {
01714        return CKR_ATTRIBUTE_VALUE_INVALID;
01715     }
01716     trust = *(CK_TRUST *)value;
01717     flags = sftk_MapTrust(trust, (PRBool) (type == CKA_TRUST_SERVER_AUTH));
01718 
01719     certHandle = sftk_getCertDB(to->obj.slot);
01720 
01721     if (certHandle == NULL) {
01722        crv = CKR_TOKEN_WRITE_PROTECTED;
01723        goto done;
01724     }
01725 
01726     cert = sftk_getCert(to, certHandle);
01727     if (cert == NULL) {
01728        crv = CKR_OBJECT_HANDLE_INVALID;
01729        goto done;
01730     }
01731     dbTrust = *cert->trust;
01732 
01733     switch (type) {
01734     case CKA_TRUST_EMAIL_PROTECTION:
01735        dbTrust.emailFlags = flags |
01736               (cert->trust->emailFlags & CERTDB_PRESERVE_TRUST_BITS);
01737        break;
01738     case CKA_TRUST_CODE_SIGNING:
01739        dbTrust.objectSigningFlags = flags |
01740               (cert->trust->objectSigningFlags & CERTDB_PRESERVE_TRUST_BITS);
01741        break;
01742     case CKA_TRUST_CLIENT_AUTH:
01743        dbTrust.sslFlags = flags | (cert->trust->sslFlags & 
01744                             (CERTDB_PRESERVE_TRUST_BITS|CERTDB_TRUSTED_CA));
01745        break;
01746     case CKA_TRUST_SERVER_AUTH:
01747        dbTrust.sslFlags = flags | (cert->trust->sslFlags & 
01748                      (CERTDB_PRESERVE_TRUST_BITS|CERTDB_TRUSTED_CLIENT_CA));
01749        break;
01750     default:
01751        crv = CKR_ATTRIBUTE_READ_ONLY;
01752        goto done;
01753     }
01754 
01755     rv = nsslowcert_ChangeCertTrust(certHandle, cert, &dbTrust);
01756     crv = (rv == SECSuccess) ? CKR_OK : CKR_DEVICE_ERROR;
01757 done:
01758     if (certHandle) {
01759        sftk_freeCertDB(certHandle);
01760     }
01761     return crv;
01762 }
01763 
01764 static CK_RV
01765 sftk_forceTokenAttribute(SFTKObject *object,CK_ATTRIBUTE_TYPE type, 
01766                                           void *value, unsigned int len)
01767 {
01768     SFTKAttribute *attribute;
01769     SFTKTokenObject *to = sftk_narrowToTokenObject(object);
01770     CK_RV crv = CKR_ATTRIBUTE_READ_ONLY;
01771 
01772     PORT_Assert(to);
01773     if (to == NULL) {
01774        return CKR_DEVICE_ERROR;
01775     }
01776 
01777     /* if we are just setting it to the value we already have,
01778      * allow it to happen. Let label setting go through so
01779      * we have the opportunity to repair any database corruption. */
01780     attribute=sftk_FindAttribute(object,type);
01781     PORT_Assert(attribute);
01782     if (!attribute) {
01783         return CKR_ATTRIBUTE_TYPE_INVALID;
01784 
01785     }
01786     if ((type != CKA_LABEL) && (attribute->attrib.ulValueLen == len) &&
01787        PORT_Memcmp(attribute->attrib.pValue,value,len) == 0) {
01788        sftk_FreeAttribute(attribute);
01789        return CKR_OK;
01790     }
01791 
01792     switch (object->objclass) {
01793     case CKO_CERTIFICATE:
01794        /* change NICKNAME, EMAIL,  */
01795        crv = sftk_SetCertAttribute(to,type,value,len);
01796        break;
01797     case CKO_NETSCAPE_CRL:
01798        /* change URL */
01799        break;
01800     case CKO_NETSCAPE_TRUST:
01801        crv = sftk_SetTrustAttribute(to,type,value,len);
01802        break;
01803     case CKO_PRIVATE_KEY:
01804     case CKO_SECRET_KEY:
01805        crv = sftk_SetPrivateKeyAttribute(to,type,value,len);
01806        break;
01807     }
01808     sftk_FreeAttribute(attribute);
01809     return crv;
01810 }
01811        
01812 /*
01813  * force an attribute to a spaecif value.
01814  */
01815 CK_RV
01816 sftk_forceAttribute(SFTKObject *object,CK_ATTRIBUTE_TYPE type, void *value,
01817                                           unsigned int len)
01818 {
01819     SFTKAttribute *attribute;
01820     void *att_val = NULL;
01821     PRBool freeData = PR_FALSE;
01822 
01823     PORT_Assert(object);
01824     PORT_Assert(object->refCount);
01825     PORT_Assert(object->slot);
01826     if (!object ||
01827         !object->refCount ||
01828         !object->slot) {
01829         return CKR_DEVICE_ERROR;
01830     }
01831     if (sftk_isToken(object->handle)) {
01832        return sftk_forceTokenAttribute(object,type,value,len);
01833     }
01834     attribute=sftk_FindAttribute(object,type);
01835     if (attribute == NULL) return sftk_AddAttributeType(object,type,value,len);
01836 
01837 
01838     if (value) {
01839         if (len <= ATTR_SPACE) {
01840            att_val = attribute->space;
01841        } else {
01842            att_val = PORT_Alloc(len);
01843            freeData = PR_TRUE;
01844        }
01845        if (att_val == NULL) {
01846            return CKR_HOST_MEMORY;
01847        }
01848        if (attribute->attrib.pValue == att_val) {
01849            PORT_Memset(attribute->attrib.pValue,0,
01850                                    attribute->attrib.ulValueLen);
01851        }
01852        PORT_Memcpy(att_val,value,len);
01853     }
01854     if (attribute->attrib.pValue != NULL) {
01855        if (attribute->attrib.pValue != att_val) {
01856            PORT_Memset(attribute->attrib.pValue,0,
01857                                    attribute->attrib.ulValueLen);
01858        }
01859        if (attribute->freeData) {
01860            PORT_Free(attribute->attrib.pValue);
01861        }
01862        attribute->freeData = PR_FALSE;
01863        attribute->attrib.pValue = NULL;
01864        attribute->attrib.ulValueLen = 0;
01865     }
01866     if (att_val) {
01867        attribute->attrib.pValue = att_val;
01868        attribute->attrib.ulValueLen = len;
01869        attribute->freeData = freeData;
01870     }
01871     sftk_FreeAttribute(attribute);
01872     return CKR_OK;
01873 }
01874 
01875 /*
01876  * return a null terminated string from attribute 'type'. This string
01877  * is allocated and needs to be freed with PORT_Free() When complete.
01878  */
01879 char *
01880 sftk_getString(SFTKObject *object,CK_ATTRIBUTE_TYPE type)
01881 {
01882     SFTKAttribute *attribute;
01883     char *label = NULL;
01884 
01885     attribute=sftk_FindAttribute(object,type);
01886     if (attribute == NULL) return NULL;
01887 
01888     if (attribute->attrib.pValue != NULL) {
01889        label = (char *) PORT_Alloc(attribute->attrib.ulValueLen+1);
01890        if (label == NULL) {
01891            sftk_FreeAttribute(attribute);
01892            return NULL;
01893        }
01894 
01895        PORT_Memcpy(label,attribute->attrib.pValue,
01896                                           attribute->attrib.ulValueLen);
01897        label[attribute->attrib.ulValueLen] = 0;
01898     }
01899     sftk_FreeAttribute(attribute);
01900     return label;
01901 }
01902 
01903 /*
01904  * decode when a particular attribute may be modified
01905  *     SFTK_NEVER: This attribute must be set at object creation time and
01906  *  can never be modified.
01907  *     SFTK_ONCOPY: This attribute may be modified only when you copy the
01908  *  object.
01909  *     SFTK_SENSITIVE: The CKA_SENSITIVE attribute can only be changed from
01910  *  CK_FALSE to CK_TRUE.
01911  *     SFTK_ALWAYS: This attribute can always be modified.
01912  * Some attributes vary their modification type based on the class of the 
01913  *   object.
01914  */
01915 SFTKModifyType
01916 sftk_modifyType(CK_ATTRIBUTE_TYPE type, CK_OBJECT_CLASS inClass)
01917 {
01918     /* if we don't know about it, user user defined, always allow modify */
01919     SFTKModifyType mtype = SFTK_ALWAYS; 
01920 
01921     switch(type) {
01922     /* NEVER */
01923     case CKA_CLASS:
01924     case CKA_CERTIFICATE_TYPE:
01925     case CKA_KEY_TYPE:
01926     case CKA_MODULUS:
01927     case CKA_MODULUS_BITS:
01928     case CKA_PUBLIC_EXPONENT:
01929     case CKA_PRIVATE_EXPONENT:
01930     case CKA_PRIME:
01931     case CKA_SUBPRIME:
01932     case CKA_BASE:
01933     case CKA_PRIME_1:
01934     case CKA_PRIME_2:
01935     case CKA_EXPONENT_1:
01936     case CKA_EXPONENT_2:
01937     case CKA_COEFFICIENT:
01938     case CKA_VALUE_LEN:
01939     case CKA_ALWAYS_SENSITIVE:
01940     case CKA_NEVER_EXTRACTABLE:
01941     case CKA_NETSCAPE_DB:
01942        mtype = SFTK_NEVER;
01943        break;
01944 
01945     /* ONCOPY */
01946     case CKA_TOKEN:
01947     case CKA_PRIVATE:
01948     case CKA_MODIFIABLE:
01949        mtype = SFTK_ONCOPY;
01950        break;
01951 
01952     /* SENSITIVE */
01953     case CKA_SENSITIVE:
01954     case CKA_EXTRACTABLE:
01955        mtype = SFTK_SENSITIVE;
01956        break;
01957 
01958     /* ALWAYS */
01959     case CKA_LABEL:
01960     case CKA_APPLICATION:
01961     case CKA_ID:
01962     case CKA_SERIAL_NUMBER:
01963     case CKA_START_DATE:
01964     case CKA_END_DATE:
01965     case CKA_DERIVE:
01966     case CKA_ENCRYPT:
01967     case CKA_DECRYPT:
01968     case CKA_SIGN:
01969     case CKA_VERIFY:
01970     case CKA_SIGN_RECOVER:
01971     case CKA_VERIFY_RECOVER:
01972     case CKA_WRAP:
01973     case CKA_UNWRAP:
01974        mtype = SFTK_ALWAYS;
01975        break;
01976 
01977     /* DEPENDS ON CLASS */
01978     case CKA_VALUE:
01979        mtype = (inClass == CKO_DATA) ? SFTK_ALWAYS : SFTK_NEVER;
01980        break;
01981 
01982     case CKA_SUBJECT:
01983        mtype = (inClass == CKO_CERTIFICATE) ? SFTK_NEVER : SFTK_ALWAYS;
01984        break;
01985     default:
01986        break;
01987     }
01988     return mtype;
01989 }
01990 
01991 /* decode if a particular attribute is sensitive (cannot be read
01992  * back to the user of if the object is set to SENSITIVE) */
01993 PRBool
01994 sftk_isSensitive(CK_ATTRIBUTE_TYPE type, CK_OBJECT_CLASS inClass)
01995 {
01996     switch(type) {
01997     /* ALWAYS */
01998     case CKA_PRIVATE_EXPONENT:
01999     case CKA_PRIME_1:
02000     case CKA_PRIME_2:
02001     case CKA_EXPONENT_1:
02002     case CKA_EXPONENT_2:
02003     case CKA_COEFFICIENT:
02004        return PR_TRUE;
02005 
02006     /* DEPENDS ON CLASS */
02007     case CKA_VALUE:
02008        /* PRIVATE and SECRET KEYS have SENSITIVE values */
02009        return (PRBool)((inClass == CKO_PRIVATE_KEY) || (inClass == CKO_SECRET_KEY));
02010 
02011     default:
02012        break;
02013     }
02014     return PR_FALSE;
02015 }
02016 
02017 /* 
02018  * copy an attribute into a SECItem. Secitem is allocated in the specified
02019  * arena.
02020  */
02021 CK_RV
02022 sftk_Attribute2SecItem(PLArenaPool *arena,SECItem *item,SFTKObject *object,
02023                                    CK_ATTRIBUTE_TYPE type)
02024 {
02025     int len;
02026     SFTKAttribute *attribute;
02027 
02028     attribute = sftk_FindAttribute(object, type);
02029     if (attribute == NULL) return CKR_TEMPLATE_INCOMPLETE;
02030     len = attribute->attrib.ulValueLen;
02031 
02032     if (arena) {
02033        item->data = (unsigned char *) PORT_ArenaAlloc(arena,len);
02034     } else {
02035        item->data = (unsigned char *) PORT_Alloc(len);
02036     }
02037     if (item->data == NULL) {
02038        sftk_FreeAttribute(attribute);
02039        return CKR_HOST_MEMORY;
02040     }
02041     item->len = len;
02042     PORT_Memcpy(item->data,attribute->attrib.pValue, len);
02043     sftk_FreeAttribute(attribute);
02044     return CKR_OK;
02045 }
02046 
02047 CK_RV
02048 sftk_GetULongAttribute(SFTKObject *object, CK_ATTRIBUTE_TYPE type,
02049                                                   CK_ULONG *longData)
02050 {
02051     SFTKAttribute *attribute;
02052 
02053     attribute = sftk_FindAttribute(object, type);
02054     if (attribute == NULL) return CKR_TEMPLATE_INCOMPLETE;
02055 
02056     if (attribute->attrib.ulValueLen != sizeof(CK_ULONG)) {
02057        return CKR_ATTRIBUTE_VALUE_INVALID;
02058     }
02059 
02060     *longData = *(CK_ULONG *)attribute->attrib.pValue;
02061     sftk_FreeAttribute(attribute);
02062     return CKR_OK;
02063 }
02064 
02065 void
02066 sftk_DeleteAttributeType(SFTKObject *object,CK_ATTRIBUTE_TYPE type)
02067 {
02068     SFTKAttribute *attribute;
02069     attribute = sftk_FindAttribute(object, type);
02070     if (attribute == NULL) return ;
02071     sftk_DeleteAttribute(object,attribute);
02072     sftk_FreeAttribute(attribute);
02073 }
02074 
02075 CK_RV
02076 sftk_AddAttributeType(SFTKObject *object,CK_ATTRIBUTE_TYPE type,void *valPtr,
02077                                                  CK_ULONG length)
02078 {
02079     SFTKAttribute *attribute;
02080     attribute = sftk_NewAttribute(object,type,valPtr,length);
02081     if (attribute == NULL) { return CKR_HOST_MEMORY; }
02082     sftk_AddAttribute(object,attribute);
02083     return CKR_OK;
02084 }
02085 
02086 /*
02087  * ******************** Object Utilities *******************************
02088  */
02089 
02090 static SECStatus
02091 sftk_deleteTokenKeyByHandle(SFTKSlot *slot, CK_OBJECT_HANDLE handle)
02092 {
02093    SECItem *item;
02094    PRBool rem;
02095 
02096    item = (SECItem *)PL_HashTableLookup(slot->tokenHashTable, (void *)handle);
02097    rem = PL_HashTableRemove(slot->tokenHashTable,(void *)handle) ;
02098    if (rem && item) {
02099        SECITEM_FreeItem(item,PR_TRUE);
02100    }
02101    return rem ? SECSuccess : SECFailure;
02102 }
02103 
02104 /* must be called holding sftk_tokenKeyLock(slot) */
02105 static SECStatus
02106 sftk_addTokenKeyByHandle(SFTKSlot *slot, CK_OBJECT_HANDLE handle, SECItem *key)
02107 {
02108     PLHashEntry *entry;
02109     SECItem *item;
02110 
02111     /* don't add a new handle in the middle of closing down a slot */
02112     if (!slot->present) {
02113        return SECFailure;
02114     }
02115 
02116     item = SECITEM_DupItem(key);
02117     if (item == NULL) {
02118        return SECFailure;
02119     }
02120     entry = PL_HashTableAdd(slot->tokenHashTable,(void *)handle,item);
02121     if (entry == NULL) {
02122        SECITEM_FreeItem(item,PR_TRUE);
02123        return SECFailure;
02124     }
02125     return SECSuccess;
02126 }
02127 
02128 /* must be called holding sftk_tokenKeyLock(slot) */
02129 static SECItem *
02130 sftk_lookupTokenKeyByHandle(SFTKSlot *slot, CK_OBJECT_HANDLE handle)
02131 {
02132     return (SECItem *)PL_HashTableLookup(slot->tokenHashTable, (void *)handle);
02133 }
02134 
02135 /*
02136  * use the refLock. This operations should be very rare, so the added
02137  * contention on the ref lock should be lower than the overhead of adding
02138  * a new lock. We use separate functions for this just in case I'm wrong.
02139  */
02140 static void
02141 sftk_tokenKeyLock(SFTKSlot *slot) {
02142     PZ_Lock(slot->objectLock);
02143 }
02144 
02145 static void
02146 sftk_tokenKeyUnlock(SFTKSlot *slot) {
02147     PZ_Unlock(slot->objectLock);
02148 }
02149 
02150 static PRIntn
02151 sftk_freeHashItem(PLHashEntry* entry, PRIntn index, void *arg)
02152 {
02153     SECItem *item = (SECItem *)entry->value;
02154 
02155     SECITEM_FreeItem(item, PR_TRUE);
02156     return HT_ENUMERATE_NEXT;
02157 }
02158 
02159 CK_RV
02160 SFTK_ClearTokenKeyHashTable(SFTKSlot *slot)
02161 {
02162     sftk_tokenKeyLock(slot);
02163     PORT_Assert(!slot->present);
02164     PL_HashTableEnumerateEntries(slot->tokenHashTable, sftk_freeHashItem, NULL);
02165     sftk_tokenKeyUnlock(slot);
02166     return CKR_OK;
02167 }
02168 
02169 
02170 /* allocation hooks that allow us to recycle old object structures */
02171 static SFTKObjectFreeList sessionObjectList = { NULL, NULL, 0 };
02172 static SFTKObjectFreeList tokenObjectList = { NULL, NULL, 0 };
02173 
02174 SFTKObject *
02175 sftk_GetObjectFromList(PRBool *hasLocks, PRBool optimizeSpace, 
02176      SFTKObjectFreeList *list, unsigned int hashSize, PRBool isSessionObject)
02177 {
02178     SFTKObject *object;
02179     int size = 0;
02180 
02181     if (!optimizeSpace) {
02182        PZ_Lock(list->lock);
02183        object = list->head;
02184        if (object) {
02185            list->head = object->next;
02186            list->count--;
02187        }      
02188        PZ_Unlock(list->lock);
02189        if (object) {
02190            object->next = object->prev = NULL;
02191             *hasLocks = PR_TRUE;
02192            return object;
02193        }
02194     }
02195     size = isSessionObject ? sizeof(SFTKSessionObject) 
02196               + hashSize *sizeof(SFTKAttribute *) : sizeof(SFTKTokenObject);
02197 
02198     object  = (SFTKObject*)PORT_ZAlloc(size);
02199     if (isSessionObject) {
02200        ((SFTKSessionObject *)object)->hashSize = hashSize;
02201     }
02202     *hasLocks = PR_FALSE;
02203     return object;
02204 }
02205 
02206 static void
02207 sftk_PutObjectToList(SFTKObject *object, SFTKObjectFreeList *list,
02208                                           PRBool isSessionObject) {
02209 
02210     /* the code below is equivalent to :
02211      *     optimizeSpace = isSessionObject ? object->optimizeSpace : PR_FALSE;
02212      * just faster.
02213      */
02214     PRBool optimizeSpace = isSessionObject && 
02215                             ((SFTKSessionObject *)object)->optimizeSpace; 
02216     if (!optimizeSpace && (list->count < MAX_OBJECT_LIST_SIZE)) {
02217        PZ_Lock(list->lock);
02218        object->next = list->head;
02219        list->head = object;
02220        list->count++;
02221        PZ_Unlock(list->lock);
02222        return;
02223     }
02224     if (isSessionObject) {
02225        SFTKSessionObject *so = (SFTKSessionObject *)object;
02226        PZ_DestroyLock(so->attributeLock);
02227        so->attributeLock = NULL;
02228     }
02229     PZ_DestroyLock(object->refLock);
02230     object->refLock = NULL;
02231     PORT_Free(object);
02232 }
02233 
02234 static SFTKObject *
02235 sftk_freeObjectData(SFTKObject *object) {
02236    SFTKObject *next = object->next;
02237 
02238    PORT_Free(object);
02239    return next;
02240 }
02241 
02242 static void
02243 sftk_InitFreeList(SFTKObjectFreeList *list)
02244 {
02245     list->lock = PZ_NewLock(nssILockObject);
02246 }
02247 
02248 void sftk_InitFreeLists(void)
02249 {
02250     sftk_InitFreeList(&sessionObjectList);
02251     sftk_InitFreeList(&tokenObjectList);
02252 }
02253    
02254 static void
02255 sftk_CleanupFreeList(SFTKObjectFreeList *list, PRBool isSessionList)
02256 {
02257     SFTKObject *object;
02258 
02259     if (!list->lock) {
02260        return;
02261     }
02262     PZ_Lock(list->lock);
02263     for (object= list->head; object != NULL; 
02264                                    object = sftk_freeObjectData(object)) {
02265        PZ_DestroyLock(object->refLock);
02266        if (isSessionList) {
02267            PZ_DestroyLock(((SFTKSessionObject *)object)->attributeLock);
02268        }
02269     }
02270     list->count = 0;
02271     list->head = NULL;
02272     PZ_Unlock(list->lock);
02273     PZ_DestroyLock(list->lock);
02274     list->lock = NULL;
02275 }
02276 
02277 void
02278 sftk_CleanupFreeLists(void)
02279 {
02280     sftk_CleanupFreeList(&sessionObjectList, PR_TRUE);
02281     sftk_CleanupFreeList(&tokenObjectList, PR_FALSE);
02282 }
02283 
02284 
02285 /*
02286  * Create a new object
02287  */
02288 SFTKObject *
02289 sftk_NewObject(SFTKSlot *slot)
02290 {
02291     SFTKObject *object;
02292     SFTKSessionObject *sessObject;
02293     PRBool hasLocks = PR_FALSE;
02294     unsigned int i;
02295     unsigned int hashSize = 0;
02296 
02297     hashSize = (slot->optimizeSpace) ? SPACE_ATTRIBUTE_HASH_SIZE :
02298                             TIME_ATTRIBUTE_HASH_SIZE;
02299 
02300     object = sftk_GetObjectFromList(&hasLocks, slot->optimizeSpace,
02301                             &sessionObjectList,  hashSize, PR_TRUE);
02302     if (object == NULL) {
02303        return NULL;
02304     }
02305     sessObject = (SFTKSessionObject *)object;
02306     sessObject->nextAttr = 0;
02307 
02308     for (i=0; i < MAX_OBJS_ATTRS; i++) {
02309        sessObject->attrList[i].attrib.pValue = NULL;
02310        sessObject->attrList[i].freeData = PR_FALSE;
02311     }
02312     sessObject->optimizeSpace = slot->optimizeSpace;
02313 
02314     object->handle = 0;
02315     object->next = object->prev = NULL;
02316     object->slot = slot;
02317     
02318     object->refCount = 1;
02319     sessObject->sessionList.next = NULL;
02320     sessObject->sessionList.prev = NULL;
02321     sessObject->sessionList.parent = object;
02322     sessObject->session = NULL;
02323     sessObject->wasDerived = PR_FALSE;
02324     if (!hasLocks) object->refLock = PZ_NewLock(nssILockRefLock);
02325     if (object->refLock == NULL) {
02326        PORT_Free(object);
02327        return NULL;
02328     }
02329     if (!hasLocks) sessObject->attributeLock = PZ_NewLock(nssILockAttribute);
02330     if (sessObject->attributeLock == NULL) {
02331        PZ_DestroyLock(object->refLock);
02332        PORT_Free(object);
02333        return NULL;
02334     }
02335     for (i=0; i < sessObject->hashSize; i++) {
02336        sessObject->head[i] = NULL;
02337     }
02338     object->objectInfo = NULL;
02339     object->infoFree = NULL;
02340     return object;
02341 }
02342 
02343 static CK_RV
02344 sftk_DestroySessionObjectData(SFTKSessionObject *so)
02345 {
02346        int i;
02347 
02348        for (i=0; i < MAX_OBJS_ATTRS; i++) {
02349            unsigned char *value = so->attrList[i].attrib.pValue;
02350            if (value) {
02351               PORT_Memset(value,0,so->attrList[i].attrib.ulValueLen);
02352               if (so->attrList[i].freeData) {
02353                   PORT_Free(value);
02354               }
02355               so->attrList[i].attrib.pValue = NULL;
02356               so->attrList[i].freeData = PR_FALSE;
02357            }
02358        }
02359 /*     PZ_DestroyLock(so->attributeLock);*/
02360        return CKR_OK;
02361 }
02362 
02363 /*
02364  * free all the data associated with an object. Object reference count must
02365  * be 'zero'.
02366  */
02367 static CK_RV
02368 sftk_DestroyObject(SFTKObject *object)
02369 {
02370     CK_RV crv = CKR_OK;
02371     SFTKSessionObject *so = sftk_narrowToSessionObject(object);
02372     SFTKTokenObject *to = sftk_narrowToTokenObject(object);
02373 
02374     PORT_Assert(object->refCount == 0);
02375 
02376     /* delete the database value */
02377     if (to) {
02378        if (to->dbKey.data) {
02379           PORT_Free(to->dbKey.data);
02380           to->dbKey.data = NULL;
02381        }
02382     } 
02383     if (so) {
02384        sftk_DestroySessionObjectData(so);
02385     }
02386     if (object->objectInfo) {
02387        (*object->infoFree)(object->objectInfo);
02388        object->objectInfo = NULL;
02389        object->infoFree = NULL;
02390     }
02391     if (so) {
02392        sftk_PutObjectToList(object,&sessionObjectList,PR_TRUE);
02393     } else {
02394        sftk_PutObjectToList(object,&tokenObjectList,PR_FALSE);
02395     }
02396     return crv;
02397 }
02398 
02399 void
02400 sftk_ReferenceObject(SFTKObject *object)
02401 {
02402     PZ_Lock(object->refLock);
02403     object->refCount++;
02404     PZ_Unlock(object->refLock);
02405 }
02406 
02407 static SFTKObject *
02408 sftk_ObjectFromHandleOnSlot(CK_OBJECT_HANDLE handle, SFTKSlot *slot)
02409 {
02410     SFTKObject *object;
02411     PRUint32 index = sftk_hash(handle, slot->tokObjHashSize);
02412 
02413     if (sftk_isToken(handle)) {
02414        return sftk_NewTokenObject(slot, NULL, handle);
02415     }
02416 
02417     PZ_Lock(slot->objectLock);
02418     sftkqueue_find2(object, handle, index, slot->tokObjects);
02419     if (object) {
02420        sftk_ReferenceObject(object);
02421     }
02422     PZ_Unlock(slot->objectLock);
02423 
02424     return(object);
02425 }
02426 /*
02427  * look up and object structure from a handle. OBJECT_Handles only make
02428  * sense in terms of a given session.  make a reference to that object
02429  * structure returned.
02430  */
02431 SFTKObject *
02432 sftk_ObjectFromHandle(CK_OBJECT_HANDLE handle, SFTKSession *session)
02433 {
02434     SFTKSlot *slot = sftk_SlotFromSession(session);
02435 
02436     return sftk_ObjectFromHandleOnSlot(handle,slot);
02437 }
02438 
02439 
02440 /*
02441  * release a reference to an object handle
02442  */
02443 SFTKFreeStatus
02444 sftk_FreeObject(SFTKObject *object)
02445 {
02446     PRBool destroy = PR_FALSE;
02447     CK_RV crv;
02448 
02449     PZ_Lock(object->refLock);
02450     if (object->refCount == 1) destroy = PR_TRUE;
02451     object->refCount--;
02452     PZ_Unlock(object->refLock);
02453 
02454     if (destroy) {
02455        crv = sftk_DestroyObject(object);
02456        if (crv != CKR_OK) {
02457           return SFTK_DestroyFailure;
02458        } 
02459        return SFTK_Destroyed;
02460     }
02461     return SFTK_Busy;
02462 }
02463  
02464 /*
02465  * add an object to a slot and session queue. These two functions
02466  * adopt the object.
02467  */
02468 void
02469 sftk_AddSlotObject(SFTKSlot *slot, SFTKObject *object)
02470 {
02471     PRUint32 index = sftk_hash(object->handle, slot->tokObjHashSize);
02472     sftkqueue_init_element(object);
02473     PZ_Lock(slot->objectLock);
02474     sftkqueue_add2(object, object->handle, index, slot->tokObjects);
02475     PZ_Unlock(slot->objectLock);
02476 }
02477 
02478 void
02479 sftk_AddObject(SFTKSession *session, SFTKObject *object)
02480 {
02481     SFTKSlot *slot = sftk_SlotFromSession(session);
02482     SFTKSessionObject *so = sftk_narrowToSessionObject(object);
02483 
02484     if (so) {
02485        PZ_Lock(session->objectLock);
02486        sftkqueue_add(&so->sessionList,0,session->objects,0);
02487        so->session = session;
02488        PZ_Unlock(session->objectLock);
02489     }
02490     sftk_AddSlotObject(slot,object);
02491     sftk_ReferenceObject(object);
02492 } 
02493 
02494 /*
02495  * add an object to a slot andsession queue
02496  */
02497 CK_RV
02498 sftk_DeleteObject(SFTKSession *session, SFTKObject *object)
02499 {
02500     SFTKSlot *slot = sftk_SlotFromSession(session);
02501     SFTKSessionObject *so = sftk_narrowToSessionObject(object);
02502     SFTKTokenObject *to = sftk_narrowToTokenObject(object);
02503     CK_RV crv = CKR_OK;
02504     SECStatus rv;
02505     NSSLOWCERTCertificate *cert;
02506     NSSLOWCERTCertTrust tmptrust;
02507     PRBool isKrl;
02508     PRUint32 index = sftk_hash(object->handle, slot->tokObjHashSize);
02509 
02510   /* Handle Token case */
02511     if (so && so->session) {
02512        SFTKSession *session = so->session;
02513        PZ_Lock(session->objectLock);
02514        sftkqueue_delete(&so->sessionList,0,session->objects,0);
02515        PZ_Unlock(session->objectLock);
02516        PZ_Lock(slot->objectLock);
02517        sftkqueue_delete2(object, object->handle, index, slot->tokObjects);
02518        PZ_Unlock(slot->objectLock);
02519        sftkqueue_clear_deleted_element(object);
02520        sftk_FreeObject(object); /* reduce it's reference count */
02521     } else {
02522        NSSLOWKEYDBHandle *keyHandle;
02523        NSSLOWCERTCertDBHandle *certHandle;
02524 
02525        PORT_Assert(to);
02526        /* remove the objects from the real data base */
02527        switch (object->handle & SFTK_TOKEN_TYPE_MASK) {
02528        case SFTK_TOKEN_TYPE_PRIV:
02529        case SFTK_TOKEN_TYPE_KEY:
02530            /* KEYID is the public KEY for DSA and DH, and the MODULUS for
02531             *  RSA */
02532            keyHandle = sftk_getKeyDB(slot);
02533            if (!keyHandle) {
02534               crv = CKR_TOKEN_WRITE_PROTECTED;
02535               break;
02536            }
02537            rv = nsslowkey_DeleteKey(keyHandle, &to->dbKey);
02538            sftk_freeKeyDB(keyHandle);
02539            if (rv != SECSuccess) {
02540               crv = CKR_DEVICE_ERROR;
02541            }
02542            break;
02543        case SFTK_TOKEN_TYPE_PUB:
02544            break; /* public keys only exist at the behest of the priv key */
02545        case SFTK_TOKEN_TYPE_CERT:
02546            certHandle = sftk_getCertDB(slot);
02547            if (!certHandle) {
02548               crv = CKR_TOKEN_WRITE_PROTECTED;
02549               break;
02550            }
02551            cert = nsslowcert_FindCertByKey(certHandle,&to->dbKey);
02552            sftk_freeCertDB(certHandle);
02553            if (cert == NULL) {
02554               crv = CKR_DEVICE_ERROR;
02555               break;
02556            }
02557            rv = nsslowcert_DeletePermCertificate(cert);
02558            if (rv != SECSuccess) {
02559               crv = CKR_DEVICE_ERROR;
02560            }
02561            nsslowcert_DestroyCertificate(cert);
02562            break;
02563        case SFTK_TOKEN_TYPE_CRL:
02564            certHandle = sftk_getCertDB(slot);
02565            if (!certHandle) {
02566               crv = CKR_TOKEN_WRITE_PROTECTED;
02567               break;
02568            }
02569            isKrl = (PRBool) (object->handle == SFTK_TOKEN_KRL_HANDLE);
02570            rv = nsslowcert_DeletePermCRL(certHandle, &to->dbKey, isKrl);
02571            sftk_freeCertDB(certHandle);
02572            if (rv == SECFailure) crv = CKR_DEVICE_ERROR;
02573            break;
02574        case SFTK_TOKEN_TYPE_TRUST:
02575            certHandle = sftk_getCertDB(slot);
02576            if (!certHandle) {
02577               crv = CKR_TOKEN_WRITE_PROTECTED;
02578               break;
02579            }
02580            cert = nsslowcert_FindCertByKey(certHandle, &to->dbKey);
02581            if (cert == NULL) {
02582               sftk_freeCertDB(certHandle);
02583               crv = CKR_DEVICE_ERROR;
02584               break;
02585            }
02586            tmptrust = *cert->trust;
02587            tmptrust.sslFlags &= CERTDB_PRESERVE_TRUST_BITS;
02588            tmptrust.emailFlags &= CERTDB_PRESERVE_TRUST_BITS;
02589            tmptrust.objectSigningFlags &= CERTDB_PRESERVE_TRUST_BITS;
02590            tmptrust.sslFlags |= CERTDB_TRUSTED_UNKNOWN;
02591            tmptrust.emailFlags |= CERTDB_TRUSTED_UNKNOWN;
02592            tmptrust.objectSigningFlags |= CERTDB_TRUSTED_UNKNOWN;
02593            rv = nsslowcert_ChangeCertTrust(certHandle, cert, &tmptrust);
02594            sftk_freeCertDB(certHandle);
02595            if (rv != SECSuccess) crv = CKR_DEVICE_ERROR;
02596            nsslowcert_DestroyCertificate(cert);
02597            break;
02598        default:
02599            break;
02600        }
02601        sftk_tokenKeyLock(object->slot);
02602        sftk_deleteTokenKeyByHandle(object->slot,object->handle);
02603        sftk_tokenKeyUnlock(object->slot);
02604     } 
02605     return crv;
02606 }
02607 
02608 /*
02609  * Token objects don't explicitly store their attributes, so we need to know
02610  * what attributes make up a particular token object before we can copy it.
02611  * below are the tables by object type.
02612  */
02613 static const CK_ATTRIBUTE_TYPE commonAttrs[] = {
02614     CKA_CLASS, CKA_TOKEN, CKA_PRIVATE, CKA_LABEL, CKA_MODIFIABLE
02615 };
02616 static const CK_ULONG commonAttrsCount = 
02617                      sizeof(commonAttrs)/sizeof(commonAttrs[0]);
02618 
02619 static const CK_ATTRIBUTE_TYPE commonKeyAttrs[] = {
02620     CKA_ID, CKA_START_DATE, CKA_END_DATE, CKA_DERIVE, CKA_LOCAL, CKA_KEY_TYPE
02621 };
02622 static const CK_ULONG commonKeyAttrsCount = 
02623                      sizeof(commonKeyAttrs)/sizeof(commonKeyAttrs[0]);
02624 
02625 static const CK_ATTRIBUTE_TYPE secretKeyAttrs[] = {
02626     CKA_SENSITIVE, CKA_EXTRACTABLE, CKA_ENCRYPT, CKA_DECRYPT, CKA_SIGN,
02627     CKA_VERIFY, CKA_WRAP, CKA_UNWRAP, CKA_VALUE
02628 };
02629 static const CK_ULONG secretKeyAttrsCount = 
02630                      sizeof(secretKeyAttrs)/sizeof(secretKeyAttrs[0]);
02631 
02632 static const CK_ATTRIBUTE_TYPE commonPubKeyAttrs[] = {
02633     CKA_ENCRYPT, CKA_VERIFY, CKA_VERIFY_RECOVER, CKA_WRAP, CKA_SUBJECT
02634 };
02635 static const CK_ULONG commonPubKeyAttrsCount = 
02636                      sizeof(commonPubKeyAttrs)/sizeof(commonPubKeyAttrs[0]);
02637 
02638 static const CK_ATTRIBUTE_TYPE rsaPubKeyAttrs[] = {
02639     CKA_MODULUS, CKA_PUBLIC_EXPONENT
02640 };
02641 static const CK_ULONG rsaPubKeyAttrsCount = 
02642                      sizeof(rsaPubKeyAttrs)/sizeof(rsaPubKeyAttrs[0]);
02643 
02644 static const CK_ATTRIBUTE_TYPE dsaPubKeyAttrs[] = {
02645     CKA_SUBPRIME, CKA_PRIME, CKA_BASE, CKA_VALUE
02646 };
02647 static const CK_ULONG dsaPubKeyAttrsCount = 
02648                      sizeof(dsaPubKeyAttrs)/sizeof(dsaPubKeyAttrs[0]);
02649 
02650 static const CK_ATTRIBUTE_TYPE dhPubKeyAttrs[] = {
02651     CKA_PRIME, CKA_BASE, CKA_VALUE
02652 };
02653 static const CK_ULONG dhPubKeyAttrsCount = 
02654                      sizeof(dhPubKeyAttrs)/sizeof(dhPubKeyAttrs[0]);
02655 #ifdef NSS_ENABLE_ECC
02656 static const CK_ATTRIBUTE_TYPE ecPubKeyAttrs[] = {
02657     CKA_EC_PARAMS, CKA_EC_POINT
02658 };
02659 static const CK_ULONG ecPubKeyAttrsCount = 
02660                      sizeof(ecPubKeyAttrs)/sizeof(ecPubKeyAttrs[0]);
02661 #endif
02662 
02663 static const CK_ATTRIBUTE_TYPE commonPrivKeyAttrs[] = {
02664     CKA_DECRYPT, CKA_SIGN, CKA_SIGN_RECOVER, CKA_UNWRAP, CKA_SUBJECT,
02665     CKA_SENSITIVE, CKA_EXTRACTABLE, CKA_NETSCAPE_DB
02666 };
02667 static const CK_ULONG commonPrivKeyAttrsCount = 
02668               sizeof(commonPrivKeyAttrs)/sizeof(commonPrivKeyAttrs[0]);
02669 
02670 static const CK_ATTRIBUTE_TYPE rsaPrivKeyAttrs[] = {
02671     CKA_MODULUS, CKA_PUBLIC_EXPONENT, CKA_PRIVATE_EXPONENT, 
02672     CKA_PRIME_1, CKA_PRIME_2, CKA_EXPONENT_1, CKA_EXPONENT_2, CKA_COEFFICIENT
02673 };
02674 static const CK_ULONG rsaPrivKeyAttrsCount = 
02675                      sizeof(rsaPrivKeyAttrs)/sizeof(rsaPrivKeyAttrs[0]);
02676 
02677 static const CK_ATTRIBUTE_TYPE dsaPrivKeyAttrs[] = {
02678     CKA_SUBPRIME, CKA_PRIME, CKA_BASE, CKA_VALUE
02679 };
02680 static const CK_ULONG dsaPrivKeyAttrsCount = 
02681                      sizeof(dsaPrivKeyAttrs)/sizeof(dsaPrivKeyAttrs[0]);
02682 
02683 static const CK_ATTRIBUTE_TYPE dhPrivKeyAttrs[] = {
02684     CKA_PRIME, CKA_BASE, CKA_VALUE
02685 };
02686 static const CK_ULONG dhPrivKeyAttrsCount = 
02687                      sizeof(dhPrivKeyAttrs)/sizeof(dhPrivKeyAttrs[0]);
02688 #ifdef NSS_ENABLE_ECC
02689 static const CK_ATTRIBUTE_TYPE ecPrivKeyAttrs[] = {
02690     CKA_EC_PARAMS, CKA_VALUE
02691 };
02692 static const CK_ULONG ecPrivKeyAttrsCount = 
02693                      sizeof(ecPrivKeyAttrs)/sizeof(ecPrivKeyAttrs[0]);
02694 #endif
02695 
02696 static const CK_ATTRIBUTE_TYPE certAttrs[] = {
02697     CKA_CERTIFICATE_TYPE, CKA_VALUE, CKA_SUBJECT, CKA_ISSUER, CKA_SERIAL_NUMBER
02698 };
02699 static const CK_ULONG certAttrsCount = 
02700               sizeof(certAttrs)/sizeof(certAttrs[0]);
02701 
02702 static const CK_ATTRIBUTE_TYPE trustAttrs[] = {
02703     CKA_ISSUER, CKA_SERIAL_NUMBER, CKA_CERT_SHA1_HASH, CKA_CERT_MD5_HASH,
02704     CKA_TRUST_SERVER_AUTH, CKA_TRUST_CLIENT_AUTH, CKA_TRUST_EMAIL_PROTECTION,
02705     CKA_TRUST_CODE_SIGNING, CKA_TRUST_STEP_UP_APPROVED
02706 };
02707 static const CK_ULONG trustAttrsCount = 
02708               sizeof(trustAttrs)/sizeof(trustAttrs[0]);
02709 
02710 static const CK_ATTRIBUTE_TYPE smimeAttrs[] = {
02711     CKA_SUBJECT, CKA_NETSCAPE_EMAIL, CKA_NETSCAPE_SMIME_TIMESTAMP, CKA_VALUE
02712 };
02713 static const CK_ULONG smimeAttrsCount = 
02714               sizeof(smimeAttrs)/sizeof(smimeAttrs[0]);
02715 
02716 static const CK_ATTRIBUTE_TYPE crlAttrs[] = {
02717     CKA_SUBJECT, CKA_VALUE, CKA_NETSCAPE_URL, CKA_NETSCAPE_KRL
02718 };
02719 static const CK_ULONG crlAttrsCount = 
02720               sizeof(crlAttrs)/sizeof(crlAttrs[0]);
02721 
02722 /* copy an object based on it's table */
02723 CK_RV
02724 stfk_CopyTokenAttributes(SFTKObject *destObject,SFTKTokenObject *src_to,
02725        const CK_ATTRIBUTE_TYPE *attrArray, CK_ULONG attrCount)
02726 {
02727     SFTKAttribute *attribute;
02728     SFTKAttribute *newAttribute;
02729     CK_RV crv = CKR_OK;
02730     unsigned int i;
02731 
02732     for (i=0; i < attrCount; i++) {
02733        if (!sftk_hasAttribute(destObject,attrArray[i])) {
02734            attribute =sftk_FindAttribute(&src_to->obj, attrArray[i]);
02735            if (!attribute) {
02736               continue; /* return CKR_ATTRIBUTE_VALUE_INVALID; */
02737            }
02738            /* we need to copy the attribute since each attribute
02739             * only has one set of link list pointers */
02740            newAttribute = sftk_NewAttribute( destObject,
02741                             sftk_attr_expand(&attribute->attrib));
02742            sftk_FreeAttribute(attribute); /* free the old attribute */
02743            if (!newAttribute) {
02744               return CKR_HOST_MEMORY;
02745            }
02746            sftk_AddAttribute(destObject,newAttribute);
02747        }
02748     }
02749     return crv;
02750 }
02751 
02752 CK_RV
02753 stfk_CopyTokenPrivateKey(SFTKObject *destObject,SFTKTokenObject *src_to)
02754 {
02755     CK_RV crv;
02756     CK_KEY_TYPE key_type;
02757     SFTKAttribute *attribute;
02758 
02759     /* copy the common attributes for all keys first */
02760     crv = stfk_CopyTokenAttributes(destObject, src_to, commonKeyAttrs,
02761                                                  commonKeyAttrsCount);
02762     if (crv != CKR_OK) {
02763        goto fail;
02764     }
02765     /* copy the common attributes for all private keys next */
02766     crv = stfk_CopyTokenAttributes(destObject, src_to, commonPrivKeyAttrs,
02767                                           commonPrivKeyAttrsCount);
02768     if (crv != CKR_OK) {
02769        goto fail;
02770     }
02771     attribute =sftk_FindAttribute(&src_to->obj, CKA_KEY_TYPE);
02772     PORT_Assert(attribute); /* if it wasn't here, ww should have failed
02773                           * copying the common attributes */
02774     if (!attribute) {
02775        /* OK, so CKR_ATTRIBUTE_VALUE_INVALID is the immediate error, but
02776         * the fact is, the only reason we couldn't get the attribute would
02777         * be a memory error or database error (an error in the 'device').
02778         * if we have a database error code, we could return it here */
02779        crv = CKR_DEVICE_ERROR;
02780        goto fail;
02781     }
02782     key_type = *(CK_KEY_TYPE *)attribute->attrib.pValue;
02783     sftk_FreeAttribute(attribute);
02784     
02785     /* finally copy the attributes for various private key types */
02786     switch (key_type) {
02787     case CKK_RSA:
02788        crv = stfk_CopyTokenAttributes(destObject, src_to, rsaPrivKeyAttrs,
02789                                                  rsaPrivKeyAttrsCount);
02790        break;
02791     case CKK_DSA:
02792        crv = stfk_CopyTokenAttributes(destObject, src_to, dsaPrivKeyAttrs,
02793                                                  dsaPrivKeyAttrsCount);
02794        break;
02795     case CKK_DH:
02796        crv = stfk_CopyTokenAttributes(destObject, src_to, dhPrivKeyAttrs,
02797                                                  dhPrivKeyAttrsCount);
02798        break;
02799 #ifdef NSS_ENABLE_ECC
02800     case CKK_EC:
02801        crv = stfk_CopyTokenAttributes(destObject, src_to, ecPrivKeyAttrs,
02802                                                  ecPrivKeyAttrsCount);
02803        break;
02804 #endif
02805      default:
02806        crv = CKR_DEVICE_ERROR; /* shouldn't happen unless we store more types
02807                             * of token keys into our database. */
02808     }
02809 fail:
02810     return crv;
02811 }
02812 
02813 CK_RV
02814 stfk_CopyTokenPublicKey(SFTKObject *destObject,SFTKTokenObject *src_to)
02815 {
02816     CK_RV crv;
02817     CK_KEY_TYPE key_type;
02818     SFTKAttribute *attribute;
02819 
02820     /* copy the common attributes for all keys first */
02821     crv = stfk_CopyTokenAttributes(destObject, src_to, commonKeyAttrs,
02822                                                  commonKeyAttrsCount);
02823     if (crv != CKR_OK) {
02824        goto fail;
02825     }
02826 
02827     /* copy the common attributes for all public keys next */
02828     crv = stfk_CopyTokenAttributes(destObject, src_to, commonPubKeyAttrs,
02829                                                  commonPubKeyAttrsCount);
02830     if (crv != CKR_OK) {
02831        goto fail;
02832     }
02833     attribute =sftk_FindAttribute(&src_to->obj, CKA_KEY_TYPE);
02834     PORT_Assert(attribute); /* if it wasn't here, ww should have failed
02835                           * copying the common attributes */
02836     if (!attribute) {
02837        /* OK, so CKR_ATTRIBUTE_VALUE_INVALID is the immediate error, but
02838         * the fact is, the only reason we couldn't get the attribute would
02839         * be a memory error or database error (an error in the 'device').
02840         * if we have a database error code, we could return it here */
02841        crv = CKR_DEVICE_ERROR;
02842        goto fail;
02843     }
02844     key_type = *(CK_KEY_TYPE *)attribute->attrib.pValue;
02845     sftk_FreeAttribute(attribute);
02846     
02847     /* finally copy the attributes for various public key types */
02848     switch (key_type) {
02849     case CKK_RSA:
02850        crv = stfk_CopyTokenAttributes(destObject, src_to, rsaPubKeyAttrs,
02851                                                  rsaPubKeyAttrsCount);
02852        break;
02853     case CKK_DSA:
02854        crv = stfk_CopyTokenAttributes(destObject, src_to, dsaPubKeyAttrs,
02855                                                  dsaPubKeyAttrsCount);
02856        break;
02857     case CKK_DH:
02858        crv = stfk_CopyTokenAttributes(destObject, src_to, dhPubKeyAttrs,
02859                                                  dhPubKeyAttrsCount);
02860        break;
02861 #ifdef NSS_ENABLE_ECC
02862     case CKK_EC:
02863        crv = stfk_CopyTokenAttributes(destObject, src_to, ecPubKeyAttrs,
02864                                                  ecPubKeyAttrsCount);
02865        break;
02866 #endif
02867      default:
02868        crv = CKR_DEVICE_ERROR; /* shouldn't happen unless we store more types
02869                             * of token keys into our database. */
02870     }
02871 fail:
02872     return crv;
02873 }
02874 CK_RV
02875 stfk_CopyTokenSecretKey(SFTKObject *destObject,SFTKTokenObject *src_to)
02876 {
02877     CK_RV crv;
02878     crv = stfk_CopyTokenAttributes(destObject, src_to, commonKeyAttrs,
02879                                                  commonKeyAttrsCount);
02880     if (crv != CKR_OK) {
02881        goto fail;
02882     }
02883     crv = stfk_CopyTokenAttributes(destObject, src_to, secretKeyAttrs,
02884                                                  secretKeyAttrsCount);
02885 fail:
02886     return crv;
02887 }
02888 
02889 /*
02890  * Copy a token object. We need to explicitly copy the relevant
02891  * attributes since token objects don't store those attributes in
02892  * the token itself.
02893  */
02894 CK_RV
02895 sftk_CopyTokenObject(SFTKObject *destObject,SFTKObject *srcObject)
02896 {
02897     SFTKTokenObject *src_to = sftk_narrowToTokenObject(srcObject);
02898     CK_RV crv;
02899 
02900     PORT_Assert(src_to);
02901     if (src_to == NULL) {
02902        return CKR_DEVICE_ERROR; /* internal state inconsistant */
02903     }
02904 
02905     crv = stfk_CopyTokenAttributes(destObject, src_to, commonAttrs,
02906                                                  commonAttrsCount);
02907     if (crv != CKR_OK) {
02908        goto fail;
02909     }
02910     switch (src_to->obj.objclass) {
02911     case CKO_CERTIFICATE:
02912        crv = stfk_CopyTokenAttributes(destObject, src_to, certAttrs,
02913                                                  certAttrsCount);
02914        break;
02915     case CKO_NETSCAPE_TRUST:
02916        crv = stfk_CopyTokenAttributes(destObject, src_to, trustAttrs,
02917                                                  trustAttrsCount);
02918        break;
02919     case CKO_NETSCAPE_SMIME:
02920        crv = stfk_CopyTokenAttributes(destObject, src_to, smimeAttrs,
02921                                                  smimeAttrsCount);
02922        break;
02923     case CKO_NETSCAPE_CRL:
02924        crv = stfk_CopyTokenAttributes(destObject, src_to, crlAttrs,
02925                                                  crlAttrsCount);
02926        break;
02927     case CKO_PRIVATE_KEY:
02928        crv = stfk_CopyTokenPrivateKey(destObject,src_to);
02929        break;
02930     case CKO_PUBLIC_KEY:
02931        crv = stfk_CopyTokenPublicKey(destObject,src_to);
02932        break;
02933     case CKO_SECRET_KEY:
02934        crv = stfk_CopyTokenSecretKey(destObject,src_to);
02935        break;
02936     default:
02937        crv = CKR_DEVICE_ERROR; /* shouldn't happen unless we store more types
02938                             * of token keys into our database. */
02939     }
02940 fail:
02941     return crv;
02942 }
02943 
02944 /*
02945  * copy the attributes from one object to another. Don't overwrite existing
02946  * attributes. NOTE: This is a pretty expensive operation since it
02947  * grabs the attribute locks for the src object for a *long* time.
02948  */
02949 CK_RV
02950 sftk_CopyObject(SFTKObject *destObject,SFTKObject *srcObject)
02951 {
02952     SFTKAttribute *attribute;
02953     SFTKSessionObject *src_so = sftk_narrowToSessionObject(srcObject);
02954     unsigned int i;
02955 
02956     if (src_so == NULL) {
02957        return sftk_CopyTokenObject(destObject,srcObject); 
02958     }
02959 
02960     PZ_Lock(src_so->attributeLock);
02961     for(i=0; i < src_so->hashSize; i++) {
02962        attribute = src_so->head[i];
02963        do {
02964            if (attribute) {
02965               if (!sftk_hasAttribute(destObject,attribute->handle)) {
02966                   /* we need to copy the attribute since each attribute
02967                    * only has one set of link list pointers */
02968                   SFTKAttribute *newAttribute = sftk_NewAttribute(
02969                        destObject,sftk_attr_expand(&attribute->attrib));
02970                   if (newAttribute == NULL) {
02971                      PZ_Unlock(src_so->attributeLock);
02972                      return CKR_HOST_MEMORY;
02973                   }
02974                   sftk_AddAttribute(destObject,newAttribute);
02975               }
02976               attribute=attribute->next;
02977            }
02978        } while (attribute != NULL);
02979     }
02980     PZ_Unlock(src_so->attributeLock);
02981 
02982     return CKR_OK;
02983 }
02984 
02985 /*
02986  * ******************** Search Utilities *******************************
02987  */
02988 
02989 /* add an object to a search list */
02990 CK_RV
02991 AddToList(SFTKObjectListElement **list,SFTKObject *object)
02992 {
02993      SFTKObjectListElement *newElem = 
02994        (SFTKObjectListElement *)PORT_Alloc(sizeof(SFTKObjectListElement));
02995 
02996      if (newElem == NULL) return CKR_HOST_MEMORY;
02997 
02998      newElem->next = *list;
02999      newElem->object = object;
03000      sftk_ReferenceObject(object);
03001 
03002     *list = newElem;
03003     return CKR_OK;
03004 }
03005 
03006 
03007 /* return true if the object matches the template */
03008 PRBool
03009 sftk_objectMatch(SFTKObject *object,CK_ATTRIBUTE_PTR theTemplate,int count)
03010 {
03011     int i;
03012 
03013     for (i=0; i < count; i++) {
03014        SFTKAttribute *attribute = sftk_FindAttribute(object,theTemplate[i].type);
03015        if (attribute == NULL) {
03016            return PR_FALSE;
03017        }
03018        if (attribute->attrib.ulValueLen == theTemplate[i].ulValueLen) {
03019            if (PORT_Memcmp(attribute->attrib.pValue,theTemplate[i].pValue,
03020                                    theTemplate[i].ulValueLen) == 0) {
03021               sftk_FreeAttribute(attribute);
03022               continue;
03023            }
03024        }
03025         sftk_FreeAttribute(attribute);
03026        return PR_FALSE;
03027     }
03028     return PR_TRUE;
03029 }
03030 
03031 /* search through all the objects in the queue and return the template matches
03032  * in the object list.
03033  */
03034 CK_RV
03035 sftk_searchObjectList(SFTKSearchResults *search,SFTKObject **head, 
03036        unsigned int size, PZLock *lock, CK_ATTRIBUTE_PTR theTemplate, 
03037                                           int count, PRBool isLoggedIn)
03038 {
03039     unsigned int i;
03040     SFTKObject *object;
03041     CK_RV crv = CKR_OK;
03042 
03043     for(i=0; i < size; i++) {
03044         /* We need to hold the lock to copy a consistant version of
03045          * the linked list. */
03046         PZ_Lock(lock);
03047        for (object = head[i]; object != NULL; object= object->next) {
03048            if (sftk_objectMatch(object,theTemplate,count)) {
03049               /* don't return objects that aren't yet visible */
03050               if ((!isLoggedIn) && sftk_isTrue(object,CKA_PRIVATE)) continue;
03051               sftk_addHandle(search,object->handle);
03052            }
03053        }
03054         PZ_Unlock(lock);
03055     }
03056     return crv;
03057 }
03058 
03059 /*
03060  * free a single list element. Return the Next object in the list.
03061  */
03062 SFTKObjectListElement *
03063 sftk_FreeObjectListElement(SFTKObjectListElement *objectList)
03064 {
03065     SFTKObjectListElement *ol = objectList->next;
03066 
03067     sftk_FreeObject(objectList->object);
03068     PORT_Free(objectList);
03069     return ol;
03070 }
03071 
03072 /* free an entire object list */
03073 void
03074 sftk_FreeObjectList(SFTKObjectListElement *objectList)
03075 {
03076     SFTKObjectListElement *ol;
03077 
03078     for (ol= objectList; ol != NULL; ol = sftk_FreeObjectListElement(ol)) {}
03079 }
03080 
03081 /*
03082  * free a search structure
03083  */
03084 void
03085 sftk_FreeSearch(SFTKSearchResults *search)
03086 {
03087     if (search->handles) {
03088        PORT_Free(search->handles);
03089     }
03090     PORT_Free(search);
03091 }
03092 
03093 /*
03094  * ******************** Session Utilities *******************************
03095  */
03096 
03097 /* update the sessions state based in it's flags and wether or not it's
03098  * logged in */
03099 void
03100 sftk_update_state(SFTKSlot *slot,SFTKSession *session)
03101 {
03102     if (slot->isLoggedIn) {
03103        if (slot->ssoLoggedIn) {
03104            session->info.state = CKS_RW_SO_FUNCTIONS;
03105        } else if (session->info.flags & CKF_RW_SESSION) {
03106            session->info.state = CKS_RW_USER_FUNCTIONS;
03107        } else {
03108            session->info.state = CKS_RO_USER_FUNCTIONS;
03109        }
03110     } else {
03111        if (session->info.flags & CKF_RW_SESSION) {
03112            session->info.state = CKS_RW_PUBLIC_SESSION;
03113        } else {
03114            session->info.state = CKS_RO_PUBLIC_SESSION;
03115        }
03116     }
03117 }
03118 
03119 /* update the state of all the sessions on a slot */
03120 void
03121 sftk_update_all_states(SFTKSlot *slot)
03122 {
03123     unsigned int i;
03124     SFTKSession *session;
03125 
03126     for (i=0; i < slot->sessHashSize; i++) {
03127        PZLock *lock = SFTK_SESSION_LOCK(slot,i);
03128        PZ_Lock(lock);
03129        for (session = slot->head[i]; session; session = session->next) {
03130            sftk_update_state(slot,session);
03131        }
03132        PZ_Unlock(lock);
03133     }
03134 }
03135 
03136 /*
03137  * context are cipher and digest contexts that are associated with a session
03138  */
03139 void
03140 sftk_FreeContext(SFTKSessionContext *context)
03141 {
03142     if (context->cipherInfo) {
03143        (*context->destroy)(context->cipherInfo,PR_TRUE);
03144     }
03145     if (context->hashInfo) {
03146        (*context->hashdestroy)(context->hashInfo,PR_TRUE);
03147     }
03148     if (context->key) {
03149        sftk_FreeObject(context->key);
03150        context->key = NULL;
03151     }
03152     PORT_Free(context);
03153 }
03154 
03155 /*
03156  * create a new nession. NOTE: The session handle is not set, and the
03157  * session is not added to the slot's session queue.
03158  */
03159 SFTKSession *
03160 sftk_NewSession(CK_SLOT_ID slotID, CK_NOTIFY notify, CK_VOID_PTR pApplication,
03161                                                       CK_FLAGS flags)
03162 {
03163     SFTKSession *session;
03164     SFTKSlot *slot = sftk_SlotFromID(slotID, PR_FALSE);
03165 
03166     if (slot == NULL) return NULL;
03167 
03168     session = (SFTKSession*)PORT_Alloc(sizeof(SFTKSession));
03169     if (session == NULL) return NULL;
03170 
03171     session->next = session->prev = NULL;
03172     session->refCount = 1;
03173     session->enc_context = NULL;
03174     session->hash_context = NULL;
03175     session->sign_context = NULL;
03176     session->search = NULL;
03177     session->objectIDCount = 1;
03178     session->objectLock = PZ_NewLock(nssILockObject);
03179     if (session->objectLock == NULL) {
03180        PORT_Free(session);
03181        return NULL;
03182     }
03183     session->objects[0] = NULL;
03184 
03185     session->slot = slot;
03186     session->notify = notify;
03187     session->appData = pApplication;
03188     session->info.flags = flags;
03189     session->info.slotID = slotID;
03190     session->info.ulDeviceError = 0;
03191     sftk_update_state(slot,session);
03192     return session;
03193 }
03194 
03195 
03196 /* free all the data associated with a session. */
03197 static void
03198 sftk_DestroySession(SFTKSession *session)
03199 {
03200     SFTKObjectList *op,*next;
03201     PORT_Assert(session->refCount == 0);
03202 
03203     /* clean out the attributes */
03204     /* since no one is referencing us, it's safe to walk the chain
03205      * without a lock */
03206     for (op = session->objects[0]; op != NULL; op = next) {
03207         next = op->next;
03208         /* paranoia */
03209        op->next = op->prev = NULL;
03210        sftk_DeleteObject(session,op->parent);
03211     }
03212     PZ_DestroyLock(session->objectLock);
03213     if (session->enc_context) {
03214        sftk_FreeContext(session->enc_context);
03215     }
03216     if (session->hash_context) {
03217        sftk_FreeContext(session->hash_context);
03218     }
03219     if (session->sign_context) {
03220        sftk_FreeContext(session->sign_context);
03221     }
03222     if (session->search) {
03223        sftk_FreeSearch(session->search);
03224     }
03225     PORT_Free(session);
03226 }
03227 
03228 
03229 /*
03230  * look up a session structure from a session handle
03231  * generate a reference to it.
03232  */
03233 SFTKSession *
03234 sftk_SessionFromHandle(CK_SESSION_HANDLE handle)
03235 {
03236     SFTKSlot  *slot = sftk_SlotFromSessionHandle(handle);
03237     SFTKSession *session;
03238     PZLock    *lock;
03239     
03240     if (!slot) return NULL;
03241     lock = SFTK_SESSION_LOCK(slot,handle);
03242 
03243     PZ_Lock(lock);
03244     sftkqueue_find(session,handle,slot->head,slot->sessHashSize);
03245     if (session) session->refCount++;
03246     PZ_Unlock(lock);
03247 
03248     return (session);
03249 }
03250 
03251 /*
03252  * release a reference to a session handle
03253  */
03254 void
03255 sftk_FreeSession(SFTKSession *session)
03256 {
03257     PRBool destroy = PR_FALSE;
03258     SFTKSlot *slot = sftk_SlotFromSession(session);
03259     PZLock *lock = SFTK_SESSION_LOCK(slot,session->handle);
03260 
03261     PZ_Lock(lock);
03262     if (session->refCount == 1) destroy = PR_TRUE;
03263     session->refCount--;
03264     PZ_Unlock(lock);
03265 
03266     if (destroy) sftk_DestroySession(session);
03267 }
03268 /*
03269  * handle Token Object stuff
03270  */
03271 static void
03272 sftk_XORHash(unsigned char *key, unsigned char *dbkey, int len)
03273 {
03274    int i;
03275 
03276    PORT_Memset(key, 0, 4);
03277 
03278    for (i=0; i < len-4; i += 4) {
03279        key[0] ^= dbkey[i];
03280        key[1] ^= dbkey[i+1];
03281        key[2] ^= dbkey[i+2];
03282        key[3] ^= dbkey[i+3];
03283    }
03284 }
03285 
03286 /* Make a token handle for an object and record it so we can find it again */
03287 CK_OBJECT_HANDLE
03288 sftk_mkHandle(SFTKSlot *slot, SECItem *dbKey, CK_OBJECT_HANDLE class)
03289 {
03290     unsigned char hashBuf[4];
03291     CK_OBJECT_HANDLE handle;
03292     SECItem *key;
03293 
03294     handle = class;
03295     /* there is only one KRL, use a fixed handle for it */
03296     if (handle != SFTK_TOKEN_KRL_HANDLE) {
03297        sftk_XORHash(hashBuf,dbKey->data,dbKey->len);
03298        handle = (hashBuf[0] << 24) | (hashBuf[1] << 16) | 
03299                                    (hashBuf[2] << 8)  | hashBuf[3];
03300        handle = SFTK_TOKEN_MAGIC | class | 
03301                      (handle & ~(SFTK_TOKEN_TYPE_MASK|SFTK_TOKEN_MASK));
03302        /* we have a CRL who's handle has randomly matched the reserved KRL
03303         * handle, increment it */
03304        if (handle == SFTK_TOKEN_KRL_HANDLE) {
03305            handle++;
03306        }
03307     }
03308 
03309     sftk_tokenKeyLock(slot);
03310     while ((key = sftk_lookupTokenKeyByHandle(slot,handle)) != NULL) {
03311        if (SECITEM_ItemsAreEqual(key,dbKey)) {
03312           sftk_tokenKeyUnlock(slot);
03313           return handle;
03314        }
03315        handle++;
03316     }
03317     sftk_addTokenKeyByHandle(slot,handle,dbKey);
03318     sftk_tokenKeyUnlock(slot);
03319     return handle;
03320 }
03321 
03322 PRBool
03323 sftk_poisonHandle(SFTKSlot *slot, SECItem *dbKey, CK_OBJECT_HANDLE class)
03324 {
03325     unsigned char hashBuf[4];
03326     CK_OBJECT_HANDLE handle;
03327     SECItem *key;
03328 
03329     handle = class;
03330     /* there is only one KRL, use a fixed handle for it */
03331     if (handle != SFTK_TOKEN_KRL_HANDLE) {
03332        sftk_XORHash(hashBuf,dbKey->data,dbKey->len);
03333        handle = (hashBuf[0] << 24) | (hashBuf[1] << 16) | 
03334                                    (hashBuf[2] << 8)  | hashBuf[3];
03335        handle = SFTK_TOKEN_MAGIC | class | 
03336                      (handle & ~(SFTK_TOKEN_TYPE_MASK|SFTK_TOKEN_MASK));
03337        /* we have a CRL who's handle has randomly matched the reserved KRL
03338         * handle, increment it */
03339        if (handle == SFTK_TOKEN_KRL_HANDLE) {
03340            handle++;
03341        }
03342     }
03343     sftk_tokenKeyLock(slot);
03344     while ((key = sftk_lookupTokenKeyByHandle(slot,handle)) != NULL) {
03345        if (SECITEM_ItemsAreEqual(key,dbKey)) {
03346           key->data[0] ^= 0x80;
03347           sftk_tokenKeyUnlock(slot);
03348           return PR_TRUE;
03349        }
03350        handle++;
03351     }
03352     sftk_tokenKeyUnlock(slot);
03353     return PR_FALSE;
03354 }
03355 
03356 void
03357 sftk_addHandle(SFTKSearchResults *search, CK_OBJECT_HANDLE handle)
03358 {
03359     if (search->handles == NULL) {
03360        return;
03361     }
03362     if (search->size >= search->array_size) {
03363        search->array_size += NSC_SEARCH_BLOCK_SIZE;
03364        search->handles = (CK_OBJECT_HANDLE *) PORT_Realloc(search->handles,
03365                              sizeof(CK_OBJECT_HANDLE)* search->array_size);
03366        if (search->handles == NULL) {
03367           return;
03368        }
03369     }
03370     search->handles[search->size] = handle;
03371     search->size++;
03372 }
03373 
03374 static const CK_OBJECT_HANDLE sftk_classArray[] = {
03375     0, CKO_PRIVATE_KEY, CKO_PUBLIC_KEY, CKO_SECRET_KEY,
03376     CKO_NETSCAPE_TRUST, CKO_NETSCAPE_CRL, CKO_NETSCAPE_SMIME,
03377      CKO_CERTIFICATE };
03378 
03379 #define handleToClass(handle) \
03380     sftk_classArray[((handle & SFTK_TOKEN_TYPE_MASK))>>28]
03381 
03382 SFTKObject *
03383 sftk_NewTokenObject(SFTKSlot *slot, SECItem *dbKey, CK_OBJECT_HANDLE handle)
03384 {
03385     SFTKObject *object = NULL;
03386     SFTKTokenObject *tokObject = NULL;
03387     PRBool hasLocks = PR_FALSE;
03388     SECStatus rv;
03389 
03390     object = sftk_GetObjectFromList(&hasLocks, PR_FALSE, &tokenObjectList,  0,
03391                                                  PR_FALSE);
03392     if (object == NULL) {
03393        return NULL;
03394     }
03395     tokObject = (SFTKTokenObject *) object;
03396 
03397     object->objclass = handleToClass(handle);
03398     object->handle = handle;
03399     object->slot = slot;
03400     object->objectInfo = NULL;
03401     object->infoFree = NULL;
03402     if (dbKey == NULL) {
03403        sftk_tokenKeyLock(slot);
03404        dbKey = sftk_lookupTokenKeyByHandle(slot,handle);
03405        if (dbKey == NULL) {
03406            sftk_tokenKeyUnlock(slot);
03407            goto loser;
03408        }
03409        rv = SECITEM_CopyItem(NULL,&tokObject->dbKey,dbKey);
03410        sftk_tokenKeyUnlock(slot);
03411     } else {
03412        rv = SECITEM_CopyItem(NULL,&tokObject->dbKey,dbKey);
03413     }
03414     if (rv != SECSuccess) {
03415        goto loser;
03416     }
03417     if (!hasLocks) {
03418        object->refLock = PZ_NewLock(nssILockRefLock);
03419     }
03420     if (object->refLock == NULL) {
03421        goto loser;
03422     }
03423     object->refCount = 1;
03424 
03425     return object;
03426 loser:
03427     if (object) {
03428        (void) sftk_DestroyObject(object);
03429     }
03430     return NULL;
03431 
03432 }
03433 
03434 PRBool
03435 sftk_tokenMatch(SFTKSlot *slot, SECItem *dbKey, CK_OBJECT_HANDLE class,
03436                                    CK_ATTRIBUTE_PTR theTemplate,int count)
03437 {
03438     SFTKObject *object;
03439     PRBool ret;
03440 
03441     object = sftk_NewTokenObject(slot,dbKey,SFTK_TOKEN_MASK|class);
03442     if (object == NULL) {
03443        return PR_FALSE;
03444     }
03445 
03446     ret = sftk_objectMatch(object,theTemplate,count);
03447     sftk_FreeObject(object);
03448     return ret;
03449 }
03450 
03451 SFTKTokenObject *
03452 sftk_convertSessionToToken(SFTKObject *obj)
03453 {
03454     SECItem *key;
03455     SFTKSessionObject *so = (SFTKSessionObject *)obj;
03456     SFTKTokenObject *to = sftk_narrowToTokenObject(obj);
03457     SECStatus rv;
03458 
03459     sftk_DestroySessionObjectData(so);
03460     PZ_DestroyLock(so->attributeLock);
03461     if (to == NULL) {
03462        return NULL;
03463     }
03464     sftk_tokenKeyLock(so->obj.slot);
03465     key = sftk_lookupTokenKeyByHandle(so->obj.slot,so->obj.handle);
03466     if (key == NULL) {
03467        sftk_tokenKeyUnlock(so->obj.slot);
03468        return NULL;
03469     }
03470     rv = SECITEM_CopyItem(NULL,&to->dbKey,key);
03471     sftk_tokenKeyUnlock(so->obj.slot);
03472     if (rv == SECFailure) {
03473        return NULL;
03474     }
03475 
03476     return to;
03477 
03478 }
03479 
03480 SFTKSessionObject *
03481 sftk_narrowToSessionObject(SFTKObject *obj)
03482 {
03483     return !sftk_isToken(obj->handle) ? (SFTKSessionObject *)obj : NULL;
03484 }
03485 
03486 SFTKTokenObject *
03487 sftk_narrowToTokenObject(SFTKObject *obj)
03488 {
03489     return sftk_isToken(obj->handle) ? (SFTKTokenObject *)obj : NULL;
03490 }
03491