Back to index

lightning-sunbird  0.9+nobinonly
pkcs11.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 Stephen Henson <stephen.henson@gemplus.com>
00023  *   Dr Vipul Gupta <vipul.gupta@sun.com>, Sun Microsystems Laboratories
00024  *
00025  * Alternatively, the contents of this file may be used under the terms of
00026  * either the GNU General Public License Version 2 or later (the "GPL"), or
00027  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00028  * in which case the provisions of the GPL or the LGPL are applicable instead
00029  * of those above. If you wish to allow use of your version of this file only
00030  * under the terms of either the GPL or the LGPL, and not to allow others to
00031  * use your version of this file under the terms of the MPL, indicate your
00032  * decision by deleting the provisions above and replace them with the notice
00033  * and other provisions required by the GPL or the LGPL. If you do not delete
00034  * the provisions above, a recipient may use your version of this file under
00035  * the terms of any one of the MPL, the GPL or the LGPL.
00036  *
00037  * ***** END LICENSE BLOCK ***** */
00038 /*
00039  * This file implements PKCS 11 on top of our existing security modules
00040  *
00041  * For more information about PKCS 11 See PKCS 11 Token Inteface Standard.
00042  *   This implementation has two slots:
00043  *     slot 1 is our generic crypto support. It does not require login.
00044  *   It supports Public Key ops, and all they bulk ciphers and hashes. 
00045  *   It can also support Private Key ops for imported Private keys. It does 
00046  *   not have any token storage.
00047  *     slot 2 is our private key support. It requires a login before use. It
00048  *   can store Private Keys and Certs as token objects. Currently only private
00049  *   keys and their associated Certificates are saved on the token.
00050  *
00051  *   In this implementation, session objects are only visible to the session
00052  *   that created or generated them.
00053  */
00054 #include "seccomon.h"
00055 #include "secitem.h"
00056 #include "pkcs11.h"
00057 #include "pkcs11i.h"
00058 #include "softoken.h"
00059 #include "lowkeyi.h"
00060 #include "blapi.h"
00061 #include "secder.h"
00062 #include "secport.h"
00063 #include "pcert.h"
00064 #include "secrng.h"
00065 #include "softkver.h"
00066 
00067 #include "keydbi.h" 
00068 
00069 #ifdef DEBUG
00070 #include "cdbhdl.h"
00071 #endif
00072 
00073 /*
00074  * ******************** Static data *******************************
00075  */
00076 
00077 /* The next three strings must be exactly 32 characters long */
00078 static char *manufacturerID      = "Mozilla Foundation              ";
00079 static char manufacturerID_space[33];
00080 static char *libraryDescription  = "NSS Internal Crypto Services    ";
00081 static char libraryDescription_space[33];
00082 
00083 /*
00084  * In FIPS mode, we disallow login attempts for 1 second after a login
00085  * failure so that there are at most 60 login attempts per minute.
00086  */
00087 static PRIntervalTime loginWaitTime;
00088 static PRUint32       minSessionObjectHandle = 1U;
00089 
00090 #define __PASTE(x,y)    x##y
00091 
00092 /*
00093  * we renamed all our internal functions, get the correct
00094  * definitions for them...
00095  */ 
00096 #undef CK_PKCS11_FUNCTION_INFO
00097 #undef CK_NEED_ARG_LIST
00098 
00099 #define CK_EXTERN extern
00100 #define CK_PKCS11_FUNCTION_INFO(func) \
00101               CK_RV __PASTE(NS,func)
00102 #define CK_NEED_ARG_LIST    1
00103  
00104 #include "pkcs11f.h"
00105  
00106  
00107  
00108 /* build the crypto module table */
00109 static const CK_FUNCTION_LIST sftk_funcList = {
00110     { 1, 10 },
00111  
00112 #undef CK_PKCS11_FUNCTION_INFO
00113 #undef CK_NEED_ARG_LIST
00114  
00115 #define CK_PKCS11_FUNCTION_INFO(func) \
00116                             __PASTE(NS,func),
00117 #include "pkcs11f.h"
00118  
00119 };
00120  
00121 #undef CK_PKCS11_FUNCTION_INFO
00122 #undef CK_NEED_ARG_LIST
00123  
00124  
00125 #undef __PASTE
00126 
00127 /* List of DES Weak Keys */ 
00128 typedef unsigned char desKey[8];
00129 static const desKey  sftk_desWeakTable[] = {
00130 #ifdef noParity
00131     /* weak */
00132     { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
00133     { 0x1e, 0x1e, 0x1e, 0x1e, 0x0e, 0x0e, 0x0e, 0x0e },
00134     { 0xe0, 0xe0, 0xe0, 0xe0, 0xf0, 0xf0, 0xf0, 0xf0 },
00135     { 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe },
00136     /* semi-weak */
00137     { 0x00, 0xfe, 0x00, 0xfe, 0x00, 0xfe, 0x00, 0xfe },
00138     { 0xfe, 0x00, 0xfe, 0x00, 0x00, 0xfe, 0x00, 0xfe },
00139 
00140     { 0x1e, 0xe0, 0x1e, 0xe0, 0x0e, 0xf0, 0x0e, 0xf0 },
00141     { 0xe0, 0x1e, 0xe0, 0x1e, 0xf0, 0x0e, 0xf0, 0x0e },
00142 
00143     { 0x00, 0xe0, 0x00, 0xe0, 0x00, 0x0f, 0x00, 0x0f },
00144     { 0xe0, 0x00, 0xe0, 0x00, 0xf0, 0x00, 0xf0, 0x00 },
00145 
00146     { 0x1e, 0xfe, 0x1e, 0xfe, 0x0e, 0xfe, 0x0e, 0xfe },
00147     { 0xfe, 0x1e, 0xfe, 0x1e, 0xfe, 0x0e, 0xfe, 0x0e },
00148 
00149     { 0x00, 0x1e, 0x00, 0x1e, 0x00, 0x0e, 0x00, 0x0e },
00150     { 0x1e, 0x00, 0x1e, 0x00, 0x0e, 0x00, 0x0e, 0x00 },
00151 
00152     { 0xe0, 0xfe, 0xe0, 0xfe, 0xf0, 0xfe, 0xf0, 0xfe },
00153     { 0xfe, 0xe0, 0xfe, 0xe0, 0xfe, 0xf0, 0xfe, 0xf0 },
00154 #else
00155     /* weak */
00156     { 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 },
00157     { 0x1f, 0x1f, 0x1f, 0x1f, 0x0e, 0x0e, 0x0e, 0x0e },
00158     { 0xe0, 0xe0, 0xe0, 0xe0, 0xf1, 0xf1, 0xf1, 0xf1 },
00159     { 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe },
00160 
00161     /* semi-weak */
00162     { 0x01, 0xfe, 0x01, 0xfe, 0x01, 0xfe, 0x01, 0xfe },
00163     { 0xfe, 0x01, 0xfe, 0x01, 0xfe, 0x01, 0xfe, 0x01 },
00164 
00165     { 0x1f, 0xe0, 0x1f, 0xe0, 0x0e, 0xf1, 0x0e, 0xf1 },
00166     { 0xe0, 0x1f, 0xe0, 0x1f, 0xf1, 0x0e, 0xf1, 0x0e },
00167 
00168     { 0x01, 0xe0, 0x01, 0xe0, 0x01, 0xf1, 0x01, 0xf1 },
00169     { 0xe0, 0x01, 0xe0, 0x01, 0xf1, 0x01, 0xf1, 0x01 },
00170 
00171     { 0x1f, 0xfe, 0x1f, 0xfe, 0x0e, 0xfe, 0x0e, 0xfe },
00172     { 0xfe, 0x1f, 0xfe, 0x1f, 0xfe, 0x0e, 0xfe, 0x0e },
00173 
00174     { 0x01, 0x1f, 0x01, 0x1f, 0x01, 0x0e, 0x01, 0x0e },
00175     { 0x1f, 0x01, 0x1f, 0x01, 0x0e, 0x01, 0x0e, 0x01 },
00176 
00177     { 0xe0, 0xfe, 0xe0, 0xfe, 0xf1, 0xfe, 0xf1, 0xfe }, 
00178     { 0xfe, 0xe0, 0xfe, 0xe0, 0xfe, 0xf1, 0xfe, 0xf1 }
00179 #endif
00180 };
00181 
00182     
00183 static const int sftk_desWeakTableSize = sizeof(sftk_desWeakTable)/
00184                                           sizeof(sftk_desWeakTable[0]);
00185 
00186 /* DES KEY Parity conversion table. Takes each byte/2 as an index, returns
00187  * that byte with the proper parity bit set */
00188 static const unsigned char parityTable[256] = {
00189 /* Even...0x00,0x02,0x04,0x06,0x08,0x0a,0x0c,0x0e */
00190 /* E */   0x01,0x02,0x04,0x07,0x08,0x0b,0x0d,0x0e,
00191 /* Odd....0x10,0x12,0x14,0x16,0x18,0x1a,0x1c,0x1e */
00192 /* O */   0x10,0x13,0x15,0x16,0x19,0x1a,0x1c,0x1f,
00193 /* Odd....0x20,0x22,0x24,0x26,0x28,0x2a,0x2c,0x2e */
00194 /* O */   0x20,0x23,0x25,0x26,0x29,0x2a,0x2c,0x2f,
00195 /* Even...0x30,0x32,0x34,0x36,0x38,0x3a,0x3c,0x3e */
00196 /* E */   0x31,0x32,0x34,0x37,0x38,0x3b,0x3d,0x3e,
00197 /* Odd....0x40,0x42,0x44,0x46,0x48,0x4a,0x4c,0x4e */
00198 /* O */   0x40,0x43,0x45,0x46,0x49,0x4a,0x4c,0x4f,
00199 /* Even...0x50,0x52,0x54,0x56,0x58,0x5a,0x5c,0x5e */
00200 /* E */   0x51,0x52,0x54,0x57,0x58,0x5b,0x5d,0x5e,
00201 /* Even...0x60,0x62,0x64,0x66,0x68,0x6a,0x6c,0x6e */
00202 /* E */   0x61,0x62,0x64,0x67,0x68,0x6b,0x6d,0x6e,
00203 /* Odd....0x70,0x72,0x74,0x76,0x78,0x7a,0x7c,0x7e */
00204 /* O */   0x70,0x73,0x75,0x76,0x79,0x7a,0x7c,0x7f,
00205 /* Odd....0x80,0x82,0x84,0x86,0x88,0x8a,0x8c,0x8e */
00206 /* O */   0x80,0x83,0x85,0x86,0x89,0x8a,0x8c,0x8f,
00207 /* Even...0x90,0x92,0x94,0x96,0x98,0x9a,0x9c,0x9e */
00208 /* E */   0x91,0x92,0x94,0x97,0x98,0x9b,0x9d,0x9e,
00209 /* Even...0xa0,0xa2,0xa4,0xa6,0xa8,0xaa,0xac,0xae */
00210 /* E */   0xa1,0xa2,0xa4,0xa7,0xa8,0xab,0xad,0xae,
00211 /* Odd....0xb0,0xb2,0xb4,0xb6,0xb8,0xba,0xbc,0xbe */
00212 /* O */   0xb0,0xb3,0xb5,0xb6,0xb9,0xba,0xbc,0xbf,
00213 /* Even...0xc0,0xc2,0xc4,0xc6,0xc8,0xca,0xcc,0xce */
00214 /* E */   0xc1,0xc2,0xc4,0xc7,0xc8,0xcb,0xcd,0xce,
00215 /* Odd....0xd0,0xd2,0xd4,0xd6,0xd8,0xda,0xdc,0xde */
00216 /* O */   0xd0,0xd3,0xd5,0xd6,0xd9,0xda,0xdc,0xdf,
00217 /* Odd....0xe0,0xe2,0xe4,0xe6,0xe8,0xea,0xec,0xee */
00218 /* O */   0xe0,0xe3,0xe5,0xe6,0xe9,0xea,0xec,0xef,
00219 /* Even...0xf0,0xf2,0xf4,0xf6,0xf8,0xfa,0xfc,0xfe */
00220 /* E */   0xf1,0xf2,0xf4,0xf7,0xf8,0xfb,0xfd,0xfe,
00221 };
00222 
00223 /* Mechanisms */
00224 struct mechanismList {
00225     CK_MECHANISM_TYPE       type;
00226     CK_MECHANISM_INFO       info;
00227     PRBool           privkey;
00228 };
00229 
00230 /*
00231  * the following table includes a complete list of mechanism defined by
00232  * PKCS #11 version 2.01. Those Mechanisms not supported by this PKCS #11
00233  * module are ifdef'ed out.
00234  */
00235 #define CKF_EN_DE           CKF_ENCRYPT      | CKF_DECRYPT
00236 #define CKF_WR_UN           CKF_WRAP         | CKF_UNWRAP
00237 #define CKF_SN_VR           CKF_SIGN         | CKF_VERIFY
00238 #define CKF_SN_RE           CKF_SIGN_RECOVER | CKF_VERIFY_RECOVER
00239 
00240 #define CKF_EN_DE_WR_UN     CKF_EN_DE       | CKF_WR_UN
00241 #define CKF_SN_VR_RE        CKF_SN_VR       | CKF_SN_RE
00242 #define CKF_DUZ_IT_ALL             CKF_EN_DE_WR_UN | CKF_SN_VR_RE
00243 
00244 #define CKF_EC_PNU          CKF_EC_FP | CKF_EC_NAMEDCURVE | CKF_EC_UNCOMPRESS
00245 
00246 #define CKF_EC_BPNU         CKF_EC_F_2M | CKF_EC_PNU
00247 
00248 #define CK_MAX 0xffffffff
00249 
00250 static const struct mechanismList mechanisms[] = {
00251 
00252      /*
00253       * PKCS #11 Mechanism List.
00254       *
00255       * The first argument is the PKCS #11 Mechanism we support.
00256       * The second argument is Mechanism info structure. It includes:
00257       *    The minimum key size,
00258       *       in bits for RSA, DSA, DH, EC*, KEA, RC2 and RC4 * algs.
00259       *       in bytes for RC5, AES, and CAST*
00260       *       ignored for DES*, IDEA and FORTEZZA based
00261       *    The maximum key size,
00262       *       in bits for RSA, DSA, DH, EC*, KEA, RC2 and RC4 * algs.
00263       *       in bytes for RC5, AES, and CAST*
00264       *       ignored for DES*, IDEA and FORTEZZA based
00265       *     Flags
00266       *             What operations are supported by this mechanism.
00267       *  The third argument is a bool which tells if this mechanism is 
00268       *    supported in the database token.
00269       *
00270       */
00271 
00272      /* ------------------------- RSA Operations ---------------------------*/
00273      {CKM_RSA_PKCS_KEY_PAIR_GEN,{RSA_MIN_MODULUS_BITS,CK_MAX,
00274                              CKF_GENERATE_KEY_PAIR},PR_TRUE},
00275      {CKM_RSA_PKCS,             {RSA_MIN_MODULUS_BITS,CK_MAX,
00276                              CKF_DUZ_IT_ALL},       PR_TRUE},
00277 #ifdef SFTK_RSA9796_SUPPORTED
00278      {CKM_RSA_9796,         {RSA_MIN_MODULUS_BITS,CK_MAX,
00279                              CKF_DUZ_IT_ALL},       PR_TRUE},
00280 #endif
00281      {CKM_RSA_X_509,        {RSA_MIN_MODULUS_BITS,CK_MAX,
00282                              CKF_DUZ_IT_ALL},       PR_TRUE},
00283      /* -------------- RSA Multipart Signing Operations -------------------- */
00284      {CKM_MD2_RSA_PKCS,            {RSA_MIN_MODULUS_BITS,CK_MAX,
00285                              CKF_SN_VR},  PR_TRUE},
00286      {CKM_MD5_RSA_PKCS,            {RSA_MIN_MODULUS_BITS,CK_MAX,
00287                              CKF_SN_VR},  PR_TRUE},
00288      {CKM_SHA1_RSA_PKCS,    {RSA_MIN_MODULUS_BITS,CK_MAX,
00289                              CKF_SN_VR},  PR_TRUE},
00290      {CKM_SHA256_RSA_PKCS,  {RSA_MIN_MODULUS_BITS,CK_MAX,
00291                              CKF_SN_VR},  PR_TRUE},
00292      {CKM_SHA384_RSA_PKCS,  {RSA_MIN_MODULUS_BITS,CK_MAX,
00293                              CKF_SN_VR},  PR_TRUE},
00294      {CKM_SHA512_RSA_PKCS,  {RSA_MIN_MODULUS_BITS,CK_MAX,
00295                              CKF_SN_VR},  PR_TRUE},
00296      /* ------------------------- DSA Operations --------------------------- */
00297      {CKM_DSA_KEY_PAIR_GEN, {DSA_MIN_P_BITS, DSA_MAX_P_BITS,
00298                              CKF_GENERATE_KEY_PAIR}, PR_TRUE},
00299      {CKM_DSA,                     {DSA_MIN_P_BITS, DSA_MAX_P_BITS, 
00300                              CKF_SN_VR},              PR_TRUE},
00301      {CKM_DSA_SHA1,         {DSA_MIN_P_BITS, DSA_MAX_P_BITS,
00302                              CKF_SN_VR},              PR_TRUE},
00303      /* -------------------- Diffie Hellman Operations --------------------- */
00304      /* no diffie hellman yet */
00305      {CKM_DH_PKCS_KEY_PAIR_GEN,    {DH_MIN_P_BITS, DH_MAX_P_BITS, 
00306                              CKF_GENERATE_KEY_PAIR}, PR_TRUE}, 
00307      {CKM_DH_PKCS_DERIVE,   {DH_MIN_P_BITS, DH_MAX_P_BITS,
00308                              CKF_DERIVE},        PR_TRUE}, 
00309 #ifdef NSS_ENABLE_ECC
00310      /* -------------------- Elliptic Curve Operations --------------------- */
00311      {CKM_EC_KEY_PAIR_GEN,      {112, 571, CKF_GENERATE_KEY_PAIR|CKF_EC_BPNU}, PR_TRUE}, 
00312      {CKM_ECDH1_DERIVE,         {112, 571, CKF_DERIVE|CKF_EC_BPNU}, PR_TRUE}, 
00313      {CKM_ECDSA,                {112, 571, CKF_SN_VR|CKF_EC_BPNU}, PR_TRUE}, 
00314      {CKM_ECDSA_SHA1,           {112, 571, CKF_SN_VR|CKF_EC_BPNU}, PR_TRUE}, 
00315 #endif /* NSS_ENABLE_ECC */
00316      /* ------------------------- RC2 Operations --------------------------- */
00317      {CKM_RC2_KEY_GEN,             {1, 128, CKF_GENERATE},            PR_TRUE},
00318      {CKM_RC2_ECB,          {1, 128, CKF_EN_DE_WR_UN},  PR_TRUE},
00319      {CKM_RC2_CBC,          {1, 128, CKF_EN_DE_WR_UN},  PR_TRUE},
00320      {CKM_RC2_MAC,          {1, 128, CKF_SN_VR},        PR_TRUE},
00321      {CKM_RC2_MAC_GENERAL,  {1, 128, CKF_SN_VR},        PR_TRUE},
00322      {CKM_RC2_CBC_PAD,             {1, 128, CKF_EN_DE_WR_UN},  PR_TRUE},
00323      /* ------------------------- RC4 Operations --------------------------- */
00324      {CKM_RC4_KEY_GEN,             {1, 256, CKF_GENERATE},            PR_FALSE},
00325      {CKM_RC4,                     {1, 256, CKF_EN_DE_WR_UN},  PR_FALSE},
00326      /* ------------------------- DES Operations --------------------------- */
00327      {CKM_DES_KEY_GEN,             { 8,  8, CKF_GENERATE},            PR_TRUE},
00328      {CKM_DES_ECB,          { 8,  8, CKF_EN_DE_WR_UN},  PR_TRUE},
00329      {CKM_DES_CBC,          { 8,  8, CKF_EN_DE_WR_UN},  PR_TRUE},
00330      {CKM_DES_MAC,          { 8,  8, CKF_SN_VR},        PR_TRUE},
00331      {CKM_DES_MAC_GENERAL,  { 8,  8, CKF_SN_VR},        PR_TRUE},
00332      {CKM_DES_CBC_PAD,             { 8,  8, CKF_EN_DE_WR_UN},  PR_TRUE},
00333      {CKM_DES2_KEY_GEN,            {24, 24, CKF_GENERATE},            PR_TRUE},
00334      {CKM_DES3_KEY_GEN,            {24, 24, CKF_GENERATE},            PR_TRUE },
00335      {CKM_DES3_ECB,         {24, 24, CKF_EN_DE_WR_UN},  PR_TRUE },
00336      {CKM_DES3_CBC,         {24, 24, CKF_EN_DE_WR_UN},  PR_TRUE },
00337      {CKM_DES3_MAC,         {24, 24, CKF_SN_VR},        PR_TRUE },
00338      {CKM_DES3_MAC_GENERAL, {24, 24, CKF_SN_VR},        PR_TRUE },
00339      {CKM_DES3_CBC_PAD,            {24, 24, CKF_EN_DE_WR_UN},  PR_TRUE },
00340      /* ------------------------- CDMF Operations --------------------------- */
00341      {CKM_CDMF_KEY_GEN,            {8,  8, CKF_GENERATE},             PR_TRUE},
00342      {CKM_CDMF_ECB,         {8,  8, CKF_EN_DE_WR_UN},   PR_TRUE},
00343      {CKM_CDMF_CBC,         {8,  8, CKF_EN_DE_WR_UN},   PR_TRUE},
00344      {CKM_CDMF_MAC,         {8,  8, CKF_SN_VR},         PR_TRUE},
00345      {CKM_CDMF_MAC_GENERAL, {8,  8, CKF_SN_VR},         PR_TRUE},
00346      {CKM_CDMF_CBC_PAD,            {8,  8, CKF_EN_DE_WR_UN},   PR_TRUE},
00347      /* ------------------------- AES Operations --------------------------- */
00348      {CKM_AES_KEY_GEN,             {16, 32, CKF_GENERATE},            PR_TRUE},
00349      {CKM_AES_ECB,          {16, 32, CKF_EN_DE_WR_UN},  PR_TRUE},
00350      {CKM_AES_CBC,          {16, 32, CKF_EN_DE_WR_UN},  PR_TRUE},
00351      {CKM_AES_MAC,          {16, 32, CKF_SN_VR},        PR_TRUE},
00352      {CKM_AES_MAC_GENERAL,  {16, 32, CKF_SN_VR},        PR_TRUE},
00353      {CKM_AES_CBC_PAD,             {16, 32, CKF_EN_DE_WR_UN},  PR_TRUE},
00354      /* ------------------------- Hashing Operations ----------------------- */
00355      {CKM_MD2,                     {0,   0, CKF_DIGEST},              PR_FALSE},
00356      {CKM_MD2_HMAC,         {1, 128, CKF_SN_VR},        PR_TRUE},
00357      {CKM_MD2_HMAC_GENERAL, {1, 128, CKF_SN_VR},        PR_TRUE},
00358      {CKM_MD5,                     {0,   0, CKF_DIGEST},              PR_FALSE},
00359      {CKM_MD5_HMAC,         {1, 128, CKF_SN_VR},        PR_TRUE},
00360      {CKM_MD5_HMAC_GENERAL, {1, 128, CKF_SN_VR},        PR_TRUE},
00361      {CKM_SHA_1,            {0,   0, CKF_DIGEST},              PR_FALSE},
00362      {CKM_SHA_1_HMAC,              {1, 128, CKF_SN_VR},        PR_TRUE},
00363      {CKM_SHA_1_HMAC_GENERAL,      {1, 128, CKF_SN_VR},        PR_TRUE},
00364      {CKM_SHA256,           {0,   0, CKF_DIGEST},              PR_FALSE},
00365      {CKM_SHA256_HMAC,             {1, 128, CKF_SN_VR},        PR_TRUE},
00366      {CKM_SHA256_HMAC_GENERAL,     {1, 128, CKF_SN_VR},        PR_TRUE},
00367      {CKM_SHA384,           {0,   0, CKF_DIGEST},              PR_FALSE},
00368      {CKM_SHA384_HMAC,             {1, 128, CKF_SN_VR},        PR_TRUE},
00369      {CKM_SHA384_HMAC_GENERAL,     {1, 128, CKF_SN_VR},        PR_TRUE},
00370      {CKM_SHA512,           {0,   0, CKF_DIGEST},              PR_FALSE},
00371      {CKM_SHA512_HMAC,             {1, 128, CKF_SN_VR},        PR_TRUE},
00372      {CKM_SHA512_HMAC_GENERAL,     {1, 128, CKF_SN_VR},        PR_TRUE},
00373      {CKM_TLS_PRF_GENERAL,  {0, 512, CKF_SN_VR},        PR_FALSE},
00374      /* ------------------------- CAST Operations --------------------------- */
00375 #ifdef NSS_SOFTOKEN_DOES_CAST
00376      /* Cast operations are not supported ( yet? ) */
00377      {CKM_CAST_KEY_GEN,            {1,  8, CKF_GENERATE},             PR_TRUE}, 
00378      {CKM_CAST_ECB,         {1,  8, CKF_EN_DE_WR_UN},   PR_TRUE}, 
00379      {CKM_CAST_CBC,         {1,  8, CKF_EN_DE_WR_UN},   PR_TRUE}, 
00380      {CKM_CAST_MAC,         {1,  8, CKF_SN_VR},         PR_TRUE}, 
00381      {CKM_CAST_MAC_GENERAL, {1,  8, CKF_SN_VR},         PR_TRUE}, 
00382      {CKM_CAST_CBC_PAD,            {1,  8, CKF_EN_DE_WR_UN},   PR_TRUE}, 
00383      {CKM_CAST3_KEY_GEN,    {1, 16, CKF_GENERATE},             PR_TRUE}, 
00384      {CKM_CAST3_ECB,        {1, 16, CKF_EN_DE_WR_UN},   PR_TRUE}, 
00385      {CKM_CAST3_CBC,        {1, 16, CKF_EN_DE_WR_UN},   PR_TRUE}, 
00386      {CKM_CAST3_MAC,        {1, 16, CKF_SN_VR},         PR_TRUE}, 
00387      {CKM_CAST3_MAC_GENERAL,       {1, 16, CKF_SN_VR},         PR_TRUE}, 
00388      {CKM_CAST3_CBC_PAD,    {1, 16, CKF_EN_DE_WR_UN},   PR_TRUE}, 
00389      {CKM_CAST5_KEY_GEN,    {1, 16, CKF_GENERATE},             PR_TRUE}, 
00390      {CKM_CAST5_ECB,        {1, 16, CKF_EN_DE_WR_UN},   PR_TRUE}, 
00391      {CKM_CAST5_CBC,        {1, 16, CKF_EN_DE_WR_UN},   PR_TRUE}, 
00392      {CKM_CAST5_MAC,        {1, 16, CKF_SN_VR},         PR_TRUE}, 
00393      {CKM_CAST5_MAC_GENERAL,       {1, 16, CKF_SN_VR},         PR_TRUE}, 
00394      {CKM_CAST5_CBC_PAD,    {1, 16, CKF_EN_DE_WR_UN},   PR_TRUE}, 
00395 #endif
00396 #if NSS_SOFTOKEN_DOES_RC5
00397      /* ------------------------- RC5 Operations --------------------------- */
00398      {CKM_RC5_KEY_GEN,             {1, 32, CKF_GENERATE},          PR_TRUE},
00399      {CKM_RC5_ECB,          {1, 32, CKF_EN_DE_WR_UN},   PR_TRUE},
00400      {CKM_RC5_CBC,          {1, 32, CKF_EN_DE_WR_UN},   PR_TRUE},
00401      {CKM_RC5_MAC,          {1, 32, CKF_SN_VR},                PR_TRUE},
00402      {CKM_RC5_MAC_GENERAL,  {1, 32, CKF_SN_VR},                PR_TRUE},
00403      {CKM_RC5_CBC_PAD,             {1, 32, CKF_EN_DE_WR_UN},   PR_TRUE},
00404 #endif
00405 #ifdef NSS_SOFTOKEN_DOES_IDEA
00406      /* ------------------------- IDEA Operations -------------------------- */
00407      {CKM_IDEA_KEY_GEN,            {16, 16, CKF_GENERATE},     PR_TRUE}, 
00408      {CKM_IDEA_ECB,         {16, 16, CKF_EN_DE_WR_UN},  PR_TRUE}, 
00409      {CKM_IDEA_CBC,         {16, 16, CKF_EN_DE_WR_UN},  PR_TRUE}, 
00410      {CKM_IDEA_MAC,         {16, 16, CKF_SN_VR},        PR_TRUE}, 
00411      {CKM_IDEA_MAC_GENERAL, {16, 16, CKF_SN_VR},        PR_TRUE}, 
00412      {CKM_IDEA_CBC_PAD,            {16, 16, CKF_EN_DE_WR_UN},  PR_TRUE}, 
00413 #endif
00414      /* --------------------- Secret Key Operations ------------------------ */
00415      {CKM_GENERIC_SECRET_KEY_GEN,  {1, 32, CKF_GENERATE}, PR_TRUE}, 
00416      {CKM_CONCATENATE_BASE_AND_KEY,       {1, 32, CKF_GENERATE}, PR_FALSE}, 
00417      {CKM_CONCATENATE_BASE_AND_DATA,      {1, 32, CKF_GENERATE}, PR_FALSE}, 
00418      {CKM_CONCATENATE_DATA_AND_BASE,      {1, 32, CKF_GENERATE}, PR_FALSE}, 
00419      {CKM_XOR_BASE_AND_DATA,              {1, 32, CKF_GENERATE}, PR_FALSE}, 
00420      {CKM_EXTRACT_KEY_FROM_KEY,           {1, 32, CKF_DERIVE},   PR_FALSE}, 
00421      /* ---------------------- SSL Key Derivations ------------------------- */
00422      {CKM_SSL3_PRE_MASTER_KEY_GEN, {48, 48, CKF_GENERATE}, PR_FALSE}, 
00423      {CKM_SSL3_MASTER_KEY_DERIVE,  {48, 48, CKF_DERIVE},   PR_FALSE}, 
00424      {CKM_SSL3_MASTER_KEY_DERIVE_DH,      {8, 128, CKF_DERIVE},   PR_FALSE}, 
00425      {CKM_SSL3_KEY_AND_MAC_DERIVE, {48, 48, CKF_DERIVE},   PR_FALSE}, 
00426      {CKM_SSL3_MD5_MAC,                   { 0, 16, CKF_DERIVE},   PR_FALSE}, 
00427      {CKM_SSL3_SHA1_MAC,           { 0, 20, CKF_DERIVE},   PR_FALSE}, 
00428      {CKM_MD5_KEY_DERIVATION,             { 0, 16, CKF_DERIVE},   PR_FALSE}, 
00429      {CKM_MD2_KEY_DERIVATION,             { 0, 16, CKF_DERIVE},   PR_FALSE}, 
00430      {CKM_SHA1_KEY_DERIVATION,            { 0, 20, CKF_DERIVE},   PR_FALSE}, 
00431      {CKM_TLS_MASTER_KEY_DERIVE,   {48, 48, CKF_DERIVE},   PR_FALSE}, 
00432      {CKM_TLS_MASTER_KEY_DERIVE_DH,       {8, 128, CKF_DERIVE},   PR_FALSE}, 
00433      {CKM_TLS_KEY_AND_MAC_DERIVE,  {48, 48, CKF_DERIVE},   PR_FALSE}, 
00434      /* ---------------------- PBE Key Derivations  ------------------------ */
00435      {CKM_PBE_MD2_DES_CBC,         {8, 8, CKF_DERIVE},   PR_TRUE},
00436      {CKM_PBE_MD5_DES_CBC,         {8, 8, CKF_DERIVE},   PR_TRUE},
00437      /* ------------------ NETSCAPE PBE Key Derivations  ------------------- */
00438      {CKM_NETSCAPE_PBE_SHA1_DES_CBC,           { 8, 8, CKF_GENERATE}, PR_TRUE},
00439      {CKM_NETSCAPE_PBE_SHA1_FAULTY_3DES_CBC, {24,24, CKF_GENERATE}, PR_TRUE},
00440      {CKM_PBE_SHA1_DES3_EDE_CBC,        {24,24, CKF_GENERATE}, PR_TRUE},
00441      {CKM_PBE_SHA1_DES2_EDE_CBC,        {24,24, CKF_GENERATE}, PR_TRUE},
00442      {CKM_PBE_SHA1_RC2_40_CBC,                 {40,40, CKF_GENERATE}, PR_TRUE},
00443      {CKM_PBE_SHA1_RC2_128_CBC,                {128,128, CKF_GENERATE}, PR_TRUE},
00444      {CKM_PBE_SHA1_RC4_40,              {40,40, CKF_GENERATE}, PR_TRUE},
00445      {CKM_PBE_SHA1_RC4_128,             {128,128, CKF_GENERATE}, PR_TRUE},
00446      {CKM_PBA_SHA1_WITH_SHA1_HMAC,      {20,20, CKF_GENERATE}, PR_TRUE},
00447      {CKM_NETSCAPE_PBE_SHA1_HMAC_KEY_GEN,    {20,20, CKF_GENERATE}, PR_TRUE},
00448      {CKM_NETSCAPE_PBE_MD5_HMAC_KEY_GEN,     {16,16, CKF_GENERATE}, PR_TRUE},
00449      {CKM_NETSCAPE_PBE_MD2_HMAC_KEY_GEN,     {16,16, CKF_GENERATE}, PR_TRUE},
00450      /* ------------------ AES Key Wrap (also encrypt)  ------------------- */
00451      {CKM_NETSCAPE_AES_KEY_WRAP,   {16, 32, CKF_EN_DE_WR_UN},  PR_TRUE},
00452      {CKM_NETSCAPE_AES_KEY_WRAP_PAD,      {16, 32, CKF_EN_DE_WR_UN},  PR_TRUE},
00453 };
00454 static const CK_ULONG mechanismCount = sizeof(mechanisms)/sizeof(mechanisms[0]);
00455 
00456 static char *
00457 sftk_setStringName(const char *inString, char *buffer, int buffer_length)
00458 {
00459     int full_length, string_length;
00460 
00461     full_length = buffer_length -1;
00462     string_length = PORT_Strlen(inString);
00463     /* 
00464      *  shorten the string, respecting utf8 encoding
00465      *  to do so, we work backward from the end 
00466      *  bytes looking from the end are either:
00467      *    - ascii [0x00,0x7f]
00468      *    - the [2-n]th byte of a multibyte sequence 
00469      *        [0x3F,0xBF], i.e, most significant 2 bits are '10'
00470      *    - the first byte of a multibyte sequence [0xC0,0xFD],
00471      *        i.e, most significant 2 bits are '11'
00472      *
00473      *    When the string is too long, we lop off any trailing '10' bytes,
00474      *  if any. When these are all eliminated we lop off
00475      *  one additional byte. Thus if we lopped any '10'
00476      *  we'll be lopping a '11' byte (the first byte of the multibyte sequence),
00477      *  otherwise we're lopping off an ascii character.
00478      *
00479      *    To test for '10' bytes, we first AND it with 
00480      *  11000000 (0xc0) so that we get 10000000 (0x80) if and only if
00481      *  the byte starts with 10. We test for equality.
00482      */
00483     while ( string_length > full_length ) {
00484        /* need to shorten */
00485        while ( string_length > 0 && 
00486              ((inString[string_length-1]&(char)0xc0) == (char)0x80)) {
00487            /* lop off '10' byte */
00488            string_length--;
00489        }
00490        /* 
00491         * test string_length in case bad data is received
00492         * and string consisted of all '10' bytes,
00493         * avoiding any infinite loop
00494          */
00495        if ( string_length ) {
00496            /* remove either '11' byte or an asci byte */
00497            string_length--;
00498        }
00499     }
00500     PORT_Memset(buffer,' ',full_length);
00501     buffer[full_length] = 0;
00502     PORT_Memcpy(buffer,inString,string_length);
00503     return buffer;
00504 }
00505 /*
00506  * Configuration utils
00507  */
00508 static CK_RV
00509 sftk_configure(const char *man, const char *libdes)
00510 {
00511 
00512     /* make sure the internationalization was done correctly... */
00513     if (man) {
00514        manufacturerID = sftk_setStringName(man,manufacturerID_space,
00515                                           sizeof(manufacturerID_space));
00516     }
00517     if (libdes) {
00518        libraryDescription = sftk_setStringName(libdes,
00519               libraryDescription_space, sizeof(libraryDescription_space));
00520     }
00521 
00522     return CKR_OK;
00523 }
00524 
00525 /*
00526  * ******************** Password Utilities *******************************
00527  */
00528 
00529 /*
00530  * see if the key DB password is enabled
00531  */
00532 static PRBool
00533 sftk_hasNullPassword(NSSLOWKEYDBHandle *keydb,SECItem **pwitem)
00534 {
00535     PRBool pwenabled;
00536     
00537     pwenabled = PR_FALSE;
00538     *pwitem = NULL;
00539     if (nsslowkey_HasKeyDBPassword (keydb) == SECSuccess) {
00540        *pwitem = nsslowkey_HashPassword("", keydb->global_salt);
00541        if ( *pwitem ) {
00542            if (nsslowkey_CheckKeyDBPassword (keydb, *pwitem) == SECSuccess) {
00543               pwenabled = PR_TRUE;
00544            } else {
00545               SECITEM_ZfreeItem(*pwitem, PR_TRUE);
00546               *pwitem = NULL;
00547            }
00548        }
00549     }
00550 
00551     return pwenabled;
00552 }
00553 
00554 /*
00555  * ******************** Object Creation Utilities ***************************
00556  */
00557 
00558 
00559 /* Make sure a given attribute exists. If it doesn't, initialize it to
00560  * value and len
00561  */
00562 CK_RV
00563 sftk_defaultAttribute(SFTKObject *object,CK_ATTRIBUTE_TYPE type,void *value,
00564                                                  unsigned int len)
00565 {
00566     if ( !sftk_hasAttribute(object, type)) {
00567        return sftk_AddAttributeType(object,type,value,len);
00568     }
00569     return CKR_OK;
00570 }
00571 
00572 /*
00573  * check the consistancy and initialize a Data Object 
00574  */
00575 static CK_RV
00576 sftk_handleDataObject(SFTKSession *session,SFTKObject *object)
00577 {
00578     CK_RV crv;
00579 
00580     /* first reject private and token data objects */
00581     if (sftk_isTrue(object,CKA_PRIVATE) || sftk_isTrue(object,CKA_TOKEN)) {
00582        return CKR_ATTRIBUTE_VALUE_INVALID;
00583     }
00584 
00585     /* now just verify the required date fields */
00586     crv = sftk_defaultAttribute(object,CKA_APPLICATION,NULL,0);
00587     if (crv != CKR_OK) return crv;
00588     crv = sftk_defaultAttribute(object,CKA_VALUE,NULL,0);
00589     if (crv != CKR_OK) return crv;
00590 
00591     return CKR_OK;
00592 }
00593 
00594 /*
00595  * check the consistancy and initialize a Certificate Object 
00596  */
00597 static CK_RV
00598 sftk_handleCertObject(SFTKSession *session,SFTKObject *object)
00599 {
00600     CK_CERTIFICATE_TYPE type;
00601     SFTKAttribute *attribute;
00602     CK_RV crv;
00603 
00604     /* certificates must have a type */
00605     if ( !sftk_hasAttribute(object,CKA_CERTIFICATE_TYPE) ) {
00606        return CKR_TEMPLATE_INCOMPLETE;
00607     }
00608 
00609     /* we can't store any certs private */
00610     if (sftk_isTrue(object,CKA_PRIVATE)) {
00611        return CKR_ATTRIBUTE_VALUE_INVALID;
00612     }
00613        
00614     /* We only support X.509 Certs for now */
00615     attribute = sftk_FindAttribute(object,CKA_CERTIFICATE_TYPE);
00616     if (attribute == NULL) return CKR_TEMPLATE_INCOMPLETE;
00617     type = *(CK_CERTIFICATE_TYPE *)attribute->attrib.pValue;
00618     sftk_FreeAttribute(attribute);
00619 
00620     if (type != CKC_X_509) {
00621        return CKR_ATTRIBUTE_VALUE_INVALID;
00622     }
00623 
00624     /* X.509 Certificate */
00625 
00626     /* make sure we have a cert */
00627     if ( !sftk_hasAttribute(object,CKA_VALUE) ) {
00628        return CKR_TEMPLATE_INCOMPLETE;
00629     }
00630 
00631     /* in PKCS #11, Subject is a required field */
00632     if ( !sftk_hasAttribute(object,CKA_SUBJECT) ) {
00633        return CKR_TEMPLATE_INCOMPLETE;
00634     }
00635 
00636     /* in PKCS #11, Issuer is a required field */
00637     if ( !sftk_hasAttribute(object,CKA_ISSUER) ) {
00638        return CKR_TEMPLATE_INCOMPLETE;
00639     }
00640 
00641     /* in PKCS #11, Serial is a required field */
00642     if ( !sftk_hasAttribute(object,CKA_SERIAL_NUMBER) ) {
00643        return CKR_TEMPLATE_INCOMPLETE;
00644     }
00645 
00646     /* add it to the object */
00647     object->objectInfo = NULL;
00648     object->infoFree = (SFTKFree) NULL;
00649     
00650     /* now just verify the required date fields */
00651     crv = sftk_defaultAttribute(object, CKA_ID, NULL, 0);
00652     if (crv != CKR_OK) { return crv; }
00653 
00654     if (sftk_isTrue(object,CKA_TOKEN)) {
00655        SFTKSlot *slot = session->slot;
00656        SECItem derCert;
00657        NSSLOWCERTCertificate *cert;
00658        NSSLOWCERTCertTrust *trust = NULL;
00659        NSSLOWCERTCertTrust userTrust = 
00660               { CERTDB_USER, CERTDB_USER, CERTDB_USER };
00661        NSSLOWCERTCertTrust defTrust = 
00662               { CERTDB_TRUSTED_UNKNOWN, 
00663                      CERTDB_TRUSTED_UNKNOWN, CERTDB_TRUSTED_UNKNOWN };
00664        char *label = NULL;
00665        char *email = NULL;
00666        SECStatus rv;
00667        PRBool inDB = PR_TRUE;
00668        NSSLOWCERTCertDBHandle *certHandle = sftk_getCertDB(slot);
00669        NSSLOWKEYDBHandle *keyHandle = NULL;
00670 
00671        if (certHandle == NULL) {
00672            return CKR_TOKEN_WRITE_PROTECTED;
00673        }
00674 
00675        /* get the der cert */ 
00676        attribute = sftk_FindAttribute(object,CKA_VALUE);
00677        PORT_Assert(attribute);
00678 
00679        derCert.type = 0;
00680        derCert.data = (unsigned char *)attribute->attrib.pValue;
00681        derCert.len = attribute->attrib.ulValueLen ;
00682 
00683        label = sftk_getString(object,CKA_LABEL);
00684 
00685        cert =  nsslowcert_FindCertByDERCert(certHandle, &derCert);
00686        if (cert == NULL) {
00687            cert = nsslowcert_DecodeDERCertificate(&derCert, label);
00688            inDB = PR_FALSE;
00689        }
00690        if (cert == NULL) {
00691            if (label) PORT_Free(label);
00692            sftk_FreeAttribute(attribute);
00693            sftk_freeCertDB(certHandle);
00694            return CKR_ATTRIBUTE_VALUE_INVALID;
00695        }
00696 
00697        keyHandle = sftk_getKeyDB(slot);
00698        if (keyHandle) {
00699            if (nsslowkey_KeyForCertExists(keyHandle,cert)) {
00700               trust = &userTrust;
00701            }
00702            sftk_freeKeyDB(keyHandle);
00703        }
00704 
00705        if (!inDB) {
00706            if (!trust) trust = &defTrust;
00707            rv = nsslowcert_AddPermCert(certHandle, cert, label, trust);
00708        } else {
00709            rv = trust ? nsslowcert_ChangeCertTrust(certHandle,cert,trust) :
00710                             SECSuccess;
00711        }
00712 
00713        if (label) PORT_Free(label);
00714        sftk_FreeAttribute(attribute);
00715 
00716        if (rv != SECSuccess) {
00717            sftk_freeCertDB(certHandle);
00718            nsslowcert_DestroyCertificate(cert);
00719            return CKR_DEVICE_ERROR;
00720        }
00721 
00722        /*
00723         * Add a NULL S/MIME profile if necessary.
00724         */
00725        email = sftk_getString(object,CKA_NETSCAPE_EMAIL);
00726        if (email) {
00727            certDBEntrySMime *entry;
00728 
00729            entry = nsslowcert_ReadDBSMimeEntry(certHandle,email);
00730            if (!entry) {
00731               nsslowcert_SaveSMimeProfile(certHandle, email, 
00732                                           &cert->derSubject, NULL, NULL);
00733            } else {
00734                nsslowcert_DestroyDBEntry((certDBEntry *)entry);
00735            }
00736            PORT_Free(email);
00737        }
00738        sftk_freeCertDB(certHandle);
00739        object->handle=sftk_mkHandle(slot,&cert->certKey,SFTK_TOKEN_TYPE_CERT);
00740        nsslowcert_DestroyCertificate(cert);
00741     }
00742 
00743     return CKR_OK;
00744 }
00745 
00746 unsigned int
00747 sftk_MapTrust(CK_TRUST trust, PRBool clientAuth)
00748 {
00749     unsigned int trustCA = clientAuth ? CERTDB_TRUSTED_CLIENT_CA :
00750                                                  CERTDB_TRUSTED_CA;
00751     switch (trust) {
00752     case CKT_NETSCAPE_TRUSTED:
00753        return CERTDB_VALID_PEER|CERTDB_TRUSTED;
00754     case CKT_NETSCAPE_TRUSTED_DELEGATOR:
00755        return CERTDB_VALID_CA|trustCA;
00756     case CKT_NETSCAPE_UNTRUSTED:
00757        return CERTDB_NOT_TRUSTED;
00758     case CKT_NETSCAPE_MUST_VERIFY:
00759        return 0;
00760     case CKT_NETSCAPE_VALID: /* implies must verify */
00761        return CERTDB_VALID_PEER;
00762     case CKT_NETSCAPE_VALID_DELEGATOR: /* implies must verify */
00763        return CERTDB_VALID_CA;
00764     default:
00765        break;
00766     }
00767     return CERTDB_TRUSTED_UNKNOWN;
00768 }
00769     
00770        
00771 /*
00772  * check the consistancy and initialize a Trust Object 
00773  */
00774 static CK_RV
00775 sftk_handleTrustObject(SFTKSession *session,SFTKObject *object)
00776 {
00777     NSSLOWCERTIssuerAndSN issuerSN;
00778 
00779     /* we can't store any certs private */
00780     if (sftk_isTrue(object,CKA_PRIVATE)) {
00781        return CKR_ATTRIBUTE_VALUE_INVALID;
00782     }
00783 
00784     /* certificates must have a type */
00785     if ( !sftk_hasAttribute(object,CKA_ISSUER) ) {
00786        return CKR_TEMPLATE_INCOMPLETE;
00787     }
00788     if ( !sftk_hasAttribute(object,CKA_SERIAL_NUMBER) ) {
00789        return CKR_TEMPLATE_INCOMPLETE;
00790     }
00791     if ( !sftk_hasAttribute(object,CKA_CERT_SHA1_HASH) ) {
00792        return CKR_TEMPLATE_INCOMPLETE;
00793     }
00794     if ( !sftk_hasAttribute(object,CKA_CERT_MD5_HASH) ) {
00795        return CKR_TEMPLATE_INCOMPLETE;
00796     }
00797 
00798     if (sftk_isTrue(object,CKA_TOKEN)) {
00799        SFTKSlot *slot = session->slot;
00800        SFTKAttribute *issuer = NULL;
00801        SFTKAttribute *serial = NULL;
00802        NSSLOWCERTCertificate *cert = NULL;
00803        SFTKAttribute *trust;
00804         CK_TRUST sslTrust = CKT_NETSCAPE_TRUST_UNKNOWN;
00805         CK_TRUST clientTrust = CKT_NETSCAPE_TRUST_UNKNOWN;
00806         CK_TRUST emailTrust = CKT_NETSCAPE_TRUST_UNKNOWN;
00807         CK_TRUST signTrust = CKT_NETSCAPE_TRUST_UNKNOWN;
00808        CK_BBOOL stepUp;
00809        NSSLOWCERTCertTrust dbTrust = { 0 };
00810        SECStatus rv;
00811        NSSLOWCERTCertDBHandle *certHandle = sftk_getCertDB(slot);
00812 
00813        if (certHandle == NULL) {
00814            return CKR_TOKEN_WRITE_PROTECTED;
00815        }
00816 
00817        issuer = sftk_FindAttribute(object,CKA_ISSUER);
00818        PORT_Assert(issuer);
00819        issuerSN.derIssuer.data = (unsigned char *)issuer->attrib.pValue;
00820        issuerSN.derIssuer.len = issuer->attrib.ulValueLen ;
00821 
00822        serial = sftk_FindAttribute(object,CKA_SERIAL_NUMBER);
00823        PORT_Assert(serial);
00824        issuerSN.serialNumber.data = (unsigned char *)serial->attrib.pValue;
00825        issuerSN.serialNumber.len = serial->attrib.ulValueLen ;
00826 
00827        cert = nsslowcert_FindCertByIssuerAndSN(certHandle,&issuerSN);
00828        sftk_FreeAttribute(serial);
00829        sftk_FreeAttribute(issuer);
00830 
00831        if (cert == NULL) {
00832            sftk_freeCertDB(certHandle);
00833            return CKR_ATTRIBUTE_VALUE_INVALID;
00834        }
00835        
00836        trust = sftk_FindAttribute(object,CKA_TRUST_SERVER_AUTH);
00837        if (trust) {
00838            if (trust->attrib.ulValueLen == sizeof(CK_TRUST)) {
00839               PORT_Memcpy(&sslTrust,trust->attrib.pValue, sizeof(sslTrust));
00840            }
00841            sftk_FreeAttribute(trust);
00842        }
00843        trust = sftk_FindAttribute(object,CKA_TRUST_CLIENT_AUTH);
00844        if (trust) {
00845            if (trust->attrib.ulValueLen == sizeof(CK_TRUST)) {
00846               PORT_Memcpy(&clientTrust,trust->attrib.pValue,
00847                                                   sizeof(clientTrust));
00848            }
00849            sftk_FreeAttribute(trust);
00850        }
00851        trust = sftk_FindAttribute(object,CKA_TRUST_EMAIL_PROTECTION);
00852        if (trust) {
00853            if (trust->attrib.ulValueLen == sizeof(CK_TRUST)) {
00854               PORT_Memcpy(&emailTrust,trust->attrib.pValue,
00855                                                  sizeof(emailTrust));
00856            }
00857            sftk_FreeAttribute(trust);
00858        }
00859        trust = sftk_FindAttribute(object,CKA_TRUST_CODE_SIGNING);
00860        if (trust) {
00861            if (trust->attrib.ulValueLen == sizeof(CK_TRUST)) {
00862               PORT_Memcpy(&signTrust,trust->attrib.pValue,
00863                                                  sizeof(signTrust));
00864            }
00865            sftk_FreeAttribute(trust);
00866        }
00867        stepUp = CK_FALSE;
00868        trust = sftk_FindAttribute(object,CKA_TRUST_STEP_UP_APPROVED);
00869        if (trust) {
00870            if (trust->attrib.ulValueLen == sizeof(CK_BBOOL)) {
00871               stepUp = *(CK_BBOOL*)trust->attrib.pValue;
00872            }
00873            sftk_FreeAttribute(trust);
00874        }
00875 
00876        /* preserve certain old fields */
00877        if (cert->trust) {
00878            dbTrust.sslFlags =
00879                        cert->trust->sslFlags & CERTDB_PRESERVE_TRUST_BITS;
00880            dbTrust.emailFlags=
00881                      cert->trust->emailFlags & CERTDB_PRESERVE_TRUST_BITS;
00882            dbTrust.objectSigningFlags = 
00883               cert->trust->objectSigningFlags & CERTDB_PRESERVE_TRUST_BITS;
00884        }
00885 
00886        dbTrust.sslFlags |= sftk_MapTrust(sslTrust,PR_FALSE);
00887        dbTrust.sslFlags |= sftk_MapTrust(clientTrust,PR_TRUE);
00888        dbTrust.emailFlags |= sftk_MapTrust(emailTrust,PR_FALSE);
00889        dbTrust.objectSigningFlags |= sftk_MapTrust(signTrust,PR_FALSE);
00890        if (stepUp) {
00891            dbTrust.sslFlags |= CERTDB_GOVT_APPROVED_CA;
00892        }
00893 
00894        rv = nsslowcert_ChangeCertTrust(certHandle,cert,&dbTrust);
00895        object->handle=sftk_mkHandle(slot,&cert->certKey,SFTK_TOKEN_TYPE_TRUST);
00896        nsslowcert_DestroyCertificate(cert);
00897        sftk_freeCertDB(certHandle);
00898        if (rv != SECSuccess) {
00899           return CKR_DEVICE_ERROR;
00900        }
00901     }
00902 
00903     return CKR_OK;
00904 }
00905 
00906 /*
00907  * check the consistancy and initialize a Trust Object 
00908  */
00909 static CK_RV
00910 sftk_handleSMimeObject(SFTKSession *session,SFTKObject *object)
00911 {
00912 
00913     /* we can't store any certs private */
00914     if (sftk_isTrue(object,CKA_PRIVATE)) {
00915        return CKR_ATTRIBUTE_VALUE_INVALID;
00916     }
00917 
00918     /* certificates must have a type */
00919     if ( !sftk_hasAttribute(object,CKA_SUBJECT) ) {
00920        return CKR_TEMPLATE_INCOMPLETE;
00921     }
00922     if ( !sftk_hasAttribute(object,CKA_NETSCAPE_EMAIL) ) {
00923        return CKR_TEMPLATE_INCOMPLETE;
00924     }
00925 
00926     if (sftk_isTrue(object,CKA_TOKEN)) {
00927        SFTKSlot *slot = session->slot;
00928        SECItem derSubj,rawProfile,rawTime,emailKey;
00929        SECItem *pRawProfile = NULL;
00930        SECItem *pRawTime = NULL;
00931        char *email = NULL;
00932        SFTKAttribute *subject,*profile,*time;
00933        SECStatus rv;
00934        NSSLOWCERTCertDBHandle *certHandle;
00935 
00936        PORT_Assert(slot);
00937        certHandle = sftk_getCertDB(slot);
00938 
00939        if (certHandle == NULL) {
00940            return CKR_TOKEN_WRITE_PROTECTED;
00941        }
00942 
00943        /* lookup SUBJECT */
00944        subject = sftk_FindAttribute(object,CKA_SUBJECT);
00945        PORT_Assert(subject);
00946        derSubj.data = (unsigned char *)subject->attrib.pValue;
00947        derSubj.len = subject->attrib.ulValueLen ;
00948        derSubj.type = 0;
00949 
00950        /* lookup VALUE */
00951        profile = sftk_FindAttribute(object,CKA_VALUE);
00952        if (profile) {
00953            rawProfile.data = (unsigned char *)profile->attrib.pValue;
00954            rawProfile.len = profile->attrib.ulValueLen ;
00955            rawProfile.type = siBuffer;
00956            pRawProfile = &rawProfile;
00957        }
00958 
00959        /* lookup Time */
00960        time = sftk_FindAttribute(object,CKA_NETSCAPE_SMIME_TIMESTAMP);
00961        if (time) {
00962            rawTime.data = (unsigned char *)time->attrib.pValue;
00963            rawTime.len = time->attrib.ulValueLen ;
00964            rawTime.type = siBuffer;
00965            pRawTime = &rawTime;
00966        }
00967 
00968 
00969        email = sftk_getString(object,CKA_NETSCAPE_EMAIL);
00970 
00971        /* Store CRL by SUBJECT */
00972        rv = nsslowcert_SaveSMimeProfile(certHandle, email, &derSubj, 
00973                             pRawProfile,pRawTime);
00974        sftk_freeCertDB(certHandle);
00975        sftk_FreeAttribute(subject);
00976        if (profile) sftk_FreeAttribute(profile);
00977        if (time) sftk_FreeAttribute(time);
00978        if (rv != SECSuccess) {
00979            PORT_Free(email);
00980            return CKR_DEVICE_ERROR;
00981        }
00982        emailKey.data = (unsigned char *)email;
00983        emailKey.len = PORT_Strlen(email)+1;
00984 
00985        object->handle = sftk_mkHandle(slot, &emailKey, SFTK_TOKEN_TYPE_SMIME);
00986        PORT_Free(email);
00987     }
00988 
00989     return CKR_OK;
00990 }
00991 
00992 /*
00993  * check the consistancy and initialize a Trust Object 
00994  */
00995 static CK_RV
00996 sftk_handleCrlObject(SFTKSession *session,SFTKObject *object)
00997 {
00998 
00999     /* we can't store any certs private */
01000     if (sftk_isTrue(object,CKA_PRIVATE)) {
01001        return CKR_ATTRIBUTE_VALUE_INVALID;
01002     }
01003 
01004     /* certificates must have a type */
01005     if ( !sftk_hasAttribute(object,CKA_SUBJECT) ) {
01006        return CKR_TEMPLATE_INCOMPLETE;
01007     }
01008     if ( !sftk_hasAttribute(object,CKA_VALUE) ) {
01009        return CKR_TEMPLATE_INCOMPLETE;
01010     }
01011 
01012     if (sftk_isTrue(object,CKA_TOKEN)) {
01013        SFTKSlot *slot = session->slot;
01014        PRBool isKRL = PR_FALSE;
01015        SECItem derSubj,derCrl;
01016        char *url = NULL;
01017        SFTKAttribute *subject,*crl;
01018        SECStatus rv;
01019        NSSLOWCERTCertDBHandle *certHandle;
01020 
01021        PORT_Assert(slot);
01022        certHandle = sftk_getCertDB(slot);
01023 
01024        if (certHandle == NULL) {
01025            return CKR_TOKEN_WRITE_PROTECTED;
01026        }
01027 
01028        /* lookup SUBJECT */
01029        subject = sftk_FindAttribute(object,CKA_SUBJECT);
01030        PORT_Assert(subject);
01031        derSubj.data = (unsigned char *)subject->attrib.pValue;
01032        derSubj.len = subject->attrib.ulValueLen ;
01033 
01034        /* lookup VALUE */
01035        crl = sftk_FindAttribute(object,CKA_VALUE);
01036        PORT_Assert(crl);
01037        derCrl.data = (unsigned char *)crl->attrib.pValue;
01038        derCrl.len = crl->attrib.ulValueLen ;
01039 
01040 
01041        url = sftk_getString(object,CKA_NETSCAPE_URL);
01042        isKRL = sftk_isTrue(object,CKA_NETSCAPE_KRL);
01043 
01044        /* Store CRL by SUBJECT */
01045        rv = nsslowcert_AddCrl(certHandle, &derCrl, &derSubj, url, isKRL);
01046        sftk_freeCertDB(certHandle);
01047 
01048        if (url) {
01049            PORT_Free(url);
01050        }
01051        sftk_FreeAttribute(crl);
01052        if (rv != SECSuccess) {
01053            sftk_FreeAttribute(subject);
01054            return CKR_DEVICE_ERROR;
01055        }
01056 
01057        /* if we overwrote the existing CRL, poison the handle entry so we get
01058         * a new object handle */
01059        (void) sftk_poisonHandle(slot, &derSubj,
01060                      isKRL ? SFTK_TOKEN_KRL_HANDLE : SFTK_TOKEN_TYPE_CRL);
01061        object->handle = sftk_mkHandle(slot, &derSubj,
01062                      isKRL ? SFTK_TOKEN_KRL_HANDLE : SFTK_TOKEN_TYPE_CRL);
01063        sftk_FreeAttribute(subject);
01064     }
01065 
01066     return CKR_OK;
01067 }
01068 
01069 /*
01070  * check the consistancy and initialize a Public Key Object 
01071  */
01072 static CK_RV
01073 sftk_handlePublicKeyObject(SFTKSession *session, SFTKObject *object,
01074                                                   CK_KEY_TYPE key_type)
01075 {
01076     CK_BBOOL encrypt = CK_TRUE;
01077     CK_BBOOL recover = CK_TRUE;
01078     CK_BBOOL wrap = CK_TRUE;
01079     CK_BBOOL derive = CK_FALSE;
01080     CK_BBOOL verify = CK_TRUE;
01081     CK_ATTRIBUTE_TYPE pubKeyAttr = CKA_VALUE;
01082     CK_RV crv;
01083 
01084     switch (key_type) {
01085     case CKK_RSA:
01086        crv = sftk_ConstrainAttribute(object, CKA_MODULUS,
01087                                            RSA_MIN_MODULUS_BITS, 0, 0);
01088        if (crv != CKR_OK) {
01089            return crv;
01090        }
01091        crv = sftk_ConstrainAttribute(object, CKA_PUBLIC_EXPONENT, 2, 0, 0);
01092        if (crv != CKR_OK) {
01093            return crv;
01094        }
01095        pubKeyAttr = CKA_MODULUS;
01096        break;
01097     case CKK_DSA:
01098        crv = sftk_ConstrainAttribute(object, CKA_SUBPRIME, 
01099                                           DSA_Q_BITS, DSA_Q_BITS, 0);
01100        if (crv != CKR_OK) {
01101            return crv;
01102        }
01103        crv = sftk_ConstrainAttribute(object, CKA_PRIME, 
01104                                    DSA_MIN_P_BITS, DSA_MAX_P_BITS, 64);
01105        if (crv != CKR_OK) {
01106            return crv;
01107        }
01108        crv = sftk_ConstrainAttribute(object, CKA_BASE, 1, DSA_MAX_P_BITS, 0);
01109        if (crv != CKR_OK) {
01110            return crv;
01111        }
01112        crv = sftk_ConstrainAttribute(object, CKA_VALUE, 1, DSA_MAX_P_BITS, 0);
01113        if (crv != CKR_OK) {
01114            return crv;
01115        }
01116        encrypt = CK_FALSE;
01117        recover = CK_FALSE;
01118        wrap = CK_FALSE;
01119        break;
01120     case CKK_DH:
01121        crv = sftk_ConstrainAttribute(object, CKA_PRIME, 
01122                                    DH_MIN_P_BITS, DH_MAX_P_BITS, 0);
01123        if (crv != CKR_OK) {
01124            return crv;
01125        }
01126        crv = sftk_ConstrainAttribute(object, CKA_BASE, 1, DH_MAX_P_BITS, 0);
01127        if (crv != CKR_OK) {
01128            return crv;
01129        }
01130        crv = sftk_ConstrainAttribute(object, CKA_VALUE, 1, DH_MAX_P_BITS, 0);
01131        if (crv != CKR_OK) {
01132            return crv;
01133        }
01134        verify = CK_FALSE;
01135        derive = CK_TRUE;
01136        encrypt = CK_FALSE;
01137        recover = CK_FALSE;
01138        wrap = CK_FALSE;
01139        break;
01140 #ifdef NSS_ENABLE_ECC
01141     case CKK_EC:
01142        if ( !sftk_hasAttribute(object, CKA_EC_PARAMS)) {
01143            return CKR_TEMPLATE_INCOMPLETE;
01144        }
01145        if ( !sftk_hasAttribute(object, CKA_EC_POINT)) {
01146            return CKR_TEMPLATE_INCOMPLETE;
01147        }
01148        pubKeyAttr = CKA_EC_POINT;
01149        derive = CK_TRUE;    /* for ECDH */
01150        verify = CK_TRUE;    /* for ECDSA */
01151        encrypt = CK_FALSE;
01152        recover = CK_FALSE;
01153        wrap = CK_FALSE;
01154        break;
01155 #endif /* NSS_ENABLE_ECC */
01156     default:
01157        return CKR_ATTRIBUTE_VALUE_INVALID;
01158     }
01159 
01160     /* make sure the required fields exist */
01161     crv = sftk_defaultAttribute(object,CKA_SUBJECT,NULL,0);
01162     if (crv != CKR_OK)  return crv; 
01163     crv = sftk_defaultAttribute(object,CKA_ENCRYPT,&encrypt,sizeof(CK_BBOOL));
01164     if (crv != CKR_OK)  return crv; 
01165     crv = sftk_defaultAttribute(object,CKA_VERIFY,&verify,sizeof(CK_BBOOL));
01166     if (crv != CKR_OK)  return crv; 
01167     crv = sftk_defaultAttribute(object,CKA_VERIFY_RECOVER,
01168                                           &recover,sizeof(CK_BBOOL));
01169     if (crv != CKR_OK)  return crv; 
01170     crv = sftk_defaultAttribute(object,CKA_WRAP,&wrap,sizeof(CK_BBOOL));
01171     if (crv != CKR_OK)  return crv; 
01172     crv = sftk_defaultAttribute(object,CKA_DERIVE,&derive,sizeof(CK_BBOOL));
01173     if (crv != CKR_OK)  return crv; 
01174 
01175     object->objectInfo = sftk_GetPubKey(object,key_type, &crv);
01176     if (object->objectInfo == NULL) {
01177        return crv;
01178     }
01179     object->infoFree = (SFTKFree) nsslowkey_DestroyPublicKey;
01180 
01181     if (sftk_isTrue(object,CKA_TOKEN)) {
01182        SFTKSlot *slot = session->slot;
01183        NSSLOWKEYPrivateKey *priv;
01184        SECItem pubKey;
01185        NSSLOWKEYDBHandle *keyHandle = NULL;
01186 
01187        crv = sftk_Attribute2SSecItem(NULL,&pubKey,object,pubKeyAttr);
01188        if (crv != CKR_OK) return crv;
01189 
01190        PORT_Assert(pubKey.data);
01191        keyHandle = sftk_getKeyDB(slot);
01192        if (keyHandle == NULL) {
01193            PORT_Free(pubKey.data);
01194            return CKR_TOKEN_WRITE_PROTECTED;
01195        }
01196        if (keyHandle->version != 3) {
01197            unsigned char buf[SHA1_LENGTH];
01198            SHA1_HashBuf(buf,pubKey.data,pubKey.len);
01199            PORT_Memcpy(pubKey.data,buf,sizeof(buf));
01200            pubKey.len = sizeof(buf);
01201        }
01202        /* make sure the associated private key already exists */
01203        /* only works if we are logged in */
01204        priv = nsslowkey_FindKeyByPublicKey(keyHandle, &pubKey, slot->password);
01205        sftk_freeKeyDB(keyHandle);
01206        if (priv == NULL) {
01207            PORT_Free(pubKey.data);
01208            return crv;
01209        }
01210        nsslowkey_DestroyPrivateKey(priv);
01211 
01212        object->handle = sftk_mkHandle(slot, &pubKey, SFTK_TOKEN_TYPE_PUB);
01213        PORT_Free(pubKey.data);
01214     }
01215 
01216     return CKR_OK;
01217 }
01218 
01219 static NSSLOWKEYPrivateKey * 
01220 sftk_mkPrivKey(SFTKObject *object,CK_KEY_TYPE key, CK_RV *rvp);
01221 
01222 /*
01223  * check the consistancy and initialize a Private Key Object 
01224  */
01225 static CK_RV
01226 sftk_handlePrivateKeyObject(SFTKSession *session,SFTKObject *object,CK_KEY_TYPE key_type)
01227 {
01228     CK_BBOOL cktrue = CK_TRUE;
01229     CK_BBOOL encrypt = CK_TRUE;
01230     CK_BBOOL sign = CK_FALSE;
01231     CK_BBOOL recover = CK_TRUE;
01232     CK_BBOOL wrap = CK_TRUE;
01233     CK_BBOOL derive = CK_FALSE;
01234     CK_BBOOL ckfalse = CK_FALSE;
01235     SECItem mod;
01236     CK_RV crv;
01237 
01238     switch (key_type) {
01239     case CKK_RSA:
01240        if ( !sftk_hasAttribute(object, CKA_MODULUS)) {
01241            return CKR_TEMPLATE_INCOMPLETE;
01242        }
01243        if ( !sftk_hasAttribute(object, CKA_PUBLIC_EXPONENT)) {
01244            return CKR_TEMPLATE_INCOMPLETE;
01245        }
01246        if ( !sftk_hasAttribute(object, CKA_PRIVATE_EXPONENT)) {
01247            return CKR_TEMPLATE_INCOMPLETE;
01248        }
01249        if ( !sftk_hasAttribute(object, CKA_PRIME_1)) {
01250            return CKR_TEMPLATE_INCOMPLETE;
01251        }
01252        if ( !sftk_hasAttribute(object, CKA_PRIME_2)) {
01253            return CKR_TEMPLATE_INCOMPLETE;
01254        }
01255        if ( !sftk_hasAttribute(object, CKA_EXPONENT_1)) {
01256            return CKR_TEMPLATE_INCOMPLETE;
01257        }
01258        if ( !sftk_hasAttribute(object, CKA_EXPONENT_2)) {
01259            return CKR_TEMPLATE_INCOMPLETE;
01260        }
01261        if ( !sftk_hasAttribute(object, CKA_COEFFICIENT)) {
01262            return CKR_TEMPLATE_INCOMPLETE;
01263        }
01264        /* make sure Netscape DB attribute is set correctly */
01265        crv = sftk_Attribute2SSecItem(NULL, &mod, object, CKA_MODULUS);
01266        if (crv != CKR_OK) return crv;
01267        crv = sftk_forceAttribute(object, CKA_NETSCAPE_DB, 
01268                                           sftk_item_expand(&mod));
01269        if (mod.data) PORT_Free(mod.data);
01270        if (crv != CKR_OK) return crv;
01271 
01272        sign = CK_TRUE;
01273        break;
01274     case CKK_DSA:
01275        if ( !sftk_hasAttribute(object, CKA_SUBPRIME)) {
01276            return CKR_TEMPLATE_INCOMPLETE;
01277        }
01278        if (sftk_isTrue(object,CKA_TOKEN) &&
01279               !sftk_hasAttribute(object, CKA_NETSCAPE_DB)) {
01280            return CKR_TEMPLATE_INCOMPLETE;
01281        }
01282        sign = CK_TRUE;
01283        /* fall through */
01284     case CKK_DH:
01285        if ( !sftk_hasAttribute(object, CKA_PRIME)) {
01286            return CKR_TEMPLATE_INCOMPLETE;
01287        }
01288        if ( !sftk_hasAttribute(object, CKA_BASE)) {
01289            return CKR_TEMPLATE_INCOMPLETE;
01290        }
01291        if ( !sftk_hasAttribute(object, CKA_VALUE)) {
01292            return CKR_TEMPLATE_INCOMPLETE;
01293        }
01294        encrypt = CK_FALSE;
01295        recover = CK_FALSE;
01296        wrap = CK_FALSE;
01297        break;
01298 #ifdef NSS_ENABLE_ECC
01299     case CKK_EC:
01300        if ( !sftk_hasAttribute(object, CKA_EC_PARAMS)) {
01301            return CKR_TEMPLATE_INCOMPLETE;
01302        }
01303        if ( !sftk_hasAttribute(object, CKA_VALUE)) {
01304            return CKR_TEMPLATE_INCOMPLETE;
01305        }
01306        if (sftk_isTrue(object,CKA_TOKEN) &&
01307               !sftk_hasAttribute(object, CKA_NETSCAPE_DB)) {
01308            return CKR_TEMPLATE_INCOMPLETE;
01309        }
01310        encrypt = CK_FALSE;
01311        sign = CK_TRUE;
01312        recover = CK_FALSE;
01313        wrap = CK_FALSE;
01314        derive = CK_TRUE;
01315        break;
01316 #endif /* NSS_ENABLE_ECC */
01317     default:
01318        return CKR_ATTRIBUTE_VALUE_INVALID;
01319     }
01320     crv = sftk_defaultAttribute(object,CKA_SUBJECT,NULL,0);
01321     if (crv != CKR_OK)  return crv; 
01322     crv = sftk_defaultAttribute(object,CKA_SENSITIVE,&cktrue,sizeof(CK_BBOOL));
01323     if (crv != CKR_OK)  return crv; 
01324     crv = sftk_defaultAttribute(object,CKA_EXTRACTABLE,&cktrue,sizeof(CK_BBOOL));
01325     if (crv != CKR_OK)  return crv; 
01326     crv = sftk_defaultAttribute(object,CKA_DECRYPT,&encrypt,sizeof(CK_BBOOL));
01327     if (crv != CKR_OK)  return crv; 
01328     crv = sftk_defaultAttribute(object,CKA_SIGN,&sign,sizeof(CK_BBOOL));
01329     if (crv != CKR_OK)  return crv; 
01330     crv = sftk_defaultAttribute(object,CKA_SIGN_RECOVER,&recover,
01331                                                       sizeof(CK_BBOOL));
01332     if (crv != CKR_OK)  return crv; 
01333     crv = sftk_defaultAttribute(object,CKA_UNWRAP,&wrap,sizeof(CK_BBOOL));
01334     if (crv != CKR_OK)  return crv; 
01335     crv = sftk_defaultAttribute(object,CKA_DERIVE,&derive,sizeof(CK_BBOOL));
01336     if (crv != CKR_OK)  return crv; 
01337     /* the next two bits get modified only in the key gen and token cases */
01338     crv = sftk_forceAttribute(object,CKA_ALWAYS_SENSITIVE,
01339                                           &ckfalse,sizeof(CK_BBOOL));
01340     if (crv != CKR_OK)  return crv; 
01341     crv = sftk_forceAttribute(object,CKA_NEVER_EXTRACTABLE,
01342                                           &ckfalse,sizeof(CK_BBOOL));
01343     if (crv != CKR_OK)  return crv; 
01344 
01345     /* should we check the non-token RSA private keys? */
01346 
01347     if (sftk_isTrue(object,CKA_TOKEN)) {
01348        SFTKSlot *slot = session->slot;
01349        NSSLOWKEYPrivateKey *privKey;
01350        char *label;
01351        SECStatus rv = SECSuccess;
01352        CK_RV crv = CKR_DEVICE_ERROR;
01353        SECItem pubKey;
01354        NSSLOWKEYDBHandle *keyHandle = sftk_getKeyDB(slot);
01355 
01356        if (keyHandle == NULL) {
01357            return CKR_TOKEN_WRITE_PROTECTED;
01358        }
01359 
01360        privKey=sftk_mkPrivKey(object,key_type,&crv);
01361        if (privKey == NULL) return crv;
01362        label = sftk_getString(object,CKA_LABEL);
01363 
01364        crv = sftk_Attribute2SSecItem(NULL,&pubKey,object,CKA_NETSCAPE_DB);
01365        if (crv != CKR_OK) {
01366            crv = CKR_TEMPLATE_INCOMPLETE;
01367            rv = SECFailure;
01368            goto fail;
01369        }
01370        if (keyHandle->version != 3) {
01371            unsigned char buf[SHA1_LENGTH];
01372            SHA1_HashBuf(buf,pubKey.data,pubKey.len);
01373            PORT_Memcpy(pubKey.data,buf,sizeof(buf));
01374            pubKey.len = sizeof(buf);
01375        }
01376 
01377         if (key_type == CKK_RSA) {
01378            rv = RSA_PrivateKeyCheck(&privKey->u.rsa);
01379            if (rv == SECFailure) {
01380               goto fail;
01381            }
01382        }
01383        rv = nsslowkey_StoreKeyByPublicKey(keyHandle, privKey, &pubKey, 
01384                                       label, slot->password);
01385 
01386 fail:
01387        sftk_freeKeyDB(keyHandle);
01388        if (label) PORT_Free(label);
01389        object->handle = sftk_mkHandle(slot,&pubKey,SFTK_TOKEN_TYPE_PRIV);
01390        if (pubKey.data) PORT_Free(pubKey.data);
01391        nsslowkey_DestroyPrivateKey(privKey);
01392        if (rv != SECSuccess) return crv;
01393     } else {
01394        object->objectInfo = sftk_mkPrivKey(object,key_type,&crv);
01395        if (object->objectInfo == NULL) return crv;
01396        object->infoFree = (SFTKFree) nsslowkey_DestroyPrivateKey;
01397        /* now NULL out the sensitive attributes */
01398        /* remove nulled out attributes for session objects. these only
01399         * applied to rsa private keys anyway (other private keys did not
01400         * get their attributes NULL'ed out */
01401     }
01402     return CKR_OK;
01403 }
01404 
01405 /* forward declare the DES formating function for handleSecretKey */
01406 void sftk_FormatDESKey(unsigned char *key, int length);
01407 static NSSLOWKEYPrivateKey *sftk_mkSecretKeyRep(SFTKObject *object);
01408 
01409 /* Validate secret key data, and set defaults */
01410 static CK_RV
01411 validateSecretKey(SFTKSession *session, SFTKObject *object, 
01412                                    CK_KEY_TYPE key_type, PRBool isFIPS)
01413 {
01414     CK_RV crv;
01415     CK_BBOOL cktrue = CK_TRUE;
01416     CK_BBOOL ckfalse = CK_FALSE;
01417     SFTKAttribute *attribute = NULL;
01418     unsigned long requiredLen;
01419 
01420     crv = sftk_defaultAttribute(object,CKA_SENSITIVE,
01421                             isFIPS?&cktrue:&ckfalse,sizeof(CK_BBOOL));
01422     if (crv != CKR_OK)  return crv; 
01423     crv = sftk_defaultAttribute(object,CKA_EXTRACTABLE,
01424                                           &cktrue,sizeof(CK_BBOOL));
01425     if (crv != CKR_OK)  return crv; 
01426     crv = sftk_defaultAttribute(object,CKA_ENCRYPT,&cktrue,sizeof(CK_BBOOL));
01427     if (crv != CKR_OK)  return crv; 
01428     crv = sftk_defaultAttribute(object,CKA_DECRYPT,&cktrue,sizeof(CK_BBOOL));
01429     if (crv != CKR_OK)  return crv; 
01430     crv = sftk_defaultAttribute(object,CKA_SIGN,&ckfalse,sizeof(CK_BBOOL));
01431     if (crv != CKR_OK)  return crv; 
01432     crv = sftk_defaultAttribute(object,CKA_VERIFY,&ckfalse,sizeof(CK_BBOOL));
01433     if (crv != CKR_OK)  return crv; 
01434     crv = sftk_defaultAttribute(object,CKA_WRAP,&cktrue,sizeof(CK_BBOOL));
01435     if (crv != CKR_OK)  return crv; 
01436     crv = sftk_defaultAttribute(object,CKA_UNWRAP,&cktrue,sizeof(CK_BBOOL));
01437     if (crv != CKR_OK)  return crv; 
01438 
01439     if ( !sftk_hasAttribute(object, CKA_VALUE)) {
01440        return CKR_TEMPLATE_INCOMPLETE;
01441     }
01442     /* the next two bits get modified only in the key gen and token cases */
01443     crv = sftk_forceAttribute(object,CKA_ALWAYS_SENSITIVE,
01444                                           &ckfalse,sizeof(CK_BBOOL));
01445     if (crv != CKR_OK)  return crv; 
01446     crv = sftk_forceAttribute(object,CKA_NEVER_EXTRACTABLE,
01447                                           &ckfalse,sizeof(CK_BBOOL));
01448     if (crv != CKR_OK)  return crv; 
01449 
01450     /* some types of keys have a value length */
01451     crv = CKR_OK;
01452     switch (key_type) {
01453     /* force CKA_VALUE_LEN to be set */
01454     case CKK_GENERIC_SECRET:
01455     case CKK_RC2:
01456     case CKK_RC4:
01457 #if NSS_SOFTOKEN_DOES_RC5
01458     case CKK_RC5:
01459 #endif
01460 #ifdef NSS_SOFTOKEN_DOES_CAST
01461     case CKK_CAST:
01462     case CKK_CAST3:
01463     case CKK_CAST5:
01464 #endif
01465 #if NSS_SOFTOKEN_DOES_IDEA
01466     case CKK_IDEA:
01467 #endif
01468        attribute = sftk_FindAttribute(object,CKA_VALUE);
01469        /* shouldn't happen */
01470        if (attribute == NULL) return CKR_TEMPLATE_INCOMPLETE;
01471        crv = sftk_forceAttribute(object, CKA_VALUE_LEN, 
01472                      &attribute->attrib.ulValueLen, sizeof(CK_ULONG));
01473        sftk_FreeAttribute(attribute);
01474        break;
01475     /* force the value to have the correct parity */
01476     case CKK_DES:
01477     case CKK_DES2:
01478     case CKK_DES3:
01479     case CKK_CDMF:
01480        attribute = sftk_FindAttribute(object,CKA_VALUE);
01481        /* shouldn't happen */
01482        if (attribute == NULL) 
01483            return CKR_TEMPLATE_INCOMPLETE;
01484        requiredLen = sftk_MapKeySize(key_type);
01485        if (attribute->attrib.ulValueLen != requiredLen) {
01486            sftk_FreeAttribute(attribute);
01487            return CKR_KEY_SIZE_RANGE;
01488        }
01489        sftk_FormatDESKey((unsigned char*)attribute->attrib.pValue,
01490                                            attribute->attrib.ulValueLen);
01491        sftk_FreeAttribute(attribute);
01492        break;
01493     default:
01494        break;
01495     }
01496 
01497     return crv;
01498 }
01499 
01500 #define SFTK_KEY_MAX_RETRIES 10 /* don't hang if we are having problems with the rng */
01501 #define SFTK_KEY_ID_SIZE 18 /* don't use either SHA1 or MD5 sizes */
01502 /*
01503  * Secret keys must have a CKA_ID value to be stored in the database. This code
01504  * will generate one if there wasn't one already. 
01505  */
01506 static CK_RV
01507 sftk_GenerateSecretCKA_ID(NSSLOWKEYDBHandle *handle, SECItem *id, char *label)
01508 {
01509     unsigned int retries;
01510     SECStatus rv = SECSuccess;
01511     CK_RV crv = CKR_OK;
01512 
01513     id->data = NULL;
01514     if (label) {
01515        id->data = (unsigned char *)PORT_Strdup(label);
01516        if (id->data == NULL) {
01517            return CKR_HOST_MEMORY;
01518        }
01519        id->len = PORT_Strlen(label)+1;
01520        if (!nsslowkey_KeyForIDExists(handle,id)) { 
01521            return CKR_OK;
01522        }
01523        PORT_Free(id->data);
01524        id->data = NULL;
01525        id->len = 0;
01526     }
01527     id->data = (unsigned char *)PORT_Alloc(SFTK_KEY_ID_SIZE);
01528     if (id->data == NULL) {
01529        return CKR_HOST_MEMORY;
01530     }
01531     id->len = SFTK_KEY_ID_SIZE;
01532 
01533     retries = 0;
01534     do {
01535        rv = RNG_GenerateGlobalRandomBytes(id->data,id->len);
01536     } while (rv == SECSuccess && nsslowkey_KeyForIDExists(handle,id) && 
01537                             (++retries <= SFTK_KEY_MAX_RETRIES));
01538 
01539     if ((rv != SECSuccess) || (retries > SFTK_KEY_MAX_RETRIES)) {
01540        if (rv != SECSuccess) {
01541            sftk_fatalError = PR_TRUE;
01542        }
01543        crv = CKR_DEVICE_ERROR; /* random number generator is bad */
01544        PORT_Free(id->data);
01545        id->data = NULL;
01546        id->len = 0;
01547     }
01548     return crv;
01549 }
01550 
01551 /*
01552  * check the consistancy and initialize a Secret Key Object 
01553  */
01554 static CK_RV
01555 sftk_handleSecretKeyObject(SFTKSession *session,SFTKObject *object,
01556                                    CK_KEY_TYPE key_type, PRBool isFIPS)
01557 {
01558     CK_RV crv;
01559     NSSLOWKEYPrivateKey *privKey   = NULL;
01560     NSSLOWKEYDBHandle   *keyHandle = NULL;
01561     SECItem pubKey;
01562     char *label = NULL;
01563 
01564     pubKey.data = 0;
01565 
01566     /* First validate and set defaults */
01567     crv = validateSecretKey(session, object, key_type, isFIPS);
01568     if (crv != CKR_OK) goto loser;
01569 
01570     /* If the object is a TOKEN object, store in the database */
01571     if (sftk_isTrue(object,CKA_TOKEN)) {
01572        SFTKSlot *slot = session->slot;
01573        SECStatus rv = SECSuccess;
01574        keyHandle = sftk_getKeyDB(slot);
01575 
01576        if (keyHandle == NULL) {
01577            return CKR_TOKEN_WRITE_PROTECTED;
01578        }
01579 
01580        label = sftk_getString(object,CKA_LABEL);
01581 
01582        crv = sftk_Attribute2SecItem(NULL, &pubKey, object, CKA_ID);  
01583                                           /* Should this be ID? */
01584        if (crv != CKR_OK) goto loser;
01585 
01586        /* if we don't have an ID, generate one */
01587        if (pubKey.len == 0) {
01588            if (pubKey.data) { 
01589               PORT_Free(pubKey.data);
01590               pubKey.data = NULL;
01591            }
01592            crv = sftk_GenerateSecretCKA_ID(keyHandle, &pubKey, label);
01593            if (crv != CKR_OK) goto loser;
01594 
01595            crv = sftk_forceAttribute(object, CKA_ID, pubKey.data, pubKey.len);
01596            if (crv != CKR_OK) goto loser;
01597        }
01598 
01599        privKey = sftk_mkSecretKeyRep(object);
01600        if (privKey == NULL) {
01601            crv = CKR_HOST_MEMORY;
01602            goto loser;
01603        }
01604 
01605        rv = nsslowkey_StoreKeyByPublicKey(keyHandle,
01606                      privKey, &pubKey, label, slot->password);
01607        if (rv != SECSuccess) {
01608            crv = CKR_DEVICE_ERROR;
01609            goto loser;
01610        }
01611 
01612        object->handle = sftk_mkHandle(slot,&pubKey,SFTK_TOKEN_TYPE_KEY);
01613     }
01614 
01615 loser:
01616     if (keyHandle) sftk_freeKeyDB(keyHandle);
01617     if (label) PORT_Free(label);
01618     if (privKey) nsslowkey_DestroyPrivateKey(privKey);
01619     if (pubKey.data) PORT_Free(pubKey.data);
01620 
01621     return crv;
01622 }
01623 
01624 /*
01625  * check the consistancy and initialize a Key Object 
01626  */
01627 static CK_RV
01628 sftk_handleKeyObject(SFTKSession *session, SFTKObject *object)
01629 {
01630     SFTKAttribute *attribute;
01631     CK_KEY_TYPE key_type;
01632     CK_BBOOL cktrue = CK_TRUE;
01633     CK_BBOOL ckfalse = CK_FALSE;
01634     CK_RV crv;
01635 
01636     /* verify the required fields */
01637     if ( !sftk_hasAttribute(object,CKA_KEY_TYPE) ) {
01638        return CKR_TEMPLATE_INCOMPLETE;
01639     }
01640 
01641     /* now verify the common fields */
01642     crv = sftk_defaultAttribute(object,CKA_ID,NULL,0);
01643     if (crv != CKR_OK)  return crv; 
01644     crv = sftk_defaultAttribute(object,CKA_START_DATE,NULL,0);
01645     if (crv != CKR_OK)  return crv; 
01646     crv = sftk_defaultAttribute(object,CKA_END_DATE,NULL,0);
01647     if (crv != CKR_OK)  return crv; 
01648     crv = sftk_defaultAttribute(object,CKA_DERIVE,&cktrue,sizeof(CK_BBOOL));
01649     if (crv != CKR_OK)  return crv; 
01650     crv = sftk_defaultAttribute(object,CKA_LOCAL,&ckfalse,sizeof(CK_BBOOL));
01651     if (crv != CKR_OK)  return crv; 
01652 
01653     /* get the key type */
01654     attribute = sftk_FindAttribute(object,CKA_KEY_TYPE);
01655     if (!attribute) {
01656         return CKR_ATTRIBUTE_VALUE_INVALID;
01657     }
01658     key_type = *(CK_KEY_TYPE *)attribute->attrib.pValue;
01659     sftk_FreeAttribute(attribute);
01660 
01661     switch (object->objclass) {
01662     case CKO_PUBLIC_KEY:
01663        return sftk_handlePublicKeyObject(session,object,key_type);
01664     case CKO_PRIVATE_KEY:
01665        return sftk_handlePrivateKeyObject(session,object,key_type);
01666     case CKO_SECRET_KEY:
01667        /* make sure the required fields exist */
01668        return sftk_handleSecretKeyObject(session,object,key_type,
01669                           (PRBool)(session->slot->slotID == FIPS_SLOT_ID));
01670     default:
01671        break;
01672     }
01673     return CKR_ATTRIBUTE_VALUE_INVALID;
01674 }
01675 
01676 /*
01677  * check the consistancy and Verify a DSA Parameter Object 
01678  */
01679 static CK_RV
01680 sftk_handleDSAParameterObject(SFTKSession *session, SFTKObject *object)
01681 {
01682     SFTKAttribute *primeAttr = NULL;
01683     SFTKAttribute *subPrimeAttr = NULL;
01684     SFTKAttribute *baseAttr = NULL;
01685     SFTKAttribute *seedAttr = NULL;
01686     SFTKAttribute *hAttr = NULL;
01687     SFTKAttribute *attribute;
01688     CK_RV crv = CKR_TEMPLATE_INCOMPLETE;
01689     PQGParams params;
01690     PQGVerify vfy, *verify = NULL;
01691     SECStatus result,rv;
01692 
01693     primeAttr = sftk_FindAttribute(object,CKA_PRIME);
01694     if (primeAttr == NULL) goto loser;
01695     params.prime.data = primeAttr->attrib.pValue;
01696     params.prime.len = primeAttr->attrib.ulValueLen;
01697 
01698     subPrimeAttr = sftk_FindAttribute(object,CKA_SUBPRIME);
01699     if (subPrimeAttr == NULL) goto loser;
01700     params.subPrime.data = subPrimeAttr->attrib.pValue;
01701     params.subPrime.len = subPrimeAttr->attrib.ulValueLen;
01702 
01703     baseAttr = sftk_FindAttribute(object,CKA_BASE);
01704     if (baseAttr == NULL) goto loser;
01705     params.base.data = baseAttr->attrib.pValue;
01706     params.base.len = baseAttr->attrib.ulValueLen;
01707 
01708     attribute = sftk_FindAttribute(object, CKA_NETSCAPE_PQG_COUNTER);
01709     if (attribute != NULL) {
01710        vfy.counter = *(CK_ULONG *) attribute->attrib.pValue;
01711        sftk_FreeAttribute(attribute);
01712 
01713        seedAttr = sftk_FindAttribute(object, CKA_NETSCAPE_PQG_SEED);
01714        if (seedAttr == NULL) goto loser;
01715        vfy.seed.data = seedAttr->attrib.pValue;
01716        vfy.seed.len = seedAttr->attrib.ulValueLen;
01717 
01718        hAttr = sftk_FindAttribute(object, CKA_NETSCAPE_PQG_H);
01719        if (hAttr == NULL) goto loser;
01720        vfy.h.data = hAttr->attrib.pValue;
01721        vfy.h.len = hAttr->attrib.ulValueLen;
01722 
01723        verify = &vfy;
01724     }
01725 
01726     crv = CKR_FUNCTION_FAILED;
01727     rv = PQG_VerifyParams(&params,verify,&result);
01728     if (rv == SECSuccess) {
01729        crv = (result== SECSuccess) ? CKR_OK : CKR_ATTRIBUTE_VALUE_INVALID;
01730     }
01731 
01732 loser:
01733     if (hAttr) sftk_FreeAttribute(hAttr);
01734     if (seedAttr) sftk_FreeAttribute(seedAttr);
01735     if (baseAttr) sftk_FreeAttribute(baseAttr);
01736     if (subPrimeAttr) sftk_FreeAttribute(subPrimeAttr);
01737     if (primeAttr) sftk_FreeAttribute(primeAttr);
01738 
01739     return crv;
01740 }
01741 
01742 /*
01743  * check the consistancy and initialize a Key Parameter Object 
01744  */
01745 static CK_RV
01746 sftk_handleKeyParameterObject(SFTKSession *session, SFTKObject *object)
01747 {
01748     SFTKAttribute *attribute;
01749     CK_KEY_TYPE key_type;
01750     CK_BBOOL ckfalse = CK_FALSE;
01751     CK_RV crv;
01752 
01753     /* verify the required fields */
01754     if ( !sftk_hasAttribute(object,CKA_KEY_TYPE) ) {
01755        return CKR_TEMPLATE_INCOMPLETE;
01756     }
01757 
01758     /* now verify the common fields */
01759     crv = sftk_defaultAttribute(object,CKA_LOCAL,&ckfalse,sizeof(CK_BBOOL));
01760     if (crv != CKR_OK)  return crv; 
01761 
01762     /* get the key type */
01763     attribute = sftk_FindAttribute(object,CKA_KEY_TYPE);
01764     if (!attribute) {
01765         return CKR_ATTRIBUTE_VALUE_INVALID;
01766     }
01767     key_type = *(CK_KEY_TYPE *)attribute->attrib.pValue;
01768     sftk_FreeAttribute(attribute);
01769 
01770     switch (key_type) {
01771     case CKK_DSA:
01772        return sftk_handleDSAParameterObject(session,object);
01773        
01774     default:
01775        break;
01776     }
01777     return CKR_KEY_TYPE_INCONSISTENT;
01778 }
01779 
01780 /* 
01781  * Handle Object does all the object consistancy checks, automatic attribute
01782  * generation, attribute defaulting, etc. If handleObject succeeds, the object
01783  * will be assigned an object handle, and the object installed in the session
01784  * or stored in the DB.
01785  */
01786 CK_RV
01787 sftk_handleObject(SFTKObject *object, SFTKSession *session)
01788 {
01789     SFTKSlot *slot = session->slot;
01790     SFTKAttribute *attribute;
01791     SFTKObject *duplicateObject = NULL;
01792     CK_OBJECT_HANDLE handle;
01793     CK_BBOOL ckfalse = CK_FALSE;
01794     CK_BBOOL cktrue = CK_TRUE;
01795     CK_RV crv;
01796 
01797     /* make sure all the base object types are defined. If not set the
01798      * defaults */
01799     crv = sftk_defaultAttribute(object,CKA_TOKEN,&ckfalse,sizeof(CK_BBOOL));
01800     if (crv != CKR_OK) return crv;
01801     crv = sftk_defaultAttribute(object,CKA_PRIVATE,&ckfalse,sizeof(CK_BBOOL));
01802     if (crv != CKR_OK) return crv;
01803     crv = sftk_defaultAttribute(object,CKA_LABEL,NULL,0);
01804     if (crv != CKR_OK) return crv;
01805     crv = sftk_defaultAttribute(object,CKA_MODIFIABLE,&cktrue,sizeof(CK_BBOOL));
01806     if (crv != CKR_OK) return crv;
01807 
01808     /* don't create a private object if we aren't logged in */
01809     if ((!slot->isLoggedIn) && (slot->needLogin) &&
01810                             (sftk_isTrue(object,CKA_PRIVATE))) {
01811        return CKR_USER_NOT_LOGGED_IN;
01812     }
01813 
01814 
01815     if (((session->info.flags & CKF_RW_SESSION) == 0) &&
01816                             (sftk_isTrue(object,CKA_TOKEN))) {
01817        return CKR_SESSION_READ_ONLY;
01818     }
01819        
01820     /* Assign a unique SESSION object handle to every new object,
01821      * whether it is a session object or a token object.  
01822      * At this point, all new objects are structured as session objects.
01823      * Objects with the CKA_TOKEN attribute true will be turned into 
01824      * token objects and will have a token object handle assigned to 
01825      * them by a call to sftk_mkHandle in the handler for each object 
01826      * class, invoked below.
01827      *
01828      * It may be helpful to note/remember that 
01829      * sftk_narrowToXxxObject uses sftk_isToken,
01830      * sftk_isToken examines the sign bit of the object's handle, but
01831      * sftk_isTrue(...,CKA_TOKEN) examines the CKA_TOKEN attribute.
01832      */
01833     do {
01834        PRUint32 wrappedAround;
01835 
01836        duplicateObject = NULL;
01837        PZ_Lock(slot->objectLock);
01838        wrappedAround = slot->sessionObjectHandleCount &  SFTK_TOKEN_MASK;
01839        handle        = slot->sessionObjectHandleCount & ~SFTK_TOKEN_MASK;
01840        if (!handle) /* don't allow zero handle */
01841            handle = minSessionObjectHandle;  
01842        slot->sessionObjectHandleCount = (handle + 1U) | wrappedAround;
01843        /* Is there already a session object with this handle? */
01844        if (wrappedAround) {
01845            sftkqueue_find(duplicateObject, handle, slot->sessObjHashTable, \
01846                           slot->sessObjHashSize);
01847        }
01848        PZ_Unlock(slot->objectLock);
01849     } while (duplicateObject != NULL);
01850     object->handle = handle;
01851 
01852     /* get the object class */
01853     attribute = sftk_FindAttribute(object,CKA_CLASS);
01854     if (attribute == NULL) {
01855        return CKR_TEMPLATE_INCOMPLETE;
01856     }
01857     object->objclass = *(CK_OBJECT_CLASS *)attribute->attrib.pValue;
01858     sftk_FreeAttribute(attribute);
01859 
01860     /* Now handle the specific object class. 
01861      * At this point, all objects are session objects, and the session
01862      * number must be passed to the object class handlers.
01863      */
01864     switch (object->objclass) {
01865     case CKO_DATA:
01866        crv = sftk_handleDataObject(session,object);
01867        break;
01868     case CKO_CERTIFICATE:
01869        crv = sftk_handleCertObject(session,object);
01870        break;
01871     case CKO_NETSCAPE_TRUST:
01872        crv = sftk_handleTrustObject(session,object);
01873        break;
01874     case CKO_NETSCAPE_CRL:
01875        crv = sftk_handleCrlObject(session,object);
01876        break;
01877     case CKO_NETSCAPE_SMIME:
01878        crv = sftk_handleSMimeObject(session,object);
01879        break;
01880     case CKO_PRIVATE_KEY:
01881     case CKO_PUBLIC_KEY:
01882     case CKO_SECRET_KEY:
01883        crv = sftk_handleKeyObject(session,object);
01884        break;
01885     case CKO_KG_PARAMETERS:
01886        crv = sftk_handleKeyParameterObject(session,object);
01887        break;
01888     default:
01889        crv = CKR_ATTRIBUTE_VALUE_INVALID;
01890        break;
01891     }
01892 
01893     /* can't fail from here on out unless the pk_handlXXX functions have
01894      * failed the request */
01895     if (crv != CKR_OK) {
01896        return crv;
01897     }
01898 
01899     /* Now link the object into the slot and session structures.
01900      * If the object has a true CKA_TOKEN attribute, the above object
01901      * class handlers will have set the sign bit in the object handle,
01902      * causing the following test to be true.
01903      */
01904     if (sftk_isToken(object->handle)) {
01905        sftk_convertSessionToToken(object);
01906     } else {
01907        object->slot = slot;
01908        sftk_AddObject(session,object);
01909     }
01910 
01911     return CKR_OK;
01912 }
01913 
01914 /*
01915  * ******************** Public Key Utilities ***************************
01916  */
01917 /* Generate a low public key structure from an object */
01918 NSSLOWKEYPublicKey *sftk_GetPubKey(SFTKObject *object,CK_KEY_TYPE key_type, 
01919                                                         CK_RV *crvp)
01920 {
01921     NSSLOWKEYPublicKey *pubKey;
01922     PLArenaPool *arena;
01923     CK_RV crv;
01924 
01925     if (object->objclass != CKO_PUBLIC_KEY) {
01926        *crvp = CKR_KEY_TYPE_INCONSISTENT;
01927        return NULL;
01928     }
01929 
01930     if (sftk_isToken(object->handle)) {
01931 /* ferret out the token object handle */
01932     }
01933 
01934     /* If we already have a key, use it */
01935     if (object->objectInfo) {
01936        *crvp = CKR_OK;
01937        return (NSSLOWKEYPublicKey *)object->objectInfo;
01938     }
01939 
01940     /* allocate the structure */
01941     arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
01942     if (arena == NULL) {
01943        *crvp = CKR_HOST_MEMORY;
01944        return NULL;
01945     }
01946 
01947     pubKey = (NSSLOWKEYPublicKey *)
01948                      PORT_ArenaAlloc(arena,sizeof(NSSLOWKEYPublicKey));
01949     if (pubKey == NULL) {
01950        PORT_FreeArena(arena,PR_FALSE);
01951        *crvp = CKR_HOST_MEMORY;
01952        return NULL;
01953     }
01954 
01955     /* fill in the structure */
01956     pubKey->arena = arena;
01957     switch (key_type) {
01958     case CKK_RSA:
01959        pubKey->keyType = NSSLOWKEYRSAKey;
01960        crv = sftk_Attribute2SSecItem(arena,&pubKey->u.rsa.modulus,
01961                                                  object,CKA_MODULUS);
01962        if (crv != CKR_OK) break;
01963        crv = sftk_Attribute2SSecItem(arena,&pubKey->u.rsa.publicExponent,
01964                                           object,CKA_PUBLIC_EXPONENT);
01965        break;
01966     case CKK_DSA:
01967        pubKey->keyType = NSSLOWKEYDSAKey;
01968        crv = sftk_Attribute2SSecItem(arena,&pubKey->u.dsa.params.prime,
01969                                                  object,CKA_PRIME);
01970        if (crv != CKR_OK) break;
01971        crv = sftk_Attribute2SSecItem(arena,&pubKey->u.dsa.params.subPrime,
01972                                                  object,CKA_SUBPRIME);
01973        if (crv != CKR_OK) break;
01974        crv = sftk_Attribute2SSecItem(arena,&pubKey->u.dsa.params.base,
01975                                                  object,CKA_BASE);
01976        if (crv != CKR_OK) break;
01977        crv = sftk_Attribute2SSecItem(arena,&pubKey->u.dsa.publicValue,
01978                                                  object,CKA_VALUE);
01979        break;
01980     case CKK_DH:
01981        pubKey->keyType = NSSLOWKEYDHKey;
01982        crv = sftk_Attribute2SSecItem(arena,&pubKey->u.dh.prime,
01983                                                  object,CKA_PRIME);
01984        if (crv != CKR_OK) break;
01985        crv = sftk_Attribute2SSecItem(arena,&pubKey->u.dh.base,
01986                                                  object,CKA_BASE);
01987        if (crv != CKR_OK) break;
01988        crv = sftk_Attribute2SSecItem(arena,&pubKey->u.dh.publicValue,
01989                                                  object,CKA_VALUE);
01990        break;
01991 #ifdef NSS_ENABLE_ECC
01992     case CKK_EC:
01993        pubKey->keyType = NSSLOWKEYECKey;
01994        crv = sftk_Attribute2SSecItem(arena,
01995                                      &pubKey->u.ec.ecParams.DEREncoding,
01996                                      object,CKA_EC_PARAMS);
01997        if (crv != CKR_OK) break;
01998 
01999        /* Fill out the rest of the ecParams structure 
02000         * based on the encoded params
02001         */
02002        if (EC_FillParams(arena, &pubKey->u.ec.ecParams.DEREncoding,
02003                   &pubKey->u.ec.ecParams) != SECSuccess) {
02004            crv = CKR_DOMAIN_PARAMS_INVALID;
02005            break;
02006        }
02007            
02008        crv = sftk_Attribute2SSecItem(arena,&pubKey->u.ec.publicValue,
02009                                      object,CKA_EC_POINT);
02010        break;
02011 #endif /* NSS_ENABLE_ECC */
02012     default:
02013        crv = CKR_KEY_TYPE_INCONSISTENT;
02014        break;
02015     }
02016     *crvp = crv;
02017     if (crv != CKR_OK) {
02018        PORT_FreeArena(arena,PR_FALSE);
02019        return NULL;
02020     }
02021 
02022     object->objectInfo = pubKey;
02023     object->infoFree = (SFTKFree) nsslowkey_DestroyPublicKey;
02024     return pubKey;
02025 }
02026 
02027 /* make a private key from a verified object */
02028 static NSSLOWKEYPrivateKey *
02029 sftk_mkPrivKey(SFTKObject *object, CK_KEY_TYPE key_type, CK_RV *crvp)
02030 {
02031     NSSLOWKEYPrivateKey *privKey;
02032     PLArenaPool *arena;
02033     CK_RV crv = CKR_OK;
02034     SECStatus rv;
02035 
02036     PORT_Assert(!sftk_isToken(object->handle));
02037     arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
02038     if (arena == NULL) {
02039        *crvp = CKR_HOST_MEMORY;
02040        return NULL;
02041     }
02042 
02043     privKey = (NSSLOWKEYPrivateKey *)
02044                      PORT_ArenaZAlloc(arena,sizeof(NSSLOWKEYPrivateKey));
02045     if (privKey == NULL)  {
02046        PORT_FreeArena(arena,PR_FALSE);
02047        *crvp = CKR_HOST_MEMORY;
02048        return NULL;
02049     }
02050 
02051     /* in future this would be a switch on key_type */
02052     privKey->arena = arena;
02053     switch (key_type) {
02054     case CKK_RSA:
02055        privKey->keyType = NSSLOWKEYRSAKey;
02056        crv=sftk_Attribute2SSecItem(arena,&privKey->u.rsa.modulus,
02057                                                  object,CKA_MODULUS);
02058        if (crv != CKR_OK) break;
02059        crv=sftk_Attribute2SSecItem(arena,&privKey->u.rsa.publicExponent,object,
02060                                                  CKA_PUBLIC_EXPONENT);
02061        if (crv != CKR_OK) break;
02062        crv=sftk_Attribute2SSecItem(arena,&privKey->u.rsa.privateExponent,object,
02063                                                  CKA_PRIVATE_EXPONENT);
02064        if (crv != CKR_OK) break;
02065        crv=sftk_Attribute2SSecItem(arena,&privKey->u.rsa.prime1,object,
02066                                                         CKA_PRIME_1);
02067        if (crv != CKR_OK) break;
02068        crv=sftk_Attribute2SSecItem(arena,&privKey->u.rsa.prime2,object,
02069                                                         CKA_PRIME_2);
02070        if (crv != CKR_OK) break;
02071        crv=sftk_Attribute2SSecItem(arena,&privKey->u.rsa.exponent1,
02072                                           object, CKA_EXPONENT_1);
02073        if (crv != CKR_OK) break;
02074        crv=sftk_Attribute2SSecItem(arena,&privKey->u.rsa.exponent2,
02075                                                  object, CKA_EXPONENT_2);
02076        if (crv != CKR_OK) break;
02077        crv=sftk_Attribute2SSecItem(arena,&privKey->u.rsa.coefficient,object,
02078                                                        CKA_COEFFICIENT);
02079        if (crv != CKR_OK) break;
02080         rv = DER_SetUInteger(privKey->arena, &privKey->u.rsa.version,
02081                           NSSLOWKEY_VERSION);
02082        if (rv != SECSuccess) crv = CKR_HOST_MEMORY;
02083        break;
02084 
02085     case CKK_DSA:
02086        privKey->keyType = NSSLOWKEYDSAKey;
02087        crv = sftk_Attribute2SSecItem(arena,&privKey->u.dsa.params.prime,
02088                                                  object,CKA_PRIME);
02089        if (crv != CKR_OK) break;
02090        crv = sftk_Attribute2SSecItem(arena,&privKey->u.dsa.params.subPrime,
02091                                                  object,CKA_SUBPRIME);
02092        if (crv != CKR_OK) break;
02093        crv = sftk_Attribute2SSecItem(arena,&privKey->u.dsa.params.base,
02094                                                  object,CKA_BASE);
02095        if (crv != CKR_OK) break;
02096        crv = sftk_Attribute2SSecItem(arena,&privKey->u.dsa.privateValue,
02097                                                  object,CKA_VALUE);
02098        if (crv != CKR_OK) break;
02099        if (sftk_hasAttribute(object,CKA_NETSCAPE_DB)) {
02100            crv = sftk_Attribute2SSecItem(arena, &privKey->u.dsa.publicValue,
02101                                   object,CKA_NETSCAPE_DB);
02102            /* privKey was zero'd so public value is already set to NULL, 0
02103             * if we don't set it explicitly */
02104        }
02105        break;
02106 
02107     case CKK_DH:
02108        privKey->keyType = NSSLOWKEYDHKey;
02109        crv = sftk_Attribute2SSecItem(arena,&privKey->u.dh.prime,
02110                                                  object,CKA_PRIME);
02111        if (crv != CKR_OK) break;
02112        crv = sftk_Attribute2SSecItem(arena,&privKey->u.dh.base,
02113                                                  object,CKA_BASE);
02114        if (crv != CKR_OK) break;
02115        crv = sftk_Attribute2SSecItem(arena,&privKey->u.dh.privateValue,
02116                                                  object,CKA_VALUE);
02117        if (crv != CKR_OK) break;
02118        if (sftk_hasAttribute(object,CKA_NETSCAPE_DB)) {
02119            crv = sftk_Attribute2SSecItem(arena, &privKey->u.dh.publicValue,
02120                                   object,CKA_NETSCAPE_DB);
02121            /* privKey was zero'd so public value is already set to NULL, 0
02122             * if we don't set it explicitly */
02123        }
02124        break;
02125 
02126 #ifdef NSS_ENABLE_ECC
02127     case CKK_EC:
02128        privKey->keyType = NSSLOWKEYECKey;
02129        crv = sftk_Attribute2SSecItem(arena, 
02130                                      &privKey->u.ec.ecParams.DEREncoding,
02131                                      object,CKA_EC_PARAMS);
02132        if (crv != CKR_OK) break;
02133 
02134        /* Fill out the rest of the ecParams structure
02135         * based on the encoded params
02136         */
02137        if (EC_FillParams(arena, &privKey->u.ec.ecParams.DEREncoding,
02138                   &privKey->u.ec.ecParams) != SECSuccess) {
02139            crv = CKR_DOMAIN_PARAMS_INVALID;
02140            break;
02141        }
02142        crv = sftk_Attribute2SSecItem(arena,&privKey->u.ec.privateValue,
02143                                                  object,CKA_VALUE);
02144        if (crv != CKR_OK) break;
02145        if (sftk_hasAttribute(object,CKA_NETSCAPE_DB)) {
02146            crv = sftk_Attribute2SSecItem(arena, &privKey->u.ec.publicValue,
02147                                   object,CKA_NETSCAPE_DB);
02148            if (crv != CKR_OK) break;
02149            /* privKey was zero'd so public value is already set to NULL, 0
02150             * if we don't set it explicitly */
02151        }
02152         rv = DER_SetUInteger(privKey->arena, &privKey->u.ec.version,
02153                           NSSLOWKEY_EC_PRIVATE_KEY_VERSION);
02154        if (rv != SECSuccess) crv = CKR_HOST_MEMORY;
02155        break;
02156 #endif /* NSS_ENABLE_ECC */
02157 
02158     default:
02159        crv = CKR_KEY_TYPE_INCONSISTENT;
02160        break;
02161     }
02162     *crvp = crv;
02163     if (crv != CKR_OK) {
02164        PORT_FreeArena(arena,PR_FALSE);
02165        return NULL;
02166     }
02167     return privKey;
02168 }
02169 
02170 
02171 /* Generate a low private key structure from an object */
02172 NSSLOWKEYPrivateKey *
02173 sftk_GetPrivKey(SFTKObject *object,CK_KEY_TYPE key_type, CK_RV *crvp)
02174 {
02175     NSSLOWKEYPrivateKey *priv = NULL;
02176 
02177     if (object->objclass != CKO_PRIVATE_KEY) {
02178        *crvp = CKR_KEY_TYPE_INCONSISTENT;
02179        return NULL;
02180     }
02181     if (object->objectInfo) {
02182        *crvp = CKR_OK;
02183        return (NSSLOWKEYPrivateKey *)object->objectInfo;
02184     }
02185 
02186     if (sftk_isToken(object->handle)) {
02187        /* grab it from the data base */
02188        SFTKTokenObject *to = sftk_narrowToTokenObject(object);
02189 
02190        PORT_Assert(to);
02191        priv = sftk_FindKeyByPublicKey(object->slot, &to->dbKey);
02192        *crvp = (priv == NULL) ? CKR_DEVICE_ERROR : CKR_OK;
02193     } else {
02194        priv = sftk_mkPrivKey(object, key_type, crvp);
02195     }
02196     object->objectInfo = priv;
02197     object->infoFree = (SFTKFree) nsslowkey_DestroyPrivateKey;
02198     return priv;
02199 }
02200 
02201 /*
02202  **************************** Symetric Key utils ************************
02203  */
02204 /*
02205  * set the DES key with parity bits correctly
02206  */
02207 void
02208 sftk_FormatDESKey(unsigned char *key, int length)
02209 {
02210     int i;
02211 
02212     /* format the des key */
02213     for (i=0; i < length; i++) {
02214        key[i] = parityTable[key[i]>>1];
02215     }
02216 }
02217 
02218 /*
02219  * check a des key (des2 or des3 subkey) for weak keys.
02220  */
02221 PRBool
02222 sftk_CheckDESKey(unsigned char *key)
02223 {
02224     int i;
02225 
02226     /* format the des key with parity  */
02227     sftk_FormatDESKey(key, 8);
02228 
02229     for (i=0; i < sftk_desWeakTableSize; i++) {
02230        if (PORT_Memcmp(key,sftk_desWeakTable[i],8) == 0) {
02231            return PR_TRUE;
02232        }
02233     }
02234     return PR_FALSE;
02235 }
02236 
02237 /*
02238  * check if a des or triple des key is weak.
02239  */
02240 PRBool
02241 sftk_IsWeakKey(unsigned char *key,CK_KEY_TYPE key_type)
02242 {
02243 
02244     switch(key_type) {
02245     case CKK_DES:
02246        return sftk_CheckDESKey(key);
02247     case CKM_DES2_KEY_GEN:
02248        if (sftk_CheckDESKey(key)) return PR_TRUE;
02249        return sftk_CheckDESKey(&key[8]);
02250     case CKM_DES3_KEY_GEN:
02251        if (sftk_CheckDESKey(key)) return PR_TRUE;
02252        if (sftk_CheckDESKey(&key[8])) return PR_TRUE;
02253        return sftk_CheckDESKey(&key[16]);
02254     default:
02255        break;
02256     }
02257     return PR_FALSE;
02258 }
02259 
02260 
02261 /* make a fake private key representing a symmetric key */
02262 static NSSLOWKEYPrivateKey *
02263 sftk_mkSecretKeyRep(SFTKObject *object)
02264 {
02265     NSSLOWKEYPrivateKey *privKey = 0;
02266     PLArenaPool *arena = 0;
02267     CK_KEY_TYPE keyType;
02268     PRUint32 keyTypeStorage;
02269     SECItem keyTypeItem;
02270     CK_RV crv;
02271     SECStatus rv;
02272     static unsigned char derZero[1] = { 0 };
02273 
02274     arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
02275     if (arena == NULL) { crv = CKR_HOST_MEMORY; goto loser; }
02276 
02277     privKey = (NSSLOWKEYPrivateKey *)
02278                      PORT_ArenaZAlloc(arena,sizeof(NSSLOWKEYPrivateKey));
02279     if (privKey == NULL) { crv = CKR_HOST_MEMORY; goto loser; }
02280 
02281     privKey->arena = arena;
02282 
02283     /* Secret keys are represented in the database as "fake" RSA keys.  The RSA key
02284      * is marked as a secret key representation by setting the public exponent field
02285      * to 0, which is an invalid RSA exponent.  The other fields are set as follows:
02286      *   modulus - CKA_ID value for the secret key
02287      *   private exponent - CKA_VALUE (the key itself)
02288      *   coefficient - CKA_KEY_TYPE, which indicates what encryption algorithm
02289      *      is used for the key.
02290      *   all others - set to integer 0
02291      */
02292     privKey->keyType = NSSLOWKEYRSAKey;
02293 
02294     /* The modulus is set to the key id of the symmetric key */
02295     crv=sftk_Attribute2SecItem(arena,&privKey->u.rsa.modulus,object,CKA_ID);
02296     if (crv != CKR_OK) goto loser;
02297 
02298     /* The public exponent is set to 0 length to indicate a special key */
02299     privKey->u.rsa.publicExponent.len = sizeof derZero;
02300     privKey->u.rsa.publicExponent.data = derZero;
02301 
02302     /* The private exponent is the actual key value */
02303     crv=sftk_Attribute2SecItem(arena,&privKey->u.rsa.privateExponent,object,CKA_VALUE);
02304     if (crv != CKR_OK) goto loser;
02305 
02306     /* All other fields empty - needs testing */
02307     privKey->u.rsa.prime1.len = sizeof derZero;
02308     privKey->u.rsa.prime1.data = derZero;
02309 
02310     privKey->u.rsa.prime2.len = sizeof derZero;
02311     privKey->u.rsa.prime2.data = derZero;
02312 
02313     privKey->u.rsa.exponent1.len = sizeof derZero;
02314     privKey->u.rsa.exponent1.data = derZero;
02315 
02316     privKey->u.rsa.exponent2.len = sizeof derZero;
02317     privKey->u.rsa.exponent2.data = derZero;
02318 
02319     /* Coeficient set to KEY_TYPE */
02320     crv = sftk_GetULongAttribute(object, CKA_KEY_TYPE, &keyType);
02321     if (crv != CKR_OK) goto loser; 
02322     /* on 64 bit platforms, we still want to store 32 bits of keyType (This is
02323      * safe since the PKCS #11 defines for all types are 32 bits or less). */
02324     keyTypeStorage = (PRUint32) keyType;
02325     keyTypeStorage = PR_htonl(keyTypeStorage);
02326     keyTypeItem.data = (unsigned char *)&keyTypeStorage;
02327     keyTypeItem.len = sizeof (keyTypeStorage);
02328     rv = SECITEM_CopyItem(arena, &privKey->u.rsa.coefficient, &keyTypeItem);
02329     if (rv != SECSuccess) {
02330        crv = CKR_HOST_MEMORY;
02331        goto loser;
02332     }
02333     
02334     /* Private key version field set normally for compatibility */
02335     rv = DER_SetUInteger(privKey->arena, 
02336                      &privKey->u.rsa.version, NSSLOWKEY_VERSION);
02337     if (rv != SECSuccess) { crv = CKR_HOST_MEMORY; goto loser; }
02338 
02339 loser:
02340     if (crv != CKR_OK) {
02341        PORT_FreeArena(arena,PR_FALSE);
02342        privKey = 0;
02343     }
02344 
02345     return privKey;
02346 }
02347 
02348 static PRBool
02349 isSecretKey(NSSLOWKEYPrivateKey *privKey)
02350 {
02351   if (privKey->keyType == NSSLOWKEYRSAKey && 
02352               privKey->u.rsa.publicExponent.len == 1 &&
02353                             privKey->u.rsa.publicExponent.data[0] == 0)
02354     return PR_TRUE;
02355 
02356   return PR_FALSE;
02357 }
02358 
02359 /**********************************************************************
02360  *
02361  *     Start of PKCS 11 functions 
02362  *
02363  **********************************************************************/
02364 
02365 
02366 /* return the function list */
02367 CK_RV NSC_GetFunctionList(CK_FUNCTION_LIST_PTR *pFunctionList)
02368 {
02369     *pFunctionList = (CK_FUNCTION_LIST_PTR) &sftk_funcList;
02370     return CKR_OK;
02371 }
02372 
02373 /* return the function list */
02374 CK_RV C_GetFunctionList(CK_FUNCTION_LIST_PTR *pFunctionList)
02375 {
02376     return NSC_GetFunctionList(pFunctionList);
02377 }
02378 
02379 static PLHashNumber
02380 sftk_HashNumber(const void *key)
02381 {
02382     return (PLHashNumber) key;
02383 }
02384 
02385 /*
02386  * eventually I'd like to expunge all occurances of XXX_SLOT_ID and
02387  * just go with the info in the slot. This is one place, however,
02388  * where it might be a little difficult.
02389  */
02390 const char *
02391 sftk_getDefTokName(CK_SLOT_ID slotID)
02392 {
02393     static char buf[33];
02394 
02395     switch (slotID) {
02396     case NETSCAPE_SLOT_ID:
02397        return "NSS Generic Crypto Services     ";
02398     case PRIVATE_KEY_SLOT_ID:
02399        return "NSS Certificate DB              ";
02400     case FIPS_SLOT_ID:
02401         return "NSS FIPS 140-2 Certificate DB   ";
02402     default:
02403        break;
02404     }
02405     sprintf(buf,"NSS Application Token %08x  ",(unsigned int) slotID);
02406     return buf;
02407 }
02408 
02409 const char *
02410 sftk_getDefSlotName(CK_SLOT_ID slotID)
02411 {
02412     static char buf[65];
02413 
02414     switch (slotID) {
02415     case NETSCAPE_SLOT_ID:
02416        return 
02417         "NSS Internal Cryptographic Services                             ";
02418     case PRIVATE_KEY_SLOT_ID:
02419        return 
02420         "NSS User Private Key and Certificate Services                   ";
02421     case FIPS_SLOT_ID:
02422         return 
02423          "NSS FIPS 140-2 User Private Key Services                        ";
02424     default:
02425        break;
02426     }
02427     sprintf(buf,
02428      "NSS Application Slot %08x                                   ",
02429                                                  (unsigned int) slotID);
02430     return buf;
02431 }
02432 
02433 static CK_ULONG nscSlotCount[2] = {0 , 0};
02434 static CK_SLOT_ID_PTR nscSlotList[2] = {NULL, NULL};
02435 static CK_ULONG nscSlotListSize[2] = {0, 0};
02436 static PLHashTable *nscSlotHashTable[2] = {NULL, NULL};
02437 
02438 static int
02439 sftk_GetModuleIndex(CK_SLOT_ID slotID)
02440 {
02441     if ((slotID == FIPS_SLOT_ID) || (slotID >= SFTK_MIN_FIPS_USER_SLOT_ID)) {
02442        return NSC_FIPS_MODULE;
02443     }
02444     return NSC_NON_FIPS_MODULE;
02445 }
02446 
02447 /* look up a slot structure from the ID (used to be a macro when we only
02448  * had two slots) */
02449 /* if all is true, return the slot even if it has been 'unloaded' */
02450 /* if all is false, only return the slots which are present */
02451 SFTKSlot *
02452 sftk_SlotFromID(CK_SLOT_ID slotID, PRBool all)
02453 {
02454     SFTKSlot *slot;
02455     int index = sftk_GetModuleIndex(slotID);
02456     
02457     if (nscSlotHashTable[index] == NULL) return NULL;
02458     slot = (SFTKSlot *)PL_HashTableLookupConst(nscSlotHashTable[index], 
02459                                                  (void *)slotID);
02460     /* cleared slots shouldn't 'show up' */
02461     if (slot && !all && !slot->present) slot = NULL;
02462     return slot;
02463 }
02464 
02465 SFTKSlot *
02466 sftk_SlotFromSessionHandle(CK_SESSION_HANDLE handle)
02467 {
02468     CK_ULONG slotIDIndex = (handle >> 24) & 0x7f;
02469     CK_ULONG moduleIndex = (handle >> 31) & 1;
02470 
02471     if (slotIDIndex >= nscSlotCount[moduleIndex]) {
02472        return NULL;
02473     }
02474 
02475     return sftk_SlotFromID(nscSlotList[moduleIndex][slotIDIndex], PR_FALSE);
02476 }
02477  
02478 static CK_RV
02479 sftk_RegisterSlot(SFTKSlot *slot, int moduleIndex)
02480 {
02481     PLHashEntry *entry;
02482     int index;
02483 
02484     index = sftk_GetModuleIndex(slot->slotID);
02485 
02486     /* make sure the slotID for this module is valid */
02487     if (moduleIndex != index) {
02488        return CKR_SLOT_ID_INVALID;
02489     }
02490 
02491     if (nscSlotList[index] == NULL) {
02492        nscSlotListSize[index] = NSC_SLOT_LIST_BLOCK_SIZE;
02493        nscSlotList[index] = (CK_SLOT_ID *)
02494               PORT_ZAlloc(nscSlotListSize[index]*sizeof(CK_SLOT_ID));
02495        if (nscSlotList[index] == NULL) {
02496            return CKR_HOST_MEMORY;
02497        }
02498     }
02499     if (nscSlotCount[index] >= nscSlotListSize[index]) {
02500        CK_SLOT_ID* oldNscSlotList = nscSlotList[index];
02501        CK_ULONG oldNscSlotListSize = nscSlotListSize[index];
02502        nscSlotListSize[index] += NSC_SLOT_LIST_BLOCK_SIZE;
02503        nscSlotList[index] = (CK_SLOT_ID *) PORT_Realloc(oldNscSlotList,
02504                             nscSlotListSize[index]*sizeof(CK_SLOT_ID));
02505        if (nscSlotList[index] == NULL) {
02506             nscSlotList[index] = oldNscSlotList;
02507             nscSlotListSize[index] = oldNscSlotListSize;
02508             return CKR_HOST_MEMORY;
02509        }
02510     }
02511 
02512     if (nscSlotHashTable[index] == NULL) {
02513        nscSlotHashTable[index] = PL_NewHashTable(64,sftk_HashNumber,
02514                             PL_CompareValues, PL_CompareValues, NULL, 0);
02515        if (nscSlotHashTable[index] == NULL) {
02516            return CKR_HOST_MEMORY;
02517        }
02518     }
02519 
02520     entry = PL_HashTableAdd(nscSlotHashTable[index],(void *)slot->slotID,slot);
02521     if (entry == NULL) {
02522        return CKR_HOST_MEMORY;
02523     }
02524     slot->index = (nscSlotCount[index] & 0x7f) | ((index << 7) & 0x80);
02525     nscSlotList[index][nscSlotCount[index]++] = slot->slotID;
02526 
02527     return CKR_OK;
02528 }
02529 
02530 typedef struct sftk_DBsStr {
02531     NSSLOWCERTCertDBHandle *certHandle;
02532     NSSLOWKEYDBHandle *keyHandle;
02533 } sftkDBs;
02534 
02535 static SECStatus
02536 sftk_set_user(NSSLOWCERTCertificate *cert, SECItem *dummy, void *arg)
02537 {
02538     sftkDBs *param = (sftkDBs *)arg;
02539     NSSLOWCERTCertTrust trust = *cert->trust;
02540 
02541     if (param->keyHandle && 
02542                 nsslowkey_KeyForCertExists(param->keyHandle,cert)) {
02543        trust.sslFlags |= CERTDB_USER;
02544        trust.emailFlags |= CERTDB_USER;
02545        trust.objectSigningFlags |= CERTDB_USER;
02546     } else {
02547        trust.sslFlags &= ~CERTDB_USER;
02548        trust.emailFlags &= ~CERTDB_USER;
02549        trust.objectSigningFlags &= ~CERTDB_USER;
02550     }
02551 
02552     if (PORT_Memcmp(&trust,cert->trust, sizeof (trust)) != 0) {
02553        nsslowcert_ChangeCertTrust(param->certHandle, cert, &trust);
02554     }
02555 
02556     /* should check for email address and make sure we have an s/mime profile */
02557     return SECSuccess;
02558 }
02559 
02560 /*
02561  * this function fixes up old databases that may not have the CERTDB_USER
02562  * flags set correctly. it expects the owner already has references to
02563  * the cert and key handles.
02564  */
02565 static  void
02566 sftk_DBVerify(NSSLOWCERTCertDBHandle *certHandle, NSSLOWKEYDBHandle *keyHandle)
02567 {
02568     /* walk through all the certs and check to see if there are any 
02569      * user certs, and make sure there are s/mime profiles for all certs with
02570      * email addresses */
02571     sftkDBs param;
02572     param.certHandle = certHandle;
02573     param.keyHandle = keyHandle;
02574 
02575     nsslowcert_TraversePermCerts(certHandle, sftk_set_user, &param);
02576 
02577     return;
02578 }
02579 
02580 
02581 /*
02582  * ths function has all the common initialization that happens whenever we
02583  * create a new slot or repurpose an old slot (only valid for slotID's 4 
02584  * and greater).
02585  *
02586  * things that are not reinitialized are:
02587  *   slotID (can't change)
02588  *   slotDescription (can't change once defined) 
02589  *   the locks and hash tables (difficult to change in running code, and
02590  *     unnecessary. hash tables and list are cleared on shutdown, but they
02591  *     are cleared in a 'friendly' way).
02592  *   session and object ID counters -- so any old sessions and objects in the
02593  *     application will get properly notified that the world has changed.
02594  * 
02595  * things that are reinitialized:
02596  *   database (otherwise what would the point be;).
02597  *   state variables related to databases.
02598  *   session count stat info.
02599  *   tokenDescription.
02600  *
02601  * NOTE: slotID's 4 and greater show up as removable devices.
02602  *
02603  */
02604 CK_RV
02605 SFTK_SlotReInit(SFTKSlot *slot,
02606        char *configdir,sftk_token_parameters *params, int moduleIndex)
02607 {
02608     PRBool needLogin = !params->noKeyDB;
02609     CK_RV crv;
02610 
02611     slot->hasTokens = PR_FALSE;
02612     slot->sessionIDConflict = 0;
02613     slot->sessionCount = 0;
02614     slot->rwSessionCount = 0;
02615     slot->needLogin = PR_FALSE;
02616     slot->isLoggedIn = PR_FALSE;
02617     slot->ssoLoggedIn = PR_FALSE;
02618     slot->DB_loaded = PR_FALSE;
02619     slot->certDB = NULL;
02620     slot->keyDB = NULL;
02621     slot->minimumPinLen = 0;
02622     slot->readOnly = params->readOnly;
02623     sftk_setStringName(params->tokdes ? params->tokdes : 
02624        sftk_getDefTokName(slot->slotID), slot->tokDescription, 
02625                                           sizeof(slot->tokDescription));
02626 
02627     if ((!params->noCertDB) || (!params->noKeyDB)) {
02628        NSSLOWCERTCertDBHandle * certHandle = NULL;
02629        NSSLOWKEYDBHandle *keyHandle = NULL;
02630        crv = sftk_DBInit(params->configdir ? params->configdir : configdir,
02631               params->certPrefix, params->keyPrefix, params->readOnly,
02632               params->noCertDB, params->noKeyDB, params->forceOpen, 
02633                                           &certHandle, &keyHandle);
02634        if (crv != CKR_OK) {
02635            goto loser;
02636        }
02637 
02638        if (nsslowcert_needDBVerify(certHandle)) {
02639            sftk_DBVerify(certHandle, keyHandle);
02640        }
02641        slot->certDB = certHandle;
02642        slot->keyDB = keyHandle;
02643     }
02644     if (needLogin) {
02645        /* if the data base is initialized with a null password,remember that */
02646        slot->needLogin = 
02647               (PRBool)!sftk_hasNullPassword(slot->keyDB,&slot->password);
02648        if ((params->minPW >= 0) && (params->minPW <= SFTK_MAX_PIN)) {
02649            slot->minimumPinLen = params->minPW;
02650        }
02651        if ((slot->minimumPinLen == 0) && (params->pwRequired)) {
02652            slot->minimumPinLen = 1;
02653        }
02654        if ((moduleIndex == NSC_FIPS_MODULE) &&
02655               (slot->minimumPinLen < FIPS_MIN_PIN)) {
02656            slot->minimumPinLen = FIPS_MIN_PIN;
02657        }
02658     }
02659 
02660     slot->present = PR_TRUE;
02661     return CKR_OK;
02662 
02663 loser:
02664     SFTK_ShutdownSlot(slot);
02665     return crv;
02666 }
02667 
02668 /*
02669  * initialize one of the slot structures. figure out which by the ID
02670  */
02671 CK_RV
02672 SFTK_SlotInit(char *configdir,sftk_token_parameters *params, int moduleIndex)
02673 {
02674     unsigned int i;
02675     CK_SLOT_ID slotID = params->slotID;
02676     SFTKSlot *slot;
02677     CK_RV crv = CKR_HOST_MEMORY;
02678 
02679     /*
02680      * first we initialize everything that is 'permanent' with this slot.
02681      * that is everything we aren't going to shutdown if we close this slot
02682      * and open it up again with different databases */
02683 
02684     slot = PORT_ZNew(SFTKSlot);
02685 
02686     if (slot == NULL) {
02687        return CKR_HOST_MEMORY;
02688     }
02689 
02690     slot->optimizeSpace = params->optimizeSpace;
02691     if (slot->optimizeSpace) {
02692        slot->sessObjHashSize = SPACE_SESSION_OBJECT_HASH_SIZE;
02693        slot->sessHashSize = SPACE_SESSION_HASH_SIZE;
02694        slot->numSessionLocks = 1;
02695     } else {
02696        slot->sessObjHashSize = TIME_SESSION_OBJECT_HASH_SIZE;
02697        slot->sessHashSize = TIME_SESSION_HASH_SIZE;
02698        slot->numSessionLocks = slot->sessHashSize/BUCKETS_PER_SESSION_LOCK;
02699     }
02700     slot->sessionLockMask = slot->numSessionLocks-1;
02701 
02702     slot->slotLock = PZ_NewLock(nssILockSession);
02703     if (slot->slotLock == NULL)
02704        goto mem_loser;
02705     slot->sessionLock = PORT_ZNewArray(PZLock *, slot->numSessionLocks);
02706     if (slot->sessionLock == NULL)
02707        goto mem_loser;
02708     for (i=0; i < slot->numSessionLocks; i++) {
02709         slot->sessionLock[i] = PZ_NewLock(nssILockSession);
02710         if (slot->sessionLock[i] == NULL) 
02711            goto mem_loser;
02712     }
02713     slot->objectLock = PZ_NewLock(nssILockObject);
02714     if (slot->objectLock == NULL) 
02715        goto mem_loser;
02716     slot->pwCheckLock = PR_NewLock();
02717     if (slot->pwCheckLock == NULL) 
02718        goto mem_loser;
02719     slot->head = PORT_ZNewArray(SFTKSession *, slot->sessHashSize);
02720     if (slot->head == NULL) 
02721        goto mem_loser;
02722     slot->sessObjHashTable = PORT_ZNewArray(SFTKObject *, slot->sessObjHashSize);
02723     if (slot->sessObjHashTable == NULL) 
02724        goto mem_loser;
02725     slot->tokObjHashTable = PL_NewHashTable(64,sftk_HashNumber,PL_CompareValues,
02726                                    SECITEM_HashCompare, NULL, 0);
02727     if (slot->tokObjHashTable == NULL) 
02728        goto mem_loser;
02729 
02730     slot->sessionIDCount = 0;
02731     slot->sessionObjectHandleCount = minSessionObjectHandle;
02732     slot->slotID = slotID;
02733     sftk_setStringName(params->slotdes ? params->slotdes : 
02734              sftk_getDefSlotName(slotID), slot->slotDescription, 
02735                                           sizeof(slot->slotDescription));
02736 
02737     /* call the reinit code to set everything that changes between token
02738      * init calls */
02739     crv = SFTK_SlotReInit(slot, configdir, params, moduleIndex);
02740     if (crv != CKR_OK) {
02741        goto loser;
02742     }
02743     crv = sftk_RegisterSlot(slot, moduleIndex);
02744     if (crv != CKR_OK) {
02745        goto loser;
02746     }
02747     return CKR_OK;
02748 
02749 mem_loser:
02750     crv = CKR_HOST_MEMORY;
02751 loser:
02752    SFTK_DestroySlotData(slot);
02753     return crv;
02754 }
02755 
02756 
02757 static CK_RV sft_CloseAllSession(SFTKSlot *slot)
02758 {
02759     SECItem *pw = NULL;
02760     SFTKSession *session;
02761     unsigned int i;
02762     /* first log out the card */
02763     PZ_Lock(slot->slotLock);
02764     pw = slot->password;
02765     slot->isLoggedIn = PR_FALSE;
02766     slot->password = NULL;
02767     PZ_Unlock(slot->slotLock);
02768     if (pw) SECITEM_ZfreeItem(pw, PR_TRUE);
02769 
02770     /* now close all the current sessions */
02771     /* NOTE: If you try to open new sessions before NSC_CloseAllSessions
02772      * completes, some of those new sessions may or may not be closed by
02773      * NSC_CloseAllSessions... but any session running when this code starts
02774      * will guarrenteed be close, and no session will be partially closed */
02775     for (i=0; i < slot->sessHashSize; i++) {
02776        PZLock *lock = SFTK_SESSION_LOCK(slot,i);
02777        do {
02778            PZ_Lock(lock);
02779            session = slot->head[i];
02780            /* hand deque */
02781            /* this duplicates function of NSC_close session functions, but 
02782             * because we know that we are freeing all the sessions, we can
02783             * do more efficient processing */
02784            if (session) {
02785               slot->head[i] = session->next;
02786               if (session->next) session->next->prev = NULL;
02787               session->next = session->prev = NULL;
02788               PZ_Unlock(lock);
02789               PZ_Lock(slot->slotLock);
02790               --slot->sessionCount;
02791               PZ_Unlock(slot->slotLock);
02792               if (session->info.flags & CKF_RW_SESSION) {
02793                   PR_AtomicDecrement(&slot->rwSessionCount);
02794               }
02795            } else {
02796               PZ_Unlock(lock);
02797            }
02798            if (session) sftk_FreeSession(session);
02799        } while (session != NULL);
02800     }
02801     return CKR_OK;
02802 }
02803 
02804 /*
02805  * shut down the databases.
02806  * we get the slot lock (which also protects slot->certDB and slot->keyDB)
02807  * and clear the values so the new users will not find the databases.
02808  * once things are clear, we can release our references to the databases.
02809  * The databases will close when the last reference is released.
02810  *
02811  * We use reference counts so that we don't crash if someone shuts down
02812  * a token that another thread is actively using.
02813  */
02814 static void
02815 sftk_DBShutdown(SFTKSlot *slot)
02816 {
02817     NSSLOWCERTCertDBHandle *certHandle;
02818     NSSLOWKEYDBHandle      *keyHandle;
02819     PZ_Lock(slot->slotLock);
02820     certHandle = slot->certDB;
02821     slot->certDB = NULL;
02822     keyHandle = slot->keyDB;
02823     slot->keyDB = NULL;
02824     PZ_Unlock(slot->slotLock);
02825     if (certHandle) {
02826        PORT_Assert(certHandle->ref == 1 || slot->slotID > FIPS_SLOT_ID);
02827        sftk_freeCertDB(certHandle);
02828     }
02829     if (keyHandle) {
02830        PORT_Assert(keyHandle->ref == 1 || slot->slotID > FIPS_SLOT_ID);
02831        sftk_freeKeyDB(keyHandle);
02832     }
02833 }
02834 
02835 CK_RV
02836 SFTK_ShutdownSlot(SFTKSlot *slot)
02837 {
02838     /* make sure no new PK11 calls work except C_GetSlotInfo */
02839     slot->present = PR_FALSE;
02840 
02841     /* close all outstanding sessions
02842      * the sessHashSize variable guarentees we have all the session
02843      * mechanism set up */
02844     if (slot->head) {
02845        sft_CloseAllSession(slot);
02846      }
02847 
02848     /* clear all objects.. session objects are cleared as a result of
02849      * closing all the sessions. We just need to clear the token object
02850      * cache. slot->tokObjHashTable guarentees we have the token 
02851      * infrastructure set up. */
02852     if (slot->tokObjHashTable) {
02853        SFTK_ClearTokenKeyHashTable(slot);
02854     }
02855 
02856     /* clear the slot description for the next guy */
02857     PORT_Memset(slot->tokDescription, 0, sizeof(slot->tokDescription));
02858 
02859     /* now shut down the databases. */
02860     sftk_DBShutdown(slot);
02861     return CKR_OK;
02862 }
02863 
02864 /*
02865  * initialize one of the slot structures. figure out which by the ID
02866  */
02867 CK_RV
02868 SFTK_DestroySlotData(SFTKSlot *slot)
02869 {
02870     unsigned int i;
02871 
02872     SFTK_ShutdownSlot(slot);
02873 
02874     if (slot->tokObjHashTable) {
02875        PL_HashTableDestroy(slot->tokObjHashTable);
02876        slot->tokObjHashTable = NULL;
02877     }
02878 
02879     if (slot->sessObjHashTable) {
02880        PORT_Free(slot->sessObjHashTable);
02881        slot->sessObjHashTable = NULL;
02882     }
02883     slot->sessObjHashSize = 0;
02884 
02885     if (slot->head) {
02886        PORT_Free(slot->head);
02887        slot->head = NULL;
02888     }
02889     slot->sessHashSize = 0;
02890 
02891     /* OK everything has been disassembled, now we can finally get rid
02892      * of the locks */
02893     if (slot->slotLock) {
02894        PZ_DestroyLock(slot->slotLock);
02895        slot->slotLock = NULL;
02896     }
02897     if (slot->sessionLock) {
02898        for (i=0; i < slot->numSessionLocks; i++) {
02899            if (slot->sessionLock[i]) {
02900               PZ_DestroyLock(slot->sessionLock[i]);
02901               slot->sessionLock[i] = NULL;
02902            }
02903        }
02904        PORT_Free(slot->sessionLock);
02905        slot->sessionLock = NULL;
02906     }
02907     if (slot->objectLock) {
02908        PZ_DestroyLock(slot->objectLock);
02909        slot->objectLock = NULL;
02910     }
02911     if (slot->pwCheckLock) {
02912        PR_DestroyLock(slot->pwCheckLock);
02913        slot->pwCheckLock = NULL;
02914     }
02915     PORT_Free(slot);
02916     return CKR_OK;
02917 }
02918 
02919 /*
02920  * handle the SECMOD.db
02921  */
02922 char **
02923 NSC_ModuleDBFunc(unsigned long function,char *parameters, void *args)
02924 {
02925     char *secmod = NULL;
02926     char *appName = NULL;
02927     char *filename = NULL;
02928     PRBool rw;
02929     static char *success="Success";
02930     char **rvstr = NULL;
02931 
02932     secmod = secmod_getSecmodName(parameters,&appName,&filename, &rw);
02933 
02934     switch (function) {
02935     case SECMOD_MODULE_DB_FUNCTION_FIND:
02936        rvstr = secmod_ReadPermDB(appName,filename,secmod,(char *)parameters,rw);
02937        break;
02938     case SECMOD_MODULE_DB_FUNCTION_ADD:
02939        rvstr = (secmod_AddPermDB(appName,filename,secmod,(char *)args,rw) 
02940                             == SECSuccess) ? &success: NULL;
02941        break;
02942     case SECMOD_MODULE_DB_FUNCTION_DEL:
02943        rvstr = (secmod_DeletePermDB(appName,filename,secmod,(char *)args,rw)
02944                              == SECSuccess) ? &success: NULL;
02945        break;
02946     case SECMOD_MODULE_DB_FUNCTION_RELEASE:
02947        rvstr = (secmod_ReleasePermDBData(appName,filename,secmod,
02948                      (char **)args,rw) == SECSuccess) ? &success: NULL;
02949        break;
02950     }
02951     if (secmod) PR_smprintf_free(secmod);
02952     if (appName) PORT_Free(appName);
02953     if (filename) PORT_Free(filename);
02954     return rvstr;
02955 }
02956 
02957 static void nscFreeAllSlots(int moduleIndex)
02958 {
02959     /* free all the slots */
02960     SFTKSlot *slot = NULL;
02961     CK_SLOT_ID slotID;
02962     int i;
02963 
02964     if (nscSlotList[moduleIndex]) {
02965        CK_ULONG tmpSlotCount = nscSlotCount[moduleIndex];
02966        CK_SLOT_ID_PTR tmpSlotList = nscSlotList[moduleIndex];
02967        PLHashTable *tmpSlotHashTable = nscSlotHashTable[moduleIndex];
02968 
02969        /* first close all the session */
02970        for (i=0; i < (int) tmpSlotCount; i++) {
02971            slotID = tmpSlotList[i];
02972            (void) NSC_CloseAllSessions(slotID);
02973        }
02974 
02975        /* now clear out the statics */
02976        nscSlotList[moduleIndex] = NULL;
02977        nscSlotCount[moduleIndex] = 0;
02978        nscSlotHashTable[moduleIndex] = NULL;
02979        nscSlotListSize[moduleIndex] = 0;
02980 
02981        for (i=0; i < (int) tmpSlotCount; i++) {
02982            slotID = tmpSlotList[i];
02983            slot = (SFTKSlot *)
02984                      PL_HashTableLookup(tmpSlotHashTable, (void *)slotID);
02985            PORT_Assert(slot);
02986            if (!slot) continue;
02987            SFTK_DestroySlotData(slot);
02988            PL_HashTableRemove(tmpSlotHashTable, (void *)slotID);
02989        }
02990        PORT_Free(tmpSlotList);
02991        PL_HashTableDestroy(tmpSlotHashTable);
02992     }
02993 }
02994 
02995 static void
02996 sftk_closePeer(PRBool isFIPS)
02997 {
02998     CK_SLOT_ID slotID = isFIPS ? PRIVATE_KEY_SLOT_ID: FIPS_SLOT_ID;
02999     SFTKSlot *slot;
03000     int moduleIndex = isFIPS? NSC_NON_FIPS_MODULE : NSC_FIPS_MODULE;
03001     PLHashTable *tmpSlotHashTable = nscSlotHashTable[moduleIndex];
03002 
03003     slot = (SFTKSlot *) PL_HashTableLookup(tmpSlotHashTable, (void *)slotID);
03004     if (slot == NULL) {
03005        return;
03006     }
03007     sftk_DBShutdown(slot);
03008     return;
03009 }
03010 
03011 static PRBool nsc_init = PR_FALSE;
03012 extern SECStatus secoid_Init(void);
03013 
03014 /* NSC_Initialize initializes the Cryptoki library. */
03015 CK_RV nsc_CommonInitialize(CK_VOID_PTR pReserved, PRBool isFIPS)
03016 {
03017     CK_RV crv = CKR_OK;
03018     SECStatus rv;
03019     CK_C_INITIALIZE_ARGS *init_args = (CK_C_INITIALIZE_ARGS *) pReserved;
03020     int i;
03021     int moduleIndex = isFIPS? NSC_FIPS_MODULE : NSC_NON_FIPS_MODULE;
03022 
03023 
03024     if (isFIPS) {
03025        loginWaitTime = PR_SecondsToInterval(1);
03026     }
03027 
03028     rv = secoid_Init();
03029     if (rv != SECSuccess) {
03030        crv = CKR_DEVICE_ERROR;
03031        return crv;
03032     }
03033 
03034     rv = RNG_RNGInit();         /* initialize random number generator */
03035     if (rv != SECSuccess) {
03036        crv = CKR_DEVICE_ERROR;
03037        return crv;
03038     }
03039     RNG_SystemInfoForRNG();
03040 
03041     rv = nsslowcert_InitLocks();
03042     if (rv != SECSuccess) {
03043        crv = CKR_DEVICE_ERROR;
03044        return crv;
03045     }
03046 
03047 
03048     /* NOTE:
03049      * we should be getting out mutexes from this list, not statically binding
03050      * them from NSPR. This should happen before we allow the internal to split
03051      * off from the rest on NSS.
03052      */
03053 
03054     /* initialize the key and cert db's */
03055     nsslowkey_SetDefaultKeyDBAlg
03056                           (SEC_OID_PKCS12_PBE_WITH_SHA1_AND_TRIPLE_DES_CBC);
03057     if (init_args && (!(init_args->flags & CKF_OS_LOCKING_OK))) {
03058         if (init_args->CreateMutex && init_args->DestroyMutex &&
03059             init_args->LockMutex && init_args->UnlockMutex) {
03060             /* softoken always uses NSPR (ie. OS locking), and doesn't know how
03061              * to use the lock functions provided by the application.
03062              */
03063             crv = CKR_CANT_LOCK;
03064             return crv;
03065         }
03066         if (init_args->CreateMutex || init_args->DestroyMutex ||
03067             init_args->LockMutex || init_args->UnlockMutex) {
03068             /* only some of the lock functions were provided by the
03069              * application. This is invalid per PKCS#11 spec.
03070              */
03071             crv = CKR_ARGUMENTS_BAD;
03072             return crv;
03073         }
03074     }
03075     crv = CKR_ARGUMENTS_BAD;
03076     if ((init_args && init_args->LibraryParameters)) {
03077        sftk_parameters paramStrings;
03078        
03079        crv = secmod_parseParameters
03080               ((char *)init_args->LibraryParameters, &paramStrings, isFIPS);
03081        if (crv != CKR_OK) {
03082            return crv;
03083        }
03084        crv = sftk_configure(paramStrings.man, paramStrings.libdes);
03085         if (crv != CKR_OK) {
03086            goto loser;
03087        }
03088 
03089        /* if we have a peer already open, have him close his DB's so we
03090         * don't clobber each other. */
03091        if ((isFIPS && nsc_init) || (!isFIPS && nsf_init)) {
03092            sftk_closePeer(isFIPS);
03093            if (sftk_audit_enabled) {
03094               if (isFIPS && nsc_init) {
03095                   sftk_LogAuditMessage(NSS_AUDIT_INFO, "enabled FIPS mode");
03096               } else {
03097                   sftk_LogAuditMessage(NSS_AUDIT_INFO, "disabled FIPS mode");
03098               }
03099            }
03100        }
03101 
03102        for (i=0; i < paramStrings.token_count; i++) {
03103            crv = SFTK_SlotInit(paramStrings.configdir, 
03104                      &paramStrings.tokens[i],
03105                      moduleIndex);
03106            if (crv != CKR_OK) {
03107                 nscFreeAllSlots(moduleIndex);
03108                 break;
03109             }
03110        }
03111 loser:
03112        secmod_freeParams(&paramStrings);
03113     }
03114     if (CKR_OK == crv) {
03115         sftk_InitFreeLists();
03116     }
03117 
03118     return crv;
03119 }
03120 
03121 CK_RV NSC_Initialize(CK_VOID_PTR pReserved)
03122 {
03123     CK_RV crv;
03124     if (nsc_init) {
03125        return CKR_CRYPTOKI_ALREADY_INITIALIZED;
03126     }
03127     crv = nsc_CommonInitialize(pReserved,PR_FALSE);
03128     nsc_init = (PRBool) (crv == CKR_OK);
03129     return crv;
03130 }
03131 
03132 extern SECStatus SECOID_Shutdown(void);
03133 
03134 /* NSC_Finalize indicates that an application is done with the 
03135  * Cryptoki library.*/
03136 CK_RV nsc_CommonFinalize (CK_VOID_PTR pReserved, PRBool isFIPS)
03137 {
03138     
03139 
03140     nscFreeAllSlots(isFIPS ? NSC_FIPS_MODULE : NSC_NON_FIPS_MODULE);
03141 
03142     /* don't muck with the globals is our peer is still initialized */
03143     if (isFIPS && nsc_init) {
03144        return CKR_OK;
03145     }
03146     if (!isFIPS && nsf_init) {
03147        return CKR_OK;
03148     }
03149 
03150     sftk_CleanupFreeLists();
03151     nsslowcert_DestroyFreeLists();
03152     nsslowcert_DestroyGlobalLocks();
03153 
03154     /* This function does not discard all our previously aquired entropy. */
03155     RNG_RNGShutdown();
03156 
03157     /* tell freeBL to clean up after itself */
03158     BL_Cleanup();
03159     /* unload freeBL shared library from memory */
03160     BL_Unload();
03161     /* clean up the default OID table */
03162     SECOID_Shutdown();
03163     nsc_init = PR_FALSE;
03164 
03165     return CKR_OK;
03166 }
03167 
03168 /* NSC_Finalize indicates that an application is done with the 
03169  * Cryptoki library.*/
03170 CK_RV NSC_Finalize (CK_VOID_PTR pReserved)
03171 {
03172     CK_RV crv;
03173 
03174     if (!nsc_init) {
03175        return CKR_OK;
03176     }
03177 
03178     crv = nsc_CommonFinalize (pReserved, PR_FALSE);
03179 
03180     nsc_init = (PRBool) !(crv == CKR_OK);
03181 
03182     return crv;
03183 }
03184 
03185 extern const char __nss_softokn_rcsid[];
03186 extern const char __nss_softokn_sccsid[];
03187 
03188 /* NSC_GetInfo returns general information about Cryptoki. */
03189 CK_RV  NSC_GetInfo(CK_INFO_PTR pInfo)
03190 {
03191     volatile char c; /* force a reference that won't get optimized away */
03192 
03193     c = __nss_softokn_rcsid[0] + __nss_softokn_sccsid[0]; 
03194     pInfo->cryptokiVersion.major = 2;
03195     pInfo->cryptokiVersion.minor = 20;
03196     PORT_Memcpy(pInfo->manufacturerID,manufacturerID,32);
03197     pInfo->libraryVersion.major = SOFTOKEN_VMAJOR;
03198     pInfo->libraryVersion.minor = SOFTOKEN_VMINOR;
03199     PORT_Memcpy(pInfo->libraryDescription,libraryDescription,32);
03200     pInfo->flags = 0;
03201     return CKR_OK;
03202 }
03203 
03204 
03205 /* NSC_GetSlotList obtains a list of slots in the system. */
03206 CK_RV nsc_CommonGetSlotList(CK_BBOOL tokenPresent, 
03207        CK_SLOT_ID_PTR       pSlotList, CK_ULONG_PTR pulCount, int moduleIndex)
03208 {
03209     *pulCount = nscSlotCount[moduleIndex];
03210     if (pSlotList != NULL) {
03211        PORT_Memcpy(pSlotList,nscSlotList[moduleIndex],
03212                             nscSlotCount[moduleIndex]*sizeof(CK_SLOT_ID));
03213     }
03214     return CKR_OK;
03215 }
03216 
03217 /* NSC_GetSlotList obtains a list of slots in the system. */
03218 CK_RV NSC_GetSlotList(CK_BBOOL tokenPresent,
03219                      CK_SLOT_ID_PTR       pSlotList, CK_ULONG_PTR pulCount)
03220 {
03221     return nsc_CommonGetSlotList(tokenPresent, pSlotList, pulCount, 
03222                                                  NSC_NON_FIPS_MODULE);
03223 }
03224        
03225 /* NSC_GetSlotInfo obtains information about a particular slot in the system. */
03226 CK_RV NSC_GetSlotInfo(CK_SLOT_ID slotID, CK_SLOT_INFO_PTR pInfo)
03227 {
03228     SFTKSlot *slot = sftk_SlotFromID(slotID, PR_TRUE);
03229     if (slot == NULL) return CKR_SLOT_ID_INVALID;
03230 
03231     pInfo->firmwareVersion.major = 0;
03232     pInfo->firmwareVersion.minor = 0;
03233 
03234     PORT_Memcpy(pInfo->manufacturerID,manufacturerID,32);
03235     PORT_Memcpy(pInfo->slotDescription,slot->slotDescription,64);
03236     pInfo->flags = (slot->present) ? CKF_TOKEN_PRESENT : 0;
03237     /* all user defined slots are defined as removable */
03238     if (slotID >= SFTK_MIN_USER_SLOT_ID) {
03239        pInfo->flags |= CKF_REMOVABLE_DEVICE;
03240     }
03241     /* ok we really should read it out of the keydb file. */
03242     /* pInfo->hardwareVersion.major = NSSLOWKEY_DB_FILE_VERSION; */
03243     pInfo->hardwareVersion.major = SOFTOKEN_VMAJOR;
03244     pInfo->hardwareVersion.minor = SOFTOKEN_VMINOR;
03245     return CKR_OK;
03246 }
03247 
03248 /*
03249  * check the current state of the 'needLogin' flag in case the database has
03250  * been changed underneath us.
03251  */
03252 static PRBool
03253 sftk_checkNeedLogin(SFTKSlot *slot, NSSLOWKEYDBHandle *keyHandle)
03254 {
03255     if (slot->password) {
03256        SECStatus rv;
03257        rv = nsslowkey_CheckKeyDBPassword(keyHandle,slot->password);
03258        if ( rv == SECSuccess) {
03259            return slot->needLogin;
03260        } else {
03261            SECITEM_FreeItem(slot->password, PR_TRUE);
03262            slot->password = NULL;
03263            slot->isLoggedIn = PR_FALSE;
03264        }
03265     }
03266     slot->needLogin = 
03267               (PRBool)!sftk_hasNullPassword(keyHandle,&slot->password);
03268     return (slot->needLogin);
03269 }
03270 
03271 /* NSC_GetTokenInfo obtains information about a particular token in 
03272  * the system. */
03273 CK_RV NSC_GetTokenInfo(CK_SLOT_ID slotID,CK_TOKEN_INFO_PTR pInfo)
03274 {
03275     SFTKSlot *slot; 
03276     NSSLOWKEYDBHandle *handle;
03277 
03278     if (!nsc_init && !nsf_init) return CKR_CRYPTOKI_NOT_INITIALIZED;
03279     slot = sftk_SlotFromID(slotID, PR_FALSE);
03280     if (slot == NULL) return CKR_SLOT_ID_INVALID;
03281 
03282     PORT_Memcpy(pInfo->manufacturerID,manufacturerID,32);
03283     PORT_Memcpy(pInfo->model,"NSS 3           ",16);
03284     PORT_Memcpy(pInfo->serialNumber,"0000000000000000",16);
03285     PORT_Memcpy(pInfo->utcTime,"0000000000000000",16);
03286     pInfo->ulMaxSessionCount = 0; /* arbitrarily large */
03287     pInfo->ulSessionCount = slot->sessionCount;
03288     pInfo->ulMaxRwSessionCount = 0; /* arbitarily large */
03289     pInfo->ulRwSessionCount = slot->rwSessionCount;
03290     pInfo->firmwareVersion.major = 0;
03291     pInfo->firmwareVersion.minor = 0;
03292     PORT_Memcpy(pInfo->label,slot->tokDescription,32);
03293     handle = sftk_getKeyDB(slot);
03294     pInfo->flags = CKF_RNG | CKF_DUAL_CRYPTO_OPERATIONS;
03295     if (handle == NULL) {
03296        pInfo->flags |= CKF_WRITE_PROTECTED;
03297        pInfo->ulMaxPinLen = 0;
03298        pInfo->ulMinPinLen = 0;
03299        pInfo->ulTotalPublicMemory = 0;
03300        pInfo->ulFreePublicMemory = 0;
03301        pInfo->ulTotalPrivateMemory = 0;
03302        pInfo->ulFreePrivateMemory = 0;
03303        pInfo->hardwareVersion.major = 4;
03304        pInfo->hardwareVersion.minor = 0;
03305     } else {
03306        /*
03307         * we have three possible states which we may be in:
03308         *   (1) No DB password has been initialized. This also means we
03309         *   have no keys in the key db.
03310         *   (2) Password initialized to NULL. This means we have keys, but
03311         *   the user has chosen not use a password.
03312         *   (3) Finally we have an initialized password whicn is not NULL, and
03313         *   we will need to prompt for it.
03314         */
03315        if (nsslowkey_HasKeyDBPassword(handle) == SECFailure) {
03316            pInfo->flags |= CKF_LOGIN_REQUIRED;
03317        } else if (!sftk_checkNeedLogin(slot,handle)) {
03318            pInfo->flags |= CKF_USER_PIN_INITIALIZED;
03319        } else {
03320            pInfo->flags |= CKF_LOGIN_REQUIRED | CKF_USER_PIN_INITIALIZED;
03321        }
03322        pInfo->ulMaxPinLen = SFTK_MAX_PIN;
03323        pInfo->ulMinPinLen = (CK_ULONG)slot->minimumPinLen;
03324        pInfo->ulTotalPublicMemory = 1;
03325        pInfo->ulFreePublicMemory = 1;
03326        pInfo->ulTotalPrivateMemory = 1;
03327        pInfo->ulFreePrivateMemory = 1;
03328        pInfo->hardwareVersion.major = CERT_DB_FILE_VERSION;
03329        pInfo->hardwareVersion.minor = handle->version;
03330         sftk_freeKeyDB(handle);
03331     }
03332     /*
03333      * CKF_LOGIN_REQUIRED CKF_USER_PIN_INITIALIZED  how CKF_TOKEN_INITIALIZED
03334      *                                              should be set
03335      *         0                   0                           1
03336      *         1                   0                           0
03337      *         0                   1                           1
03338      *         1                   1                           1
03339      */
03340     if (!(pInfo->flags & CKF_LOGIN_REQUIRED) ||
03341        (pInfo->flags & CKF_USER_PIN_INITIALIZED)) {
03342        pInfo->flags |= CKF_TOKEN_INITIALIZED;
03343     }
03344     return CKR_OK;
03345 }
03346 
03347 /* NSC_GetMechanismList obtains a list of mechanism types 
03348  * supported by a token. */
03349 CK_RV NSC_GetMechanismList(CK_SLOT_ID slotID,
03350        CK_MECHANISM_TYPE_PTR pMechanismList, CK_ULONG_PTR pulCount)
03351 {
03352     CK_ULONG i;
03353 
03354     switch (slotID) {
03355     /* default: */
03356     case NETSCAPE_SLOT_ID:
03357        *pulCount = mechanismCount;
03358        if (pMechanismList != NULL) {
03359            for (i=0; i < mechanismCount; i++) {
03360               pMechanismList[i] = mechanisms[i].type;
03361            }
03362        }
03363        break;
03364      default:
03365        *pulCount = 0;
03366        for (i=0; i < mechanismCount; i++) {
03367            if (mechanisms[i].privkey) {
03368               (*pulCount)++;
03369               if (pMechanismList != NULL) {
03370                   *pMechanismList++ = mechanisms[i].type;
03371               }
03372            }
03373        }
03374        break;
03375     }
03376     return CKR_OK;
03377 }
03378 
03379 
03380 /* NSC_GetMechanismInfo obtains information about a particular mechanism 
03381  * possibly supported by a token. */
03382 CK_RV NSC_GetMechanismInfo(CK_SLOT_ID slotID, CK_MECHANISM_TYPE type,
03383                                    CK_MECHANISM_INFO_PTR pInfo)
03384 {
03385     PRBool isPrivateKey;
03386     CK_ULONG i;
03387 
03388     switch (slotID) {
03389     case NETSCAPE_SLOT_ID:
03390        isPrivateKey = PR_FALSE;
03391        break;
03392     default:
03393        isPrivateKey = PR_TRUE;
03394        break;
03395     }
03396     for (i=0; i < mechanismCount; i++) {
03397         if (type == mechanisms[i].type) {
03398            if (isPrivateKey && !mechanisms[i].privkey) {
03399               return CKR_MECHANISM_INVALID;
03400            }
03401            PORT_Memcpy(pInfo,&mechanisms[i].info, sizeof(CK_MECHANISM_INFO));
03402            return CKR_OK;
03403        }
03404     }
03405     return CKR_MECHANISM_INVALID;
03406 }
03407 
03408 CK_RV sftk_MechAllowsOperation(CK_MECHANISM_TYPE type, CK_ATTRIBUTE_TYPE op)
03409 {
03410     CK_ULONG i;
03411     CK_FLAGS flags;
03412 
03413     switch (op) {
03414     case CKA_ENCRYPT:         flags = CKF_ENCRYPT;         break;
03415     case CKA_DECRYPT:         flags = CKF_DECRYPT;         break;
03416     case CKA_WRAP:            flags = CKF_WRAP;            break;
03417     case CKA_UNWRAP:          flags = CKF_UNWRAP;          break;
03418     case CKA_SIGN:            flags = CKF_SIGN;            break;
03419     case CKA_SIGN_RECOVER:    flags = CKF_SIGN_RECOVER;    break;
03420     case CKA_VERIFY:          flags = CKF_VERIFY;          break;
03421     case CKA_VERIFY_RECOVER:  flags = CKF_VERIFY_RECOVER;  break;
03422     case CKA_DERIVE:          flags = CKF_DERIVE;          break;
03423     default:
03424        return CKR_ARGUMENTS_BAD;
03425     }
03426     for (i=0; i < mechanismCount; i++) {
03427         if (type == mechanisms[i].type) {
03428            return (flags & mechanisms[i].info.flags) ? CKR_OK 
03429                                                      : CKR_MECHANISM_INVALID;
03430        }
03431     }
03432     return CKR_MECHANISM_INVALID;
03433 }
03434 
03435 
03436 static SECStatus
03437 sftk_TurnOffUser(NSSLOWCERTCertificate *cert, SECItem *k, void *arg)
03438 {
03439    NSSLOWCERTCertTrust trust;
03440    SECStatus rv;
03441 
03442    rv = nsslowcert_GetCertTrust(cert,&trust);
03443    if (rv == SECSuccess && ((trust.emailFlags & CERTDB_USER) ||
03444                          (trust.sslFlags & CERTDB_USER) ||
03445                          (trust.objectSigningFlags & CERTDB_USER))) {
03446        trust.emailFlags &= ~CERTDB_USER;
03447        trust.sslFlags &= ~CERTDB_USER;
03448        trust.objectSigningFlags &= ~CERTDB_USER;
03449        nsslowcert_ChangeCertTrust(cert->dbhandle,cert,&trust);
03450    }
03451    return SECSuccess;
03452 }
03453 
03454 /* NSC_InitToken initializes a token. */
03455 CK_RV NSC_InitToken(CK_SLOT_ID slotID,CK_CHAR_PTR pPin,
03456                             CK_ULONG ulPinLen,CK_CHAR_PTR pLabel) {
03457     SFTKSlot *slot = sftk_SlotFromID(slotID, PR_FALSE);
03458     NSSLOWKEYDBHandle *handle;
03459     NSSLOWCERTCertDBHandle *certHandle;
03460     SECStatus rv;
03461     unsigned int i;
03462     SFTKObject *object;
03463 
03464     if (slot == NULL) return CKR_SLOT_ID_INVALID;
03465 
03466     /* don't initialize the database if we aren't talking to a token
03467      * that uses the key database.
03468      */
03469     if (slotID == NETSCAPE_SLOT_ID) {
03470        return CKR_TOKEN_WRITE_PROTECTED;
03471     }
03472 
03473     /* first, delete all our loaded key and cert objects from our 
03474      * internal list. */
03475     PZ_Lock(slot->objectLock);
03476     for (i=0; i < slot->sessObjHashSize; i++) {
03477        do {
03478            object = slot->sessObjHashTable[i];
03479            /* hand deque */
03480            /* this duplicates function of NSC_close session functions, but 
03481             * because we know that we are freeing all the sessions, we can
03482             * do more efficient processing */
03483            if (object) {
03484               slot->sessObjHashTable[i] = object->next;
03485 
03486               if (object->next) object->next->prev = NULL;
03487               object->next = object->prev = NULL;
03488            }
03489            if (object) sftk_FreeObject(object);
03490        } while (object != NULL);
03491     }
03492     slot->DB_loaded = PR_FALSE;
03493     PZ_Unlock(slot->objectLock);
03494 
03495     /* then clear out the key database */
03496     handle = sftk_getKeyDB(slot);
03497     if (handle == NULL) {
03498        return CKR_TOKEN_WRITE_PROTECTED;
03499     }
03500 
03501     rv = nsslowkey_ResetKeyDB(handle);
03502     sftk_freeKeyDB(handle);
03503     if (rv != SECSuccess) {
03504        return CKR_DEVICE_ERROR;
03505     }
03506 
03507     /* finally  mark all the user certs as non-user certs */
03508     certHandle = sftk_getCertDB(slot);
03509     if (certHandle == NULL) return CKR_OK;
03510 
03511     nsslowcert_TraversePermCerts(certHandle,sftk_TurnOffUser, NULL);
03512     sftk_freeCertDB(certHandle);
03513 
03514     return CKR_OK; /*is this the right function for not implemented*/
03515 }
03516 
03517 
03518 /* NSC_InitPIN initializes the normal user's PIN. */
03519 CK_RV NSC_InitPIN(CK_SESSION_HANDLE hSession,
03520                                    CK_CHAR_PTR pPin, CK_ULONG ulPinLen)
03521 {
03522     SFTKSession *sp = NULL;
03523     SFTKSlot *slot;
03524     NSSLOWKEYDBHandle *handle = NULL;
03525     SECItem *newPin;
03526     char newPinStr[SFTK_MAX_PIN+1];
03527     SECStatus rv;
03528     CK_RV crv = CKR_SESSION_HANDLE_INVALID;
03529 
03530     
03531     sp = sftk_SessionFromHandle(hSession);
03532     if (sp == NULL) {
03533        goto loser;
03534     }
03535 
03536     slot = sftk_SlotFromSession(sp);
03537     if (slot == NULL) {
03538        goto loser;
03539     }
03540 
03541     handle = sftk_getKeyDB(slot);
03542     if (handle == NULL) {
03543        crv = CKR_PIN_LEN_RANGE;
03544        goto loser;
03545     }
03546 
03547 
03548     if (sp->info.state != CKS_RW_SO_FUNCTIONS) {
03549        crv = CKR_USER_NOT_LOGGED_IN;
03550        goto loser;
03551     }
03552 
03553     sftk_FreeSession(sp);
03554     sp = NULL;
03555 
03556     /* make sure the pins aren't too long */
03557     if (ulPinLen > SFTK_MAX_PIN) {
03558        crv = CKR_PIN_LEN_RANGE;
03559        goto loser;
03560     }
03561     if (ulPinLen < (CK_ULONG)slot->minimumPinLen) {
03562        crv = CKR_PIN_LEN_RANGE;
03563        goto loser;
03564     }
03565 
03566     if (nsslowkey_HasKeyDBPassword(handle) != SECFailure) {
03567        crv = CKR_DEVICE_ERROR;
03568        goto loser;
03569     }
03570 
03571     /* convert to null terminated string */
03572     PORT_Memcpy(newPinStr,pPin,ulPinLen);
03573     newPinStr[ulPinLen] = 0; 
03574 
03575     /* build the hashed pins which we pass around */
03576     newPin = nsslowkey_HashPassword(newPinStr,handle->global_salt);
03577     PORT_Memset(newPinStr,0,sizeof(newPinStr));
03578 
03579     /* change the data base */
03580     rv = nsslowkey_SetKeyDBPassword(handle,newPin);
03581     sftk_freeKeyDB(handle);
03582     handle = NULL;
03583 
03584     /* Now update our local copy of the pin */
03585     if (rv == SECSuccess) {
03586        if (slot->password) {
03587            SECITEM_ZfreeItem(slot->password, PR_TRUE);
03588        }
03589        slot->password = newPin;
03590        if (ulPinLen == 0) slot->needLogin = PR_FALSE;
03591        return CKR_OK;
03592     }
03593     SECITEM_ZfreeItem(newPin, PR_TRUE);
03594     crv = CKR_PIN_INCORRECT;
03595 
03596 loser:
03597     if (sp) {
03598        sftk_FreeSession(sp);
03599     }
03600     if (handle) {
03601        sftk_freeKeyDB(handle);
03602     }
03603     return crv;
03604 }
03605 
03606 
03607 /* NSC_SetPIN modifies the PIN of user that is currently logged in. */
03608 /* NOTE: This is only valid for the PRIVATE_KEY_SLOT */
03609 CK_RV NSC_SetPIN(CK_SESSION_HANDLE hSession, CK_CHAR_PTR pOldPin,
03610     CK_ULONG ulOldLen, CK_CHAR_PTR pNewPin, CK_ULONG ulNewLen)
03611 {
03612     SFTKSession *sp = NULL;
03613     SFTKSlot *slot;
03614     NSSLOWKEYDBHandle *handle = NULL;
03615     SECItem *newPin;
03616     SECItem *oldPin;
03617     char newPinStr[SFTK_MAX_PIN+1],oldPinStr[SFTK_MAX_PIN+1];
03618     SECStatus rv;
03619     CK_RV crv = CKR_SESSION_HANDLE_INVALID;
03620 
03621     
03622     sp = sftk_SessionFromHandle(hSession);
03623     if (sp == NULL) {
03624        goto loser;
03625     }
03626 
03627     slot = sftk_SlotFromSession(sp);
03628     if (!slot) {
03629        goto loser;
03630     }
03631 
03632     handle = sftk_getKeyDB(slot);
03633     if (handle == NULL) {
03634        sftk_FreeSession(sp);
03635        return CKR_PIN_LEN_RANGE; /* XXX FIXME wrong return value */
03636     }
03637 
03638     if (slot->needLogin && sp->info.state != CKS_RW_USER_FUNCTIONS) {
03639        crv = CKR_USER_NOT_LOGGED_IN;
03640        goto loser;
03641     }
03642 
03643     sftk_FreeSession(sp);
03644     sp = NULL;
03645 
03646     /* make sure the pins aren't too long */
03647     if ((ulNewLen > SFTK_MAX_PIN) || (ulOldLen > SFTK_MAX_PIN)) {
03648        crv = CKR_PIN_LEN_RANGE;
03649        goto loser;
03650     }
03651     if (ulNewLen < (CK_ULONG)slot->minimumPinLen) {
03652        crv = CKR_PIN_LEN_RANGE;
03653        goto loser;
03654     }
03655 
03656 
03657     /* convert to null terminated string */
03658     PORT_Memcpy(newPinStr,pNewPin,ulNewLen);
03659     newPinStr[ulNewLen] = 0; 
03660     PORT_Memcpy(oldPinStr,pOldPin,ulOldLen);
03661     oldPinStr[ulOldLen] = 0; 
03662 
03663     /* build the hashed pins which we pass around */
03664     newPin = nsslowkey_HashPassword(newPinStr,handle->global_salt);
03665     oldPin = nsslowkey_HashPassword(oldPinStr,handle->global_salt);
03666     PORT_Memset(newPinStr,0,sizeof(newPinStr));
03667     PORT_Memset(oldPinStr,0,sizeof(oldPinStr));
03668 
03669     /* change the data base password */
03670     PR_Lock(slot->pwCheckLock);
03671     rv = nsslowkey_ChangeKeyDBPassword(handle,oldPin,newPin);
03672     sftk_freeKeyDB(handle);
03673     handle = NULL;
03674     if ((rv != SECSuccess) && (slot->slotID == FIPS_SLOT_ID)) {
03675        PR_Sleep(loginWaitTime);
03676     }
03677     PR_Unlock(slot->pwCheckLock);
03678 
03679     /* Now update our local copy of the pin */
03680     SECITEM_ZfreeItem(oldPin, PR_TRUE);
03681     if (rv == SECSuccess) {
03682        if (slot->password) {
03683            SECITEM_ZfreeItem(slot->password, PR_TRUE);
03684        }
03685        slot->password = newPin;
03686        slot->needLogin = (PRBool)(ulNewLen != 0);
03687        return CKR_OK;
03688     }
03689     SECITEM_ZfreeItem(newPin, PR_TRUE);
03690     crv = CKR_PIN_INCORRECT;
03691 loser:
03692     if (sp) {
03693        sftk_FreeSession(sp);
03694     }
03695     if (handle) {
03696        sftk_freeKeyDB(handle);
03697     }
03698     return crv;
03699 }
03700 
03701 /* NSC_OpenSession opens a session between an application and a token. */
03702 CK_RV NSC_OpenSession(CK_SLOT_ID slotID, CK_FLAGS flags,
03703    CK_VOID_PTR pApplication,CK_NOTIFY Notify,CK_SESSION_HANDLE_PTR phSession)
03704 {
03705     SFTKSlot *slot;
03706     CK_SESSION_HANDLE sessionID;
03707     SFTKSession *session;
03708     SFTKSession *sameID;
03709 
03710     slot = sftk_SlotFromID(slotID, PR_FALSE);
03711     if (slot == NULL) return CKR_SLOT_ID_INVALID;
03712 
03713     /* new session (we only have serial sessions) */
03714     session = sftk_NewSession(slotID, Notify, pApplication,
03715                                            flags | CKF_SERIAL_SESSION);
03716     if (session == NULL) return CKR_HOST_MEMORY;
03717 
03718     if (slot->readOnly && (flags & CKF_RW_SESSION)) {
03719        /* NETSCAPE_SLOT_ID is Read ONLY */
03720        session->info.flags &= ~CKF_RW_SESSION;
03721     }
03722     PZ_Lock(slot->slotLock);
03723     ++slot->sessionCount;
03724     PZ_Unlock(slot->slotLock);
03725     if (session->info.flags & CKF_RW_SESSION) {
03726        PR_AtomicIncrement(&slot->rwSessionCount);
03727     }
03728 
03729     do {
03730         PZLock *lock;
03731         do {
03732             sessionID = (PR_AtomicIncrement(&slot->sessionIDCount) & 0xffffff)
03733                         | (slot->index << 24);
03734         } while (sessionID == CK_INVALID_HANDLE);
03735         lock = SFTK_SESSION_LOCK(slot,sessionID);
03736         PZ_Lock(lock);
03737         sftkqueue_find(sameID, sessionID, slot->head, slot->sessHashSize);
03738         if (sameID == NULL) {
03739             session->handle = sessionID;
03740             sftk_update_state(slot, session);
03741             sftkqueue_add(session, sessionID, slot->head,slot->sessHashSize);
03742         } else {
03743             slot->sessionIDConflict++;  /* for debugging */
03744         }
03745         PZ_Unlock(lock);
03746     } while (sameID != NULL);
03747 
03748     *phSession = sessionID;
03749     return CKR_OK;
03750 }
03751 
03752 
03753 /* NSC_CloseSession closes a session between an application and a token. */
03754 CK_RV NSC_CloseSession(CK_SESSION_HANDLE hSession)
03755 {
03756     SFTKSlot *slot;
03757     SFTKSession *session;
03758     SECItem *pw = NULL;
03759     PRBool sessionFound;
03760     PZLock *lock;
03761 
03762     session = sftk_SessionFromHandle(hSession);
03763     if (session == NULL) return CKR_SESSION_HANDLE_INVALID;
03764     slot = sftk_SlotFromSession(session);
03765     sessionFound = PR_FALSE;
03766 
03767     /* lock */
03768     lock = SFTK_SESSION_LOCK(slot,hSession);
03769     PZ_Lock(lock);
03770     if (sftkqueue_is_queued(session,hSession,slot->head,slot->sessHashSize)) {
03771        sessionFound = PR_TRUE;
03772        sftkqueue_delete(session,hSession,slot->head,slot->sessHashSize);
03773        session->refCount--; /* can't go to zero while we hold the reference */
03774        PORT_Assert(session->refCount > 0);
03775     }
03776     PZ_Unlock(lock);
03777 
03778     if (sessionFound) {
03779        PZ_Lock(slot->slotLock);
03780        if (--slot->sessionCount == 0) {
03781            pw = slot->password;
03782            slot->isLoggedIn = PR_FALSE;
03783            slot->password = NULL;
03784        }
03785        PZ_Unlock(slot->slotLock);
03786        if (session->info.flags & CKF_RW_SESSION) {
03787            PR_AtomicDecrement(&slot->rwSessionCount);
03788        }
03789     }
03790 
03791     sftk_FreeSession(session);
03792     if (pw) SECITEM_ZfreeItem(pw, PR_TRUE);
03793     return CKR_OK;
03794 }
03795 
03796 
03797 /* NSC_CloseAllSessions closes all sessions with a token. */
03798 CK_RV NSC_CloseAllSessions (CK_SLOT_ID slotID)
03799 {
03800     SFTKSlot *slot;
03801 
03802     slot = sftk_SlotFromID(slotID, PR_FALSE);
03803     if (slot == NULL) return CKR_SLOT_ID_INVALID;
03804 
03805     return sft_CloseAllSession(slot);
03806 }
03807 
03808 
03809 
03810 /* NSC_GetSessionInfo obtains information about the session. */
03811 CK_RV NSC_GetSessionInfo(CK_SESSION_HANDLE hSession,
03812                                           CK_SESSION_INFO_PTR pInfo)
03813 {
03814     SFTKSession *session;
03815 
03816     session = sftk_SessionFromHandle(hSession);
03817     if (session == NULL) return CKR_SESSION_HANDLE_INVALID;
03818 
03819     PORT_Memcpy(pInfo,&session->info,sizeof(CK_SESSION_INFO));
03820     sftk_FreeSession(session);
03821     return CKR_OK;
03822 }
03823 
03824 /* NSC_Login logs a user into a token. */
03825 CK_RV NSC_Login(CK_SESSION_HANDLE hSession, CK_USER_TYPE userType,
03826                                 CK_CHAR_PTR pPin, CK_ULONG ulPinLen)
03827 {
03828     SFTKSlot *slot;
03829     SFTKSession *session;
03830     NSSLOWKEYDBHandle *handle;
03831     CK_FLAGS sessionFlags;
03832     SECStatus rv;
03833     CK_RV crv;
03834     SECItem *pin;
03835     char pinStr[SFTK_MAX_PIN+1];
03836 
03837 
03838     /* get the slot */
03839     slot = sftk_SlotFromSessionHandle(hSession);
03840 
03841     /* make sure the session is valid */
03842     session = sftk_SessionFromHandle(hSession);
03843     if (session == NULL) {
03844        return CKR_SESSION_HANDLE_INVALID;
03845     }
03846     sessionFlags = session->info.flags;
03847     sftk_FreeSession(session);
03848     session = NULL;
03849 
03850     /* can't log into the Netscape Slot */
03851     if (slot->slotID == NETSCAPE_SLOT_ID) {
03852         return CKR_USER_TYPE_INVALID;
03853     }
03854 
03855     if (slot->isLoggedIn) return CKR_USER_ALREADY_LOGGED_IN;
03856     slot->ssoLoggedIn = PR_FALSE;
03857 
03858     if (ulPinLen > SFTK_MAX_PIN) return CKR_PIN_LEN_RANGE;
03859 
03860     /* convert to null terminated string */
03861     PORT_Memcpy(pinStr,pPin,ulPinLen);
03862     pinStr[ulPinLen] = 0; 
03863 
03864     handle = sftk_getKeyDB(slot);
03865     if (handle == NULL) {
03866         return CKR_USER_TYPE_INVALID;
03867     }
03868 
03869     /*
03870      * Deal with bootstrap. We allow the SSO to login in with a NULL
03871      * password if and only if we haven't initialized the KEY DB yet.
03872      * We only allow this on a RW session.
03873      */
03874     rv = nsslowkey_HasKeyDBPassword(handle);
03875     if (rv == SECFailure) {
03876        /* allow SSO's to log in only if there is not password on the
03877         * key database */
03878        if (((userType == CKU_SO) && (sessionFlags & CKF_RW_SESSION))
03879            /* fips always needs to authenticate, even if there isn't a db */
03880                                    || (slot->slotID == FIPS_SLOT_ID)) {
03881            /* should this be a fixed password? */
03882            if (ulPinLen == 0) {
03883               SECItem *pw;
03884               PZ_Lock(slot->slotLock);
03885               pw = slot->password;
03886               slot->password = NULL;
03887               slot->isLoggedIn = PR_TRUE;
03888               slot->ssoLoggedIn = (PRBool)(userType == CKU_SO);
03889               PZ_Unlock(slot->slotLock);
03890               sftk_update_all_states(slot);
03891               SECITEM_ZfreeItem(pw,PR_TRUE);
03892               crv = CKR_OK;
03893               goto done;
03894            }
03895            crv = CKR_PIN_INCORRECT;
03896            goto done;
03897        } 
03898        crv = CKR_USER_TYPE_INVALID;
03899        goto done;
03900     } 
03901 
03902     /* don't allow the SSO to log in if the user is already initialized */
03903     if (userType != CKU_USER) { 
03904        crv = CKR_USER_TYPE_INVALID; 
03905        goto done;
03906     }
03907 
03908 
03909     /* build the hashed pins which we pass around */
03910     pin = nsslowkey_HashPassword(pinStr,handle->global_salt);
03911     if (pin == NULL) {
03912        crv = CKR_HOST_MEMORY;
03913        goto done;
03914     }
03915 
03916     PR_Lock(slot->pwCheckLock);
03917     rv = nsslowkey_CheckKeyDBPassword(handle,pin);
03918     sftk_freeKeyDB(handle);
03919     handle = NULL;
03920     if ((rv != SECSuccess) && (slot->slotID == FIPS_SLOT_ID)) {
03921        PR_Sleep(loginWaitTime);
03922     }
03923     PR_Unlock(slot->pwCheckLock);
03924     if (rv == SECSuccess) {
03925        SECItem *tmp;
03926        PZ_Lock(slot->slotLock);
03927        tmp = slot->password;
03928        slot->isLoggedIn = PR_TRUE;
03929        slot->password = pin;
03930        PZ_Unlock(slot->slotLock);
03931         if (tmp) SECITEM_ZfreeItem(tmp, PR_TRUE);
03932 
03933        /* update all sessions */
03934        sftk_update_all_states(slot);
03935        return CKR_OK;
03936     }
03937 
03938     SECITEM_ZfreeItem(pin, PR_TRUE);
03939     crv = CKR_PIN_INCORRECT;
03940 done:
03941     if (handle) {
03942        sftk_freeKeyDB(handle);
03943     }
03944     return crv;
03945 }
03946 
03947 /* NSC_Logout logs a user out from a token. */
03948 CK_RV NSC_Logout(CK_SESSION_HANDLE hSession)
03949 {
03950     SFTKSlot *slot = sftk_SlotFromSessionHandle(hSession);
03951     SFTKSession *session;
03952     SECItem *pw = NULL;
03953 
03954     session = sftk_SessionFromHandle(hSession);
03955     if (session == NULL) return CKR_SESSION_HANDLE_INVALID;
03956     sftk_FreeSession(session);
03957     session = NULL;
03958 
03959     if (!slot->isLoggedIn) return CKR_USER_NOT_LOGGED_IN;
03960 
03961     PZ_Lock(slot->slotLock);
03962     pw = slot->password;
03963     slot->isLoggedIn = PR_FALSE;
03964     slot->ssoLoggedIn = PR_FALSE;
03965     slot->password = NULL;
03966     PZ_Unlock(slot->slotLock);
03967     if (pw) SECITEM_ZfreeItem(pw, PR_TRUE);
03968 
03969     sftk_update_all_states(slot);
03970     return CKR_OK;
03971 }
03972 
03973 /*
03974  * Create a new slot on the fly. The slot that is passed in is the
03975  * slot the request came from. Only the crypto or FIPS slots can
03976  * be used. The resulting slot will live in the same module as
03977  * the slot the request was passed to. object is the creation object
03978  * that specifies the module spec for the new slot.
03979  */
03980 static CK_RV sftk_CreateNewSlot(SFTKSlot *slot, CK_OBJECT_CLASS class,
03981                                 SFTKObject *object)
03982 {
03983     CK_SLOT_ID idMin, idMax;
03984     PRBool isFIPS = PR_FALSE;
03985     unsigned long moduleIndex;
03986     SFTKAttribute *attribute;
03987     sftk_parameters paramStrings;
03988     char *paramString;
03989     CK_SLOT_ID slotID = 0;
03990     SFTKSlot *newSlot = NULL;
03991     CK_RV crv = CKR_OK;
03992 
03993     /* only the crypto or FIPS slots can create new slot objects */
03994     if (slot->slotID == NETSCAPE_SLOT_ID) {
03995        idMin = SFTK_MIN_USER_SLOT_ID;
03996        idMax = SFTK_MAX_USER_SLOT_ID;
03997        moduleIndex = NSC_NON_FIPS_MODULE;
03998        isFIPS = PR_FALSE;
03999     } else if (slot->slotID == FIPS_SLOT_ID) {
04000        idMin = SFTK_MIN_FIPS_USER_SLOT_ID;
04001        idMax = SFTK_MAX_FIPS_USER_SLOT_ID;
04002        moduleIndex = NSC_FIPS_MODULE;
04003        isFIPS = PR_TRUE;
04004     } else {
04005        return CKR_ATTRIBUTE_VALUE_INVALID;
04006     }
04007     attribute = sftk_FindAttribute(object,CKA_NETSCAPE_MODULE_SPEC);
04008     if (attribute == NULL) {
04009        return CKR_TEMPLATE_INCOMPLETE;
04010     }
04011     paramString = (char *)attribute->attrib.pValue;
04012     crv = secmod_parseParameters(paramString, &paramStrings, isFIPS);
04013     if (crv != CKR_OK) {
04014        goto loser;
04015     }
04016 
04017     /* enforce only one at a time */
04018     if (paramStrings.token_count != 1) {
04019        crv = CKR_ATTRIBUTE_VALUE_INVALID;
04020        goto loser;
04021     }
04022 
04023     slotID = paramStrings.tokens[0].slotID;
04024 
04025     /* stay within the valid ID space */
04026     if ((slotID < idMin) || (slotID > idMax)) {
04027        crv = CKR_ATTRIBUTE_VALUE_INVALID;
04028        goto loser;
04029     }
04030 
04031     /* unload any existing slot at this id */
04032     newSlot = sftk_SlotFromID(slotID, PR_TRUE);
04033     if (newSlot && newSlot->present) {
04034        crv = SFTK_ShutdownSlot(newSlot);
04035        if (crv != CKR_OK) {
04036            goto loser;
04037        }
04038     }
04039 
04040     /* if we were just planning on deleting the slot, then do so now */
04041     if (class == CKO_NETSCAPE_DELSLOT) {
04042        /* sort of a unconventional use of this error code, be we are
04043          * overusing CKR_ATTRIBUTE_VALUE_INVALID, and it does apply */
04044        crv = newSlot ? CKR_OK : CKR_SLOT_ID_INVALID;
04045        goto loser; /* really exit */
04046     }
04047 
04048     if (newSlot) {
04049        crv = SFTK_SlotReInit(newSlot, paramStrings.configdir, 
04050                      &paramStrings.tokens[0], moduleIndex);
04051     } else {
04052        crv = SFTK_SlotInit(paramStrings.configdir, 
04053                      &paramStrings.tokens[0], moduleIndex);
04054     }
04055     if (crv != CKR_OK) {
04056        goto loser;
04057     }
04058 loser:
04059     secmod_freeParams(&paramStrings);
04060     sftk_FreeAttribute(attribute);
04061 
04062     return crv;
04063 }
04064 
04065 
04066 /* NSC_CreateObject creates a new object. */
04067 CK_RV NSC_CreateObject(CK_SESSION_HANDLE hSession,
04068               CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount, 
04069                                    CK_OBJECT_HANDLE_PTR phObject)
04070 {
04071     SFTKSlot *slot = sftk_SlotFromSessionHandle(hSession);
04072     SFTKSession *session;
04073     SFTKObject *object;
04074     /* make sure class isn't randomly CKO_NETSCAPE_NEWSLOT or
04075      * CKO_NETSCPE_DELSLOT. */
04076     CK_OBJECT_CLASS class = CKO_VENDOR_DEFINED;
04077     CK_RV crv;
04078     int i;
04079 
04080     *phObject = CK_INVALID_HANDLE;
04081 
04082     /*
04083      * now lets create an object to hang the attributes off of
04084      */
04085     object = sftk_NewObject(slot); /* fill in the handle later */
04086     if (object == NULL) {
04087        return CKR_HOST_MEMORY;
04088     }
04089 
04090     /*
04091      * load the template values into the object
04092      */
04093     for (i=0; i < (int) ulCount; i++) {
04094        crv = sftk_AddAttributeType(object,sftk_attr_expand(&pTemplate[i]));
04095        if (crv != CKR_OK) {
04096            sftk_FreeObject(object);
04097            return crv;
04098        }
04099        if ((pTemplate[i].type == CKA_CLASS) && pTemplate[i].pValue) {
04100            class = *(CK_OBJECT_CLASS *)pTemplate[i].pValue;
04101        }
04102     }
04103 
04104     /* get the session */
04105     session = sftk_SessionFromHandle(hSession);
04106     if (session == NULL) {
04107        sftk_FreeObject(object);
04108         return CKR_SESSION_HANDLE_INVALID;
04109     }
04110 
04111     /*
04112      * handle pseudo objects (CKO_NEWSLOT)
04113      */
04114     if ((class == CKO_NETSCAPE_NEWSLOT)  || (class == CKO_NETSCAPE_DELSLOT)) {
04115        crv = sftk_CreateNewSlot(slot, class, object);
04116        goto done;
04117     } 
04118 
04119     /*
04120      * handle the base object stuff
04121      */
04122     crv = sftk_handleObject(object,session);
04123     *phObject = object->handle;
04124 done:
04125     sftk_FreeSession(session);
04126     sftk_FreeObject(object);
04127 
04128     return crv;
04129 }
04130 
04131 
04132 
04133 /* NSC_CopyObject copies an object, creating a new object for the copy. */
04134 CK_RV NSC_CopyObject(CK_SESSION_HANDLE hSession,
04135        CK_OBJECT_HANDLE hObject, CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount,
04136                                    CK_OBJECT_HANDLE_PTR phNewObject) 
04137 {
04138     SFTKObject *destObject,*srcObject;
04139     SFTKSession *session;
04140     CK_RV crv = CKR_OK;
04141     SFTKSlot *slot = sftk_SlotFromSessionHandle(hSession);
04142     int i;
04143 
04144     /* Get srcObject so we can find the class */
04145     session = sftk_SessionFromHandle(hSession);
04146     if (session == NULL) {
04147         return CKR_SESSION_HANDLE_INVALID;
04148     }
04149     srcObject = sftk_ObjectFromHandle(hObject,session);
04150     if (srcObject == NULL) {
04151        sftk_FreeSession(session);
04152        return CKR_OBJECT_HANDLE_INVALID;
04153     }
04154     /*
04155      * create an object to hang the attributes off of
04156      */
04157     destObject = sftk_NewObject(slot); /* fill in the handle later */
04158     if (destObject == NULL) {
04159        sftk_FreeSession(session);
04160         sftk_FreeObject(srcObject);
04161        return CKR_HOST_MEMORY;
04162     }
04163 
04164     /*
04165      * load the template values into the object
04166      */
04167     for (i=0; i < (int) ulCount; i++) {
04168        if (sftk_modifyType(pTemplate[i].type,srcObject->objclass) == SFTK_NEVER) {
04169            crv = CKR_ATTRIBUTE_READ_ONLY;
04170            break;
04171        }
04172        crv = sftk_AddAttributeType(destObject,sftk_attr_expand(&pTemplate[i]));
04173        if (crv != CKR_OK) { break; }
04174     }
04175     if (crv != CKR_OK) {
04176        sftk_FreeSession(session);
04177         sftk_FreeObject(srcObject);
04178        sftk_FreeObject(destObject);
04179        return crv;
04180     }
04181 
04182     /* sensitive can only be changed to CK_TRUE */
04183     if (sftk_hasAttribute(destObject,CKA_SENSITIVE)) {
04184        if (!sftk_isTrue(destObject,CKA_SENSITIVE)) {
04185            sftk_FreeSession(session);
04186             sftk_FreeObject(srcObject);
04187            sftk_FreeObject(destObject);
04188            return CKR_ATTRIBUTE_READ_ONLY;
04189        }
04190     }
04191 
04192     /*
04193      * now copy the old attributes from the new attributes
04194      */
04195     /* don't create a token object if we aren't in a rw session */
04196     /* we need to hold the lock to copy a consistant version of
04197      * the object. */
04198     crv = sftk_CopyObject(destObject,srcObject);
04199 
04200     destObject->objclass = srcObject->objclass;
04201     sftk_FreeObject(srcObject);
04202     if (crv != CKR_OK) {
04203        sftk_FreeObject(destObject);
04204        sftk_FreeSession(session);
04205         return crv;
04206     }
04207 
04208     crv = sftk_handleObject(destObject,session);
04209     *phNewObject = destObject->handle;
04210     sftk_FreeSession(session);
04211     sftk_FreeObject(destObject);
04212     
04213     return crv;
04214 }
04215 
04216 
04217 /* NSC_GetObjectSize gets the size of an object in bytes. */
04218 CK_RV NSC_GetObjectSize(CK_SESSION_HANDLE hSession,
04219                      CK_OBJECT_HANDLE hObject, CK_ULONG_PTR pulSize) {
04220     *pulSize = 0;
04221     return CKR_OK;
04222 }
04223 
04224 
04225 /* NSC_GetAttributeValue obtains the value of one or more object attributes. */
04226 CK_RV NSC_GetAttributeValue(CK_SESSION_HANDLE hSession,
04227     CK_OBJECT_HANDLE hObject,CK_ATTRIBUTE_PTR pTemplate,CK_ULONG ulCount) {
04228     SFTKSlot *slot = sftk_SlotFromSessionHandle(hSession);
04229     SFTKSession *session;
04230     SFTKObject *object;
04231     SFTKAttribute *attribute;
04232     PRBool sensitive;
04233     CK_RV crv;
04234     int i;
04235 
04236     /*
04237      * make sure we're allowed
04238      */
04239     session = sftk_SessionFromHandle(hSession);
04240     if (session == NULL) {
04241         return CKR_SESSION_HANDLE_INVALID;
04242     }
04243 
04244     object = sftk_ObjectFromHandle(hObject,session);
04245     sftk_FreeSession(session);
04246     if (object == NULL) {
04247        return CKR_OBJECT_HANDLE_INVALID;
04248     }
04249 
04250     /* don't read a private object if we aren't logged in */
04251     if ((!slot->isLoggedIn) && (slot->needLogin) &&
04252                             (sftk_isTrue(object,CKA_PRIVATE))) {
04253        sftk_FreeObject(object);
04254        return CKR_USER_NOT_LOGGED_IN;
04255     }
04256 
04257     crv = CKR_OK;
04258     sensitive = sftk_isTrue(object,CKA_SENSITIVE);
04259     for (i=0; i < (int) ulCount; i++) {
04260        /* Make sure that this attribute is retrievable */
04261        if (sensitive && sftk_isSensitive(pTemplate[i].type,object->objclass)) {
04262            crv = CKR_ATTRIBUTE_SENSITIVE;
04263            pTemplate[i].ulValueLen = -1;
04264            continue;
04265        }
04266        attribute = sftk_FindAttribute(object,pTemplate[i].type);
04267        if (attribute == NULL) {
04268            crv = CKR_ATTRIBUTE_TYPE_INVALID;
04269            pTemplate[i].ulValueLen = -1;
04270            continue;
04271        }
04272        if (pTemplate[i].pValue != NULL) {
04273            PORT_Memcpy(pTemplate[i].pValue,attribute->attrib.pValue,
04274                                           attribute->attrib.ulValueLen);
04275        }
04276        pTemplate[i].ulValueLen = attribute->attrib.ulValueLen;
04277        sftk_FreeAttribute(attribute);
04278     }
04279 
04280     sftk_FreeObject(object);
04281     return crv;
04282 }
04283 
04284 /* NSC_SetAttributeValue modifies the value of one or more object attributes */
04285 CK_RV NSC_SetAttributeValue (CK_SESSION_HANDLE hSession,
04286  CK_OBJECT_HANDLE hObject,CK_ATTRIBUTE_PTR pTemplate,CK_ULONG ulCount) {
04287     SFTKSlot *slot = sftk_SlotFromSessionHandle(hSession);
04288     SFTKSession *session;
04289     SFTKAttribute *attribute;
04290     SFTKObject *object;
04291     PRBool isToken;
04292     CK_RV crv = CKR_OK;
04293     CK_BBOOL legal;
04294     int i;
04295 
04296     /*
04297      * make sure we're allowed
04298      */
04299     session = sftk_SessionFromHandle(hSession);
04300     if (session == NULL) {
04301         return CKR_SESSION_HANDLE_INVALID;
04302     }
04303 
04304     object = sftk_ObjectFromHandle(hObject,session);
04305     if (object == NULL) {
04306         sftk_FreeSession(session);
04307        return CKR_OBJECT_HANDLE_INVALID;
04308     }
04309 
04310     /* don't modify a private object if we aren't logged in */
04311     if ((!slot->isLoggedIn) && (slot->needLogin) &&
04312                             (sftk_isTrue(object,CKA_PRIVATE))) {
04313        sftk_FreeSession(session);
04314        sftk_FreeObject(object);
04315        return CKR_USER_NOT_LOGGED_IN;
04316     }
04317 
04318     /* don't modify a token object if we aren't in a rw session */
04319     isToken = sftk_isTrue(object,CKA_TOKEN);
04320     if (((session->info.flags & CKF_RW_SESSION) == 0) && isToken) {
04321        sftk_FreeSession(session);
04322        sftk_FreeObject(object);
04323        return CKR_SESSION_READ_ONLY;
04324     }
04325     sftk_FreeSession(session);
04326 
04327     /* only change modifiable objects */
04328     if (!sftk_isTrue(object,CKA_MODIFIABLE)) {
04329        sftk_FreeObject(object);
04330        return CKR_ATTRIBUTE_READ_ONLY;
04331     }
04332 
04333     for (i=0; i < (int) ulCount; i++) {
04334        /* Make sure that this attribute is changeable */
04335        switch (sftk_modifyType(pTemplate[i].type,object->objclass)) {
04336        case SFTK_NEVER:
04337        case SFTK_ONCOPY:
04338         default:
04339            crv = CKR_ATTRIBUTE_READ_ONLY;
04340            break;
04341 
04342         case SFTK_SENSITIVE:
04343            legal = (pTemplate[i].type == CKA_EXTRACTABLE) ? CK_FALSE : CK_TRUE;
04344            if ((*(CK_BBOOL *)pTemplate[i].pValue) != legal) {
04345                crv = CKR_ATTRIBUTE_READ_ONLY;
04346            }
04347            break;
04348         case SFTK_ALWAYS:
04349            break;
04350        }
04351        if (crv != CKR_OK) break;
04352 
04353        /* find the old attribute */
04354        attribute = sftk_FindAttribute(object,pTemplate[i].type);
04355        if (attribute == NULL) {
04356            crv =CKR_ATTRIBUTE_TYPE_INVALID;
04357            break;
04358        }
04359        sftk_FreeAttribute(attribute);
04360        crv = sftk_forceAttribute(object,sftk_attr_expand(&pTemplate[i]));
04361        if (crv != CKR_OK) break;
04362 
04363     }
04364 
04365     sftk_FreeObject(object);
04366     return crv;
04367 }
04368 
04369 /*
04370  * find any certs that may match the template and load them.
04371  */
04372 #define NSC_CERT     0x00000001
04373 #define NSC_TRUST    0x00000002
04374 #define NSC_CRL             0x00000004
04375 #define NSC_SMIME    0x00000008
04376 #define NSC_PRIVATE  0x00000010
04377 #define NSC_PUBLIC   0x00000020
04378 #define NSC_KEY             0x00000040
04379 
04380 /*
04381  * structure to collect key handles.
04382  */
04383 typedef struct sftkCrlDataStr {
04384     SFTKSlot *slot;
04385     SFTKSearchResults *searchHandles;
04386     CK_ATTRIBUTE *template;
04387     CK_ULONG templ_count;
04388 } sftkCrlData;
04389 
04390 
04391 static SECStatus
04392 sftk_crl_collect(SECItem *data, SECItem *key, certDBEntryType type, void *arg)
04393 {
04394     sftkCrlData *crlData;
04395     CK_OBJECT_HANDLE class_handle;
04396     SFTKSlot *slot;
04397     
04398     crlData = (sftkCrlData *)arg;
04399     slot = crlData->slot;
04400 
04401     class_handle = (type == certDBEntryTypeRevocation) ? SFTK_TOKEN_TYPE_CRL :
04402                                                  SFTK_TOKEN_KRL_HANDLE;
04403     if (sftk_tokenMatch(slot, key, class_handle,
04404                      crlData->template, crlData->templ_count)) {
04405        sftk_addHandle(crlData->searchHandles,
04406                              sftk_mkHandle(slot,key,class_handle));
04407     }
04408     return(SECSuccess);
04409 }
04410 
04411 static void
04412 sftk_searchCrls(SFTKSlot *slot, SECItem *derSubject, PRBool isKrl, 
04413               unsigned long classFlags, SFTKSearchResults *search,
04414               CK_ATTRIBUTE *pTemplate, CK_ULONG ulCount)
04415 {
04416     NSSLOWCERTCertDBHandle *certHandle = NULL;
04417 
04418     certHandle = sftk_getCertDB(slot);
04419     if (certHandle == NULL) {
04420        return;
04421     }
04422     if (derSubject->data != NULL)  {
04423        certDBEntryRevocation *crl = 
04424            nsslowcert_FindCrlByKey(certHandle, derSubject, isKrl);
04425 
04426        if (crl != NULL) {
04427            sftk_addHandle(search, sftk_mkHandle(slot, derSubject,
04428               isKrl ? SFTK_TOKEN_KRL_HANDLE : SFTK_TOKEN_TYPE_CRL));
04429            nsslowcert_DestroyDBEntry((certDBEntry *)crl);
04430        }
04431     } else {
04432        sftkCrlData crlData;
04433 
04434        /* traverse */
04435        crlData.slot = slot;
04436        crlData.searchHandles = search;
04437        crlData.template = pTemplate;
04438        crlData.templ_count = ulCount;
04439        nsslowcert_TraverseDBEntries(certHandle, certDBEntryTypeRevocation,
04440               sftk_crl_collect, (void *)&crlData);
04441        nsslowcert_TraverseDBEntries(certHandle, certDBEntryTypeKeyRevocation,
04442               sftk_crl_collect, (void *)&crlData);
04443     } 
04444     sftk_freeCertDB(certHandle);
04445 }
04446 
04447 /*
04448  * structure to collect key handles.
04449  */
04450 typedef struct sftkKeyDataStr {
04451     SFTKSlot *slot;
04452     NSSLOWKEYDBHandle *keyHandle;
04453     SFTKSearchResults *searchHandles;
04454     SECItem *id;
04455     CK_ATTRIBUTE *template;
04456     CK_ULONG templ_count;
04457     unsigned long classFlags;
04458     PRBool isLoggedIn;
04459     PRBool strict;
04460 } sftkKeyData;
04461 
04462 
04463 static SECStatus
04464 sftk_key_collect(DBT *key, DBT *data, void *arg)
04465 {
04466     sftkKeyData *keyData;
04467     NSSLOWKEYPrivateKey *privKey = NULL;
04468     SECItem tmpDBKey;
04469     SFTKSlot *slot;
04470     
04471     keyData = (sftkKeyData *)arg;
04472     slot = keyData->slot;
04473 
04474     tmpDBKey.data = key->data;
04475     tmpDBKey.len = key->size;
04476     tmpDBKey.type = siBuffer;
04477 
04478     PORT_Assert(keyData->keyHandle);
04479     if (!keyData->strict && keyData->id && keyData->id->data) {
04480        SECItem result;
04481        PRBool haveMatch= PR_FALSE;
04482        unsigned char hashKey[SHA1_LENGTH];
04483        result.data = hashKey;
04484        result.len = sizeof(hashKey);
04485 
04486        if (keyData->id->len == 0) {
04487            /* Make sure this isn't a NSC_KEY */
04488            privKey = nsslowkey_FindKeyByPublicKey(keyData->keyHandle, 
04489                                    &tmpDBKey, keyData->slot->password);
04490            if (privKey) {
04491               haveMatch = isSecretKey(privKey) ?
04492                             (PRBool)(keyData->classFlags & NSC_KEY) != 0:
04493                             (PRBool)(keyData->classFlags & 
04494                                          (NSC_PRIVATE|NSC_PUBLIC)) != 0;
04495               nsslowkey_DestroyPrivateKey(privKey);
04496            }
04497        } else {
04498            SHA1_HashBuf( hashKey, key->data, key->size ); /* match id */
04499            haveMatch = SECITEM_ItemsAreEqual(keyData->id,&result);
04500            if (!haveMatch && ((unsigned char *)key->data)[0] == 0) {
04501               /* This is a fix for backwards compatibility.  The key
04502                * database indexes private keys by the public key, and
04503                * versions of NSS prior to 3.4 stored the public key as
04504                * a signed integer.  The public key is now treated as an
04505                * unsigned integer, with no leading zero.  In order to
04506                * correctly compute the hash of an old key, it is necessary
04507                * to fallback and detect the leading zero.
04508                */
04509               SHA1_HashBuf(hashKey, 
04510                            (unsigned char *)key->data + 1, key->size - 1);
04511               haveMatch = SECITEM_ItemsAreEqual(keyData->id,&result);
04512            }
04513        }
04514        if (haveMatch) {
04515            if (keyData->classFlags & NSC_PRIVATE)  {
04516               sftk_addHandle(keyData->searchHandles,
04517                      sftk_mkHandle(slot,&tmpDBKey,SFTK_TOKEN_TYPE_PRIV));
04518            }
04519            if (keyData->classFlags & NSC_PUBLIC) {
04520               sftk_addHandle(keyData->searchHandles,
04521                      sftk_mkHandle(slot,&tmpDBKey,SFTK_TOKEN_TYPE_PUB));
04522            }
04523            if (keyData->classFlags & NSC_KEY) {
04524               sftk_addHandle(keyData->searchHandles,
04525                      sftk_mkHandle(slot,&tmpDBKey,SFTK_TOKEN_TYPE_KEY));
04526            }
04527        }
04528        return SECSuccess;
04529     }
04530 
04531     privKey = nsslowkey_FindKeyByPublicKey(keyData->keyHandle, &tmpDBKey, 
04532                                            keyData->slot->password);
04533     if ( privKey == NULL ) {
04534        goto loser;
04535     }
04536 
04537     if (isSecretKey(privKey)) {
04538        if ((keyData->classFlags & NSC_KEY) && 
04539               sftk_tokenMatch(keyData->slot, &tmpDBKey, SFTK_TOKEN_TYPE_KEY,
04540                      keyData->template, keyData->templ_count)) {
04541            sftk_addHandle(keyData->searchHandles,
04542               sftk_mkHandle(keyData->slot, &tmpDBKey, SFTK_TOKEN_TYPE_KEY));
04543        }
04544     } else {
04545        if ((keyData->classFlags & NSC_PRIVATE) && 
04546               sftk_tokenMatch(keyData->slot, &tmpDBKey, SFTK_TOKEN_TYPE_PRIV,
04547                      keyData->template, keyData->templ_count)) {
04548            sftk_addHandle(keyData->searchHandles,
04549               sftk_mkHandle(keyData->slot,&tmpDBKey,SFTK_TOKEN_TYPE_PRIV));
04550        }
04551        if ((keyData->classFlags & NSC_PUBLIC) && 
04552               sftk_tokenMatch(keyData->slot, &tmpDBKey, SFTK_TOKEN_TYPE_PUB,
04553                      keyData->template, keyData->templ_count)) {
04554            sftk_addHandle(keyData->searchHandles,
04555               sftk_mkHandle(keyData->slot, &tmpDBKey,SFTK_TOKEN_TYPE_PUB));
04556        }
04557     }
04558 
04559 loser:
04560     if ( privKey ) {
04561        nsslowkey_DestroyPrivateKey(privKey);
04562     }
04563     return(SECSuccess);
04564 }
04565 
04566 static void
04567 sftk_searchKeys(SFTKSlot *slot, SECItem *key_id, PRBool isLoggedIn,
04568        unsigned long classFlags, SFTKSearchResults *search, PRBool mustStrict,
04569        CK_ATTRIBUTE *pTemplate, CK_ULONG ulCount)
04570 {
04571     NSSLOWKEYDBHandle *keyHandle = NULL;
04572     NSSLOWKEYPrivateKey *privKey;
04573     sftkKeyData keyData;
04574     PRBool found = PR_FALSE;
04575 
04576     keyHandle = sftk_getKeyDB(slot);
04577     if (keyHandle == NULL) {
04578        return;
04579     }
04580 
04581     if (key_id->data) {
04582        privKey = nsslowkey_FindKeyByPublicKey(keyHandle, key_id, slot->password);
04583        if (privKey) {
04584            if ((classFlags & NSC_KEY) && isSecretKey(privKey)) {
04585                sftk_addHandle(search,
04586                      sftk_mkHandle(slot,key_id,SFTK_TOKEN_TYPE_KEY));
04587               found = PR_TRUE;
04588            }
04589            if ((classFlags & NSC_PRIVATE) && !isSecretKey(privKey)) {
04590                sftk_addHandle(search,
04591                      sftk_mkHandle(slot,key_id,SFTK_TOKEN_TYPE_PRIV));
04592               found = PR_TRUE;
04593            }
04594            if ((classFlags & NSC_PUBLIC) && !isSecretKey(privKey)) {
04595                sftk_addHandle(search,
04596                      sftk_mkHandle(slot,key_id,SFTK_TOKEN_TYPE_PUB));
04597               found = PR_TRUE;
04598            }
04599            nsslowkey_DestroyPrivateKey(privKey);
04600        }
04601        /* don't do the traversal if we have an up to date db */
04602        if (keyHandle->version != 3) {
04603            goto loser;
04604        }
04605        /* don't do the traversal if it can't possibly be the correct id */
04606        /* all soft token id's are SHA1_HASH_LEN's */
04607        if (key_id->len != SHA1_LENGTH) {
04608            goto loser;
04609        }
04610        if (found) {
04611           /* if we already found some keys, don't do the traversal */
04612           goto loser;
04613        }
04614     }
04615     keyData.slot = slot;
04616     keyData.keyHandle = keyHandle;
04617     keyData.searchHandles = search;
04618     keyData.id = key_id;
04619     keyData.template = pTemplate;
04620     keyData.templ_count = ulCount;
04621     keyData.isLoggedIn = isLoggedIn;
04622     keyData.classFlags = classFlags;
04623     keyData.strict = mustStrict ? mustStrict : NSC_STRICT;
04624 
04625     nsslowkey_TraverseKeys(keyHandle, sftk_key_collect, &keyData);
04626 loser:
04627     sftk_freeKeyDB(keyHandle);
04628        
04629 }
04630 
04631 /*
04632  * structure to collect certs into
04633  */
04634 typedef struct sftkCertDataStr {
04635     SFTKSlot *slot;
04636     int cert_count;
04637     int max_cert_count;
04638     NSSLOWCERTCertificate **certs;
04639     CK_ATTRIBUTE *template;
04640     CK_ULONG  templ_count;
04641     unsigned long classFlags;
04642     PRBool    strict;
04643 } sftkCertData;
04644 
04645 /*
04646  * collect all the certs from the traverse call.
04647  */    
04648 static SECStatus
04649 sftk_cert_collect(NSSLOWCERTCertificate *cert,void *arg)
04650 {
04651     sftkCertData *cd = (sftkCertData *)arg;
04652 
04653     if (cert == NULL) {
04654        return SECSuccess;
04655     }
04656 
04657     if (cd->certs == NULL) {
04658        return SECFailure;
04659     }
04660 
04661     if (cd->strict) {
04662        if ((cd->classFlags & NSC_CERT) && !sftk_tokenMatch(cd->slot,
04663          &cert->certKey, SFTK_TOKEN_TYPE_CERT, cd->template,cd->templ_count)) {
04664            return SECSuccess;
04665        }
04666        if ((cd->classFlags & NSC_TRUST) && !sftk_tokenMatch(cd->slot,
04667          &cert->certKey, SFTK_TOKEN_TYPE_TRUST, 
04668                                         cd->template, cd->templ_count)) {
04669            return SECSuccess;
04670        }
04671     }
04672 
04673     /* allocate more space if we need it. This should only happen in
04674      * the general traversal case */
04675     if (cd->cert_count >= cd->max_cert_count) {
04676        int size;
04677        cd->max_cert_count += NSC_CERT_BLOCK_SIZE;
04678        size = cd->max_cert_count * sizeof (NSSLOWCERTCertificate *);
04679        cd->certs = (NSSLOWCERTCertificate **)PORT_Realloc(cd->certs,size);
04680        if (cd->certs == NULL) {
04681            return SECFailure;
04682        }
04683     }
04684 
04685     cd->certs[cd->cert_count++] = nsslowcert_DupCertificate(cert);
04686     return SECSuccess;
04687 }
04688 
04689 /* provide impedence matching ... */
04690 static SECStatus
04691 sftk_cert_collect2(NSSLOWCERTCertificate *cert, SECItem *dymmy, void *arg)
04692 {
04693     return sftk_cert_collect(cert, arg);
04694 }
04695 
04696 static void
04697 sftk_searchSingleCert(sftkCertData *certData,NSSLOWCERTCertificate *cert)
04698 {
04699     if (cert == NULL) {
04700            return;
04701     }
04702     if (certData->strict && 
04703        !sftk_tokenMatch(certData->slot, &cert->certKey, SFTK_TOKEN_TYPE_CERT, 
04704                             certData->template,certData->templ_count)) {
04705        nsslowcert_DestroyCertificate(cert);
04706        return;
04707     }
04708     certData->certs = (NSSLOWCERTCertificate **) 
04709                             PORT_Alloc(sizeof (NSSLOWCERTCertificate *));
04710     if (certData->certs == NULL) {
04711        nsslowcert_DestroyCertificate(cert);
04712        return;
04713     }
04714     certData->certs[0] = cert;
04715     certData->cert_count = 1;
04716 }
04717 
04718 static void
04719 sftk_CertSetupData(sftkCertData *certData,int count)
04720 {
04721     certData->max_cert_count = count;
04722 
04723     if (certData->max_cert_count <= 0) {
04724        return;
04725     }
04726     certData->certs = (NSSLOWCERTCertificate **)
04727                       PORT_Alloc( count * sizeof(NSSLOWCERTCertificate *));
04728     return;
04729 }
04730 
04731 static void
04732 sftk_searchCertsAndTrust(SFTKSlot *slot, SECItem *derCert, SECItem *name, 
04733                      SECItem *derSubject, NSSLOWCERTIssuerAndSN *issuerSN, 
04734                      SECItem *email,
04735                      unsigned long classFlags, SFTKSearchResults *handles, 
04736                      CK_ATTRIBUTE *pTemplate, CK_LONG ulCount)
04737 {
04738     NSSLOWCERTCertDBHandle *certHandle = NULL;
04739     sftkCertData certData;
04740     int i;
04741 
04742     certHandle = sftk_getCertDB(slot);
04743     if (certHandle == NULL) return;
04744 
04745     certData.slot = slot;
04746     certData.max_cert_count = 0;
04747     certData.certs = NULL;
04748     certData.cert_count = 0;
04749     certData.template = pTemplate;
04750     certData.templ_count = ulCount;
04751     certData.classFlags = classFlags; 
04752     certData.strict = NSC_STRICT; 
04753 
04754 
04755     /*
04756      * Find the Cert.
04757      */
04758     if (derCert->data != NULL) {
04759        NSSLOWCERTCertificate *cert = 
04760                      nsslowcert_FindCertByDERCert(certHandle,derCert);
04761        sftk_searchSingleCert(&certData,cert);
04762     } else if (name->data != NULL) {
04763        char *tmp_name = (char*)PORT_Alloc(name->len+1);
04764        int count;
04765 
04766        if (tmp_name == NULL) {
04767            return;
04768        }
04769        PORT_Memcpy(tmp_name,name->data,name->len);
04770        tmp_name[name->len] = 0;
04771 
04772        count= nsslowcert_NumPermCertsForNickname(certHandle,tmp_name);
04773        sftk_CertSetupData(&certData,count);
04774        nsslowcert_TraversePermCertsForNickname(certHandle,tmp_name,
04775                             sftk_cert_collect, &certData);
04776        PORT_Free(tmp_name);
04777     } else if (derSubject->data != NULL) {
04778        int count;
04779 
04780        count = nsslowcert_NumPermCertsForSubject(certHandle,derSubject);
04781        sftk_CertSetupData(&certData,count);
04782        nsslowcert_TraversePermCertsForSubject(certHandle,derSubject,
04783                             sftk_cert_collect, &certData);
04784     } else if ((issuerSN->derIssuer.data != NULL) && 
04785                      (issuerSN->serialNumber.data != NULL)) {
04786         if (classFlags & NSC_CERT) {
04787            NSSLOWCERTCertificate *cert = 
04788               nsslowcert_FindCertByIssuerAndSN(certHandle,issuerSN);
04789 
04790            sftk_searchSingleCert(&certData,cert);
04791        }
04792        if (classFlags & NSC_TRUST) {
04793            NSSLOWCERTTrust *trust = 
04794               nsslowcert_FindTrustByIssuerAndSN(certHandle, issuerSN);
04795 
04796            if (trust) {
04797               sftk_addHandle(handles,
04798                   sftk_mkHandle(slot,&trust->dbKey,SFTK_TOKEN_TYPE_TRUST));
04799               nsslowcert_DestroyTrust(trust);
04800            }
04801        }
04802     } else if (email->data != NULL) {
04803        char *tmp_name = (char*)PORT_Alloc(email->len+1);
04804        certDBEntrySMime *entry = NULL;
04805 
04806        if (tmp_name == NULL) {
04807            return;
04808        }
04809        PORT_Memcpy(tmp_name,email->data,email->len);
04810        tmp_name[email->len] = 0;
04811 
04812        entry = nsslowcert_ReadDBSMimeEntry(certHandle,tmp_name);
04813        if (entry) {
04814            int count;
04815            SECItem *subjectName = &entry->subjectName;
04816 
04817            count = nsslowcert_NumPermCertsForSubject(certHandle, subjectName);
04818            sftk_CertSetupData(&certData,count);
04819            nsslowcert_TraversePermCertsForSubject(certHandle, subjectName, 
04820                                           sftk_cert_collect, &certData);
04821 
04822            nsslowcert_DestroyDBEntry((certDBEntry *)entry);
04823        }
04824        PORT_Free(tmp_name);
04825     } else {
04826        /* we aren't filtering the certs, we are working on all, so turn
04827         * on the strict filters. */
04828        certData.strict = PR_TRUE;
04829        sftk_CertSetupData(&certData,NSC_CERT_BLOCK_SIZE);
04830        nsslowcert_TraversePermCerts(certHandle, sftk_cert_collect2, &certData);
04831     }
04832     sftk_freeCertDB(certHandle);
04833 
04834     /*
04835      * build the handles
04836      */       
04837     for (i=0 ; i < certData.cert_count ; i++) {
04838        NSSLOWCERTCertificate *cert = certData.certs[i];
04839 
04840        /* if we filtered it would have been on the stuff above */
04841        if (classFlags & NSC_CERT) {
04842            sftk_addHandle(handles,
04843               sftk_mkHandle(slot,&cert->certKey,SFTK_TOKEN_TYPE_CERT));
04844        }
04845        if ((classFlags & NSC_TRUST) && nsslowcert_hasTrust(cert->trust)) {
04846            sftk_addHandle(handles,
04847               sftk_mkHandle(slot,&cert->certKey,SFTK_TOKEN_TYPE_TRUST));
04848        }
04849        nsslowcert_DestroyCertificate(cert);
04850     }
04851 
04852     if (certData.certs) PORT_Free(certData.certs);
04853     return;
04854 }
04855 
04856 static void
04857 sftk_searchSMime(SFTKSlot *slot, SECItem *email, SFTKSearchResults *handles, 
04858                      CK_ATTRIBUTE *pTemplate, CK_LONG ulCount)
04859 {
04860     NSSLOWCERTCertDBHandle *certHandle = NULL;
04861     certDBEntrySMime *entry;
04862 
04863     certHandle = sftk_getCertDB(slot);
04864     if (certHandle == NULL) return;
04865 
04866     if (email->data != NULL) {
04867        char *tmp_name = (char*)PORT_Alloc(email->len+1);
04868 
04869        if (tmp_name == NULL) {
04870            sftk_freeCertDB(certHandle);
04871            return;
04872        }
04873        PORT_Memcpy(tmp_name,email->data,email->len);
04874        tmp_name[email->len] = 0;
04875 
04876        entry = nsslowcert_ReadDBSMimeEntry(certHandle,tmp_name);
04877        if (entry) {
04878            SECItem emailKey;
04879 
04880            emailKey.data = (unsigned char *)tmp_name;
04881            emailKey.len = PORT_Strlen(tmp_name)+1;
04882            emailKey.type = 0;
04883            sftk_addHandle(handles,
04884               sftk_mkHandle(slot,&emailKey,SFTK_TOKEN_TYPE_SMIME));
04885            nsslowcert_DestroyDBEntry((certDBEntry *)entry);
04886        }
04887        PORT_Free(tmp_name);
04888     }
04889     sftk_freeCertDB(certHandle);
04890     return;
04891 }
04892 
04893 static CK_RV
04894 sftk_searchTokenList(SFTKSlot *slot, SFTKSearchResults *search,
04895                      CK_ATTRIBUTE *pTemplate, CK_LONG ulCount, 
04896                      PRBool *tokenOnly, PRBool isLoggedIn)
04897 {
04898     int i;
04899     PRBool isKrl = PR_FALSE;
04900     SECItem derCert = { siBuffer, NULL, 0 };
04901     SECItem derSubject = { siBuffer, NULL, 0 };
04902     SECItem name = { siBuffer, NULL, 0 };
04903     SECItem email = { siBuffer, NULL, 0 };
04904     SECItem key_id = { siBuffer, NULL, 0 };
04905     SECItem cert_sha1_hash = { siBuffer, NULL, 0 };
04906     SECItem cert_md5_hash  = { siBuffer, NULL, 0 };
04907     NSSLOWCERTIssuerAndSN issuerSN = {
04908        { siBuffer, NULL, 0 },
04909        { siBuffer, NULL, 0 }
04910     };
04911     SECItem *copy = NULL;
04912     unsigned long classFlags = 
04913        NSC_CERT|NSC_TRUST|NSC_PRIVATE|NSC_PUBLIC|NSC_KEY|NSC_SMIME|NSC_CRL;
04914 
04915     /* if we aren't logged in, don't look for private or secret keys */
04916     if (!isLoggedIn) {
04917        classFlags &= ~(NSC_PRIVATE|NSC_KEY);
04918     }
04919 
04920     /*
04921      * look for things to search on token objects for. If the right options
04922      * are specified, we can use them as direct indeces into the database
04923      * (rather than using linear searches. We can also use the attributes to
04924      * limit the kinds of objects we are searching for. Later we can use this
04925      * array to filter the remaining objects more finely.
04926      */
04927     for (i=0 ;classFlags && i < (int)ulCount; i++) {
04928 
04929        switch (pTemplate[i].type) {
04930        case CKA_SUBJECT:
04931            copy = &derSubject;
04932            classFlags &= (NSC_CERT|NSC_PRIVATE|NSC_PUBLIC|NSC_SMIME|NSC_CRL);
04933            break;
04934        case CKA_ISSUER: 
04935            copy = &issuerSN.derIssuer;
04936            classFlags &= (NSC_CERT|NSC_TRUST);
04937            break;
04938        case CKA_SERIAL_NUMBER: 
04939            copy = &issuerSN.serialNumber;
04940            classFlags &= (NSC_CERT|NSC_TRUST);
04941            break;
04942        case CKA_VALUE:
04943            copy = &derCert;
04944            classFlags &= (NSC_CERT|NSC_CRL|NSC_SMIME);
04945            break;
04946        case CKA_LABEL:
04947            copy = &name;
04948            break;
04949        case CKA_NETSCAPE_EMAIL:
04950            copy = &email;
04951            classFlags &= NSC_SMIME|NSC_CERT;
04952            break;
04953        case CKA_NETSCAPE_SMIME_TIMESTAMP:
04954            classFlags &= NSC_SMIME;
04955            break;
04956        case CKA_CLASS:
04957            if (pTemplate[i].ulValueLen != sizeof(CK_OBJECT_CLASS)) {
04958               classFlags = 0;
04959               break;;
04960            }
04961            switch (*((CK_OBJECT_CLASS *)pTemplate[i].pValue)) {
04962            case CKO_CERTIFICATE:
04963               classFlags &= NSC_CERT;
04964               break;
04965            case CKO_NETSCAPE_TRUST:
04966               classFlags &= NSC_TRUST;
04967               break;
04968            case CKO_NETSCAPE_CRL:
04969               classFlags &= NSC_CRL;
04970               break;
04971            case CKO_NETSCAPE_SMIME:
04972               classFlags &= NSC_SMIME;
04973               break;
04974            case CKO_PRIVATE_KEY:
04975               classFlags &= NSC_PRIVATE;
04976               break;
04977            case CKO_PUBLIC_KEY:
04978               classFlags &= NSC_PUBLIC;
04979               break;
04980            case CKO_SECRET_KEY:
04981               classFlags &= NSC_KEY;
04982               break;
04983            default:
04984               classFlags = 0;
04985               break;
04986            }
04987            break;
04988        case CKA_PRIVATE:
04989            if (pTemplate[i].ulValueLen != sizeof(CK_BBOOL)) {
04990               classFlags = 0;
04991            }
04992            if (*((CK_BBOOL *)pTemplate[i].pValue) == CK_TRUE) {
04993               classFlags &= (NSC_PRIVATE|NSC_KEY);
04994            } else {
04995               classFlags &= ~(NSC_PRIVATE|NSC_KEY);
04996            }
04997            break;
04998        case CKA_SENSITIVE:
04999            if (pTemplate[i].ulValueLen != sizeof(CK_BBOOL)) {
05000               classFlags = 0;
05001            }
05002            if (*((CK_BBOOL *)pTemplate[i].pValue) == CK_TRUE) {
05003               classFlags &= (NSC_PRIVATE|NSC_KEY);
05004            } else {
05005               classFlags = 0;
05006            }
05007            break;
05008        case CKA_TOKEN:
05009            if (pTemplate[i].ulValueLen != sizeof(CK_BBOOL)) {
05010               classFlags = 0;
05011            }
05012            if (*((CK_BBOOL *)pTemplate[i].pValue) == CK_TRUE) {
05013               *tokenOnly = PR_TRUE;
05014            } else {
05015               classFlags = 0;
05016            }
05017            break;
05018        case CKA_CERT_SHA1_HASH:
05019            classFlags &= NSC_TRUST;
05020            copy = &cert_sha1_hash; break;
05021        case CKA_CERT_MD5_HASH:
05022            classFlags &= NSC_TRUST;
05023            copy = &cert_md5_hash; break;
05024        case CKA_CERTIFICATE_TYPE:
05025            if (pTemplate[i].ulValueLen != sizeof(CK_CERTIFICATE_TYPE)) {
05026               classFlags = 0;
05027            }
05028            classFlags &= NSC_CERT;
05029            if (*((CK_CERTIFICATE_TYPE *)pTemplate[i].pValue) != CKC_X_509) {
05030               classFlags = 0;
05031            }
05032            break;
05033        case CKA_ID:
05034            copy = &key_id;
05035            classFlags &= (NSC_CERT|NSC_PRIVATE|NSC_KEY|NSC_PUBLIC);
05036            break;
05037        case CKA_NETSCAPE_KRL:
05038            if (pTemplate[i].ulValueLen != sizeof(CK_BBOOL)) {
05039               classFlags = 0;
05040            }
05041            classFlags &= NSC_CRL;
05042            isKrl = (PRBool)(*((CK_BBOOL *)pTemplate[i].pValue) == CK_TRUE);
05043            break;
05044        case CKA_MODIFIABLE:
05045             break;
05046        case CKA_KEY_TYPE:
05047        case CKA_DERIVE:
05048            classFlags &= NSC_PUBLIC|NSC_PRIVATE|NSC_KEY;
05049            break;
05050        case CKA_VERIFY_RECOVER:
05051            classFlags &= NSC_PUBLIC;
05052            break;
05053        case CKA_SIGN_RECOVER:
05054            classFlags &= NSC_PRIVATE;
05055            break;
05056        case CKA_ENCRYPT:
05057        case CKA_VERIFY:
05058        case CKA_WRAP:
05059            classFlags &= NSC_PUBLIC|NSC_KEY;
05060            break;
05061        case CKA_DECRYPT:
05062        case CKA_SIGN:
05063        case CKA_UNWRAP:
05064        case CKA_ALWAYS_SENSITIVE:
05065        case CKA_EXTRACTABLE:
05066        case CKA_NEVER_EXTRACTABLE:
05067            classFlags &= NSC_PRIVATE|NSC_KEY;
05068            break;
05069        /* can't be a certificate if it doesn't match one of the above 
05070         * attributes */
05071        default: 
05072             classFlags  = 0;
05073             break;
05074        }
05075        if (copy) {
05076            copy->data = (unsigned char*)pTemplate[i].pValue;
05077            copy->len = pTemplate[i].ulValueLen;
05078        }
05079        copy = NULL;
05080     }
05081 
05082 
05083     /* certs */
05084     if (classFlags & (NSC_CERT|NSC_TRUST)) {
05085        sftk_searchCertsAndTrust(slot,&derCert,&name,&derSubject,
05086                              &issuerSN, &email,classFlags,search, 
05087                             pTemplate, ulCount);
05088     }
05089 
05090     /* keys */
05091     if (classFlags & (NSC_PRIVATE|NSC_PUBLIC|NSC_KEY)) {
05092        PRBool mustStrict = (name.len != 0);
05093        sftk_searchKeys(slot, &key_id, isLoggedIn, classFlags, search,
05094                       mustStrict, pTemplate, ulCount);
05095     }
05096 
05097     /* crl's */
05098     if (classFlags & NSC_CRL) {
05099        sftk_searchCrls(slot, &derSubject, isKrl, classFlags, search,
05100                      pTemplate, ulCount);
05101     }
05102     /* Add S/MIME entry stuff */
05103     if (classFlags & NSC_SMIME) {
05104        sftk_searchSMime(slot, &email, search, pTemplate, ulCount);
05105     }
05106     return CKR_OK;
05107 }
05108        
05109 
05110 /* NSC_FindObjectsInit initializes a search for token and session objects 
05111  * that match a template. */
05112 CK_RV NSC_FindObjectsInit(CK_SESSION_HANDLE hSession,
05113                      CK_ATTRIBUTE_PTR pTemplate,CK_ULONG ulCount)
05114 {
05115     SFTKSearchResults *search = NULL, *freeSearch = NULL;
05116     SFTKSession *session = NULL;
05117     SFTKSlot *slot = sftk_SlotFromSessionHandle(hSession);
05118     PRBool tokenOnly = PR_FALSE;
05119     CK_RV crv = CKR_OK;
05120     PRBool isLoggedIn;
05121     
05122     session = sftk_SessionFromHandle(hSession);
05123     if (session == NULL) {
05124        crv = CKR_SESSION_HANDLE_INVALID;
05125        goto loser;
05126     }
05127    
05128     search = (SFTKSearchResults *)PORT_Alloc(sizeof(SFTKSearchResults));
05129     if (search == NULL) {
05130        crv = CKR_HOST_MEMORY;
05131        goto loser;
05132     }
05133     search->handles = (CK_OBJECT_HANDLE *)
05134               PORT_Alloc(sizeof(CK_OBJECT_HANDLE) * NSC_SEARCH_BLOCK_SIZE);
05135     if (search->handles == NULL) {
05136        crv = CKR_HOST_MEMORY;
05137        goto loser;
05138     }
05139     search->index = 0;
05140     search->size = 0;
05141     search->array_size = NSC_SEARCH_BLOCK_SIZE;
05142     isLoggedIn = (PRBool)((!slot->needLogin) || slot->isLoggedIn);
05143 
05144     crv = sftk_searchTokenList(slot, search, pTemplate, ulCount, &tokenOnly,
05145                                                         isLoggedIn);
05146     if (crv != CKR_OK) {
05147        goto loser;
05148     }
05149     
05150     /* build list of found objects in the session */
05151     if (!tokenOnly) {
05152        crv = sftk_searchObjectList(search, slot->sessObjHashTable, 
05153                                 slot->sessObjHashSize, slot->objectLock, 
05154                                 pTemplate, ulCount, isLoggedIn);
05155     }
05156     if (crv != CKR_OK) {
05157        goto loser;
05158     }
05159 
05160     if ((freeSearch = session->search) != NULL) {
05161        session->search = NULL;
05162        sftk_FreeSearch(freeSearch);
05163     }
05164     session->search = search;
05165     sftk_FreeSession(session);
05166     return CKR_OK;
05167 
05168 loser:
05169     if (search) {
05170        sftk_FreeSearch(search);
05171     }
05172     if (session) {
05173        sftk_FreeSession(session);
05174     }
05175     return crv;
05176 }
05177 
05178 
05179 /* NSC_FindObjects continues a search for token and session objects 
05180  * that match a template, obtaining additional object handles. */
05181 CK_RV NSC_FindObjects(CK_SESSION_HANDLE hSession,
05182     CK_OBJECT_HANDLE_PTR phObject,CK_ULONG ulMaxObjectCount,
05183                                    CK_ULONG_PTR pulObjectCount)
05184 {
05185     SFTKSession *session;
05186     SFTKSearchResults *search;
05187     int       transfer;
05188     int left;
05189 
05190     *pulObjectCount = 0;
05191     session = sftk_SessionFromHandle(hSession);
05192     if (session == NULL) return CKR_SESSION_HANDLE_INVALID;
05193     if (session->search == NULL) {
05194        sftk_FreeSession(session);
05195        return CKR_OK;
05196     }
05197     search = session->search;
05198     left = session->search->size - session->search->index;
05199     transfer = ((int)ulMaxObjectCount > left) ? left : ulMaxObjectCount;
05200     if (transfer > 0) {
05201        PORT_Memcpy(phObject,&search->handles[search->index],
05202                                         transfer*sizeof(CK_OBJECT_HANDLE_PTR));
05203     } else {
05204        *phObject = CK_INVALID_HANDLE;
05205     }
05206 
05207     search->index += transfer;
05208     if (search->index == search->size) {
05209        session->search = NULL;
05210        sftk_FreeSearch(search);
05211     }
05212     *pulObjectCount = transfer;
05213     sftk_FreeSession(session);
05214     return CKR_OK;
05215 }
05216 
05217 /* NSC_FindObjectsFinal finishes a search for token and session objects. */
05218 CK_RV NSC_FindObjectsFinal(CK_SESSION_HANDLE hSession)
05219 {
05220     SFTKSession *session;
05221     SFTKSearchResults *search;
05222 
05223     session = sftk_SessionFromHandle(hSession);
05224     if (session == NULL) return CKR_SESSION_HANDLE_INVALID;
05225     search = session->search;
05226     session->search = NULL;
05227     sftk_FreeSession(session);
05228     if (search != NULL) {
05229        sftk_FreeSearch(search);
05230     }
05231     return CKR_OK;
05232 }
05233 
05234 
05235 
05236 CK_RV NSC_WaitForSlotEvent(CK_FLAGS flags, CK_SLOT_ID_PTR pSlot,
05237                                                   CK_VOID_PTR pReserved)
05238 {
05239     return CKR_FUNCTION_NOT_SUPPORTED;
05240 }