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 "pkcs11p.h"
00059 #include "softoken.h"
00060 #include "lowkeyi.h"
00061 #include "blapi.h"
00062 #include "secder.h"
00063 #include "secport.h"
00064 #include "pcert.h"
00065 #include "secrng.h"
00066 #include "nss.h"
00067 
00068 #include "keydbi.h" 
00069 
00070 #ifdef DEBUG
00071 #include "cdbhdl.h"
00072 #endif
00073 
00074 /*
00075  * ******************** Static data *******************************
00076  */
00077 
00078 /* The next three strings must be exactly 32 characters long */
00079 static char *manufacturerID      = "Mozilla Foundation              ";
00080 static char manufacturerID_space[33];
00081 static char *libraryDescription  = "NSS Internal Crypto Services    ";
00082 static char libraryDescription_space[33];
00083 
00084 /*
00085  * In FIPS mode, we disallow login attempts for 1 second after a login
00086  * failure so that there are at most 60 login attempts per minute.
00087  */
00088 static PRIntervalTime loginWaitTime;
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 delcare 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     CK_BBOOL ckfalse = CK_FALSE;
01791     CK_BBOOL cktrue = CK_TRUE;
01792     SFTKAttribute *attribute;
01793     CK_RV crv;
01794 
01795     /* make sure all the base object types are defined. If not set the
01796      * defaults */
01797     crv = sftk_defaultAttribute(object,CKA_TOKEN,&ckfalse,sizeof(CK_BBOOL));
01798     if (crv != CKR_OK) return crv;
01799     crv = sftk_defaultAttribute(object,CKA_PRIVATE,&ckfalse,sizeof(CK_BBOOL));
01800     if (crv != CKR_OK) return crv;
01801     crv = sftk_defaultAttribute(object,CKA_LABEL,NULL,0);
01802     if (crv != CKR_OK) return crv;
01803     crv = sftk_defaultAttribute(object,CKA_MODIFIABLE,&cktrue,sizeof(CK_BBOOL));
01804     if (crv != CKR_OK) return crv;
01805 
01806     /* don't create a private object if we aren't logged in */
01807     if ((!slot->isLoggedIn) && (slot->needLogin) &&
01808                             (sftk_isTrue(object,CKA_PRIVATE))) {
01809        return CKR_USER_NOT_LOGGED_IN;
01810     }
01811 
01812 
01813     if (((session->info.flags & CKF_RW_SESSION) == 0) &&
01814                             (sftk_isTrue(object,CKA_TOKEN))) {
01815        return CKR_SESSION_READ_ONLY;
01816     }
01817        
01818     /* PKCS #11 object ID's are unique for all objects on a
01819      * token */
01820     PZ_Lock(slot->objectLock);
01821     object->handle = slot->tokenIDCount++;
01822     PZ_Unlock(slot->objectLock);
01823 
01824     /* get the object class */
01825     attribute = sftk_FindAttribute(object,CKA_CLASS);
01826     if (attribute == NULL) {
01827        return CKR_TEMPLATE_INCOMPLETE;
01828     }
01829     object->objclass = *(CK_OBJECT_CLASS *)attribute->attrib.pValue;
01830     sftk_FreeAttribute(attribute);
01831 
01832     /* now handle the specific. Get a session handle for these functions
01833      * to use */
01834     switch (object->objclass) {
01835     case CKO_DATA:
01836        crv = sftk_handleDataObject(session,object);
01837        break;
01838     case CKO_CERTIFICATE:
01839        crv = sftk_handleCertObject(session,object);
01840        break;
01841     case CKO_NETSCAPE_TRUST:
01842        crv = sftk_handleTrustObject(session,object);
01843        break;
01844     case CKO_NETSCAPE_CRL:
01845        crv = sftk_handleCrlObject(session,object);
01846        break;
01847     case CKO_NETSCAPE_SMIME:
01848        crv = sftk_handleSMimeObject(session,object);
01849        break;
01850     case CKO_PRIVATE_KEY:
01851     case CKO_PUBLIC_KEY:
01852     case CKO_SECRET_KEY:
01853        crv = sftk_handleKeyObject(session,object);
01854        break;
01855     case CKO_KG_PARAMETERS:
01856        crv = sftk_handleKeyParameterObject(session,object);
01857        break;
01858     default:
01859        crv = CKR_ATTRIBUTE_VALUE_INVALID;
01860        break;
01861     }
01862 
01863     /* can't fail from here on out unless the pk_handlXXX functions have
01864      * failed the request */
01865     if (crv != CKR_OK) {
01866        return crv;
01867     }
01868 
01869     /* now link the object into the slot and session structures */
01870     if (sftk_isToken(object->handle)) {
01871        sftk_convertSessionToToken(object);
01872     } else {
01873        object->slot = slot;
01874        sftk_AddObject(session,object);
01875     }
01876 
01877     return CKR_OK;
01878 }
01879 
01880 /*
01881  * ******************** Public Key Utilities ***************************
01882  */
01883 /* Generate a low public key structure from an object */
01884 NSSLOWKEYPublicKey *sftk_GetPubKey(SFTKObject *object,CK_KEY_TYPE key_type, 
01885                                                         CK_RV *crvp)
01886 {
01887     NSSLOWKEYPublicKey *pubKey;
01888     PLArenaPool *arena;
01889     CK_RV crv;
01890 
01891     if (object->objclass != CKO_PUBLIC_KEY) {
01892        *crvp = CKR_KEY_TYPE_INCONSISTENT;
01893        return NULL;
01894     }
01895 
01896     if (sftk_isToken(object->handle)) {
01897 /* ferret out the token object handle */
01898     }
01899 
01900     /* If we already have a key, use it */
01901     if (object->objectInfo) {
01902        *crvp = CKR_OK;
01903        return (NSSLOWKEYPublicKey *)object->objectInfo;
01904     }
01905 
01906     /* allocate the structure */
01907     arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
01908     if (arena == NULL) {
01909        *crvp = CKR_HOST_MEMORY;
01910        return NULL;
01911     }
01912 
01913     pubKey = (NSSLOWKEYPublicKey *)
01914                      PORT_ArenaAlloc(arena,sizeof(NSSLOWKEYPublicKey));
01915     if (pubKey == NULL) {
01916        PORT_FreeArena(arena,PR_FALSE);
01917        *crvp = CKR_HOST_MEMORY;
01918        return NULL;
01919     }
01920 
01921     /* fill in the structure */
01922     pubKey->arena = arena;
01923     switch (key_type) {
01924     case CKK_RSA:
01925        pubKey->keyType = NSSLOWKEYRSAKey;
01926        crv = sftk_Attribute2SSecItem(arena,&pubKey->u.rsa.modulus,
01927                                                  object,CKA_MODULUS);
01928        if (crv != CKR_OK) break;
01929        crv = sftk_Attribute2SSecItem(arena,&pubKey->u.rsa.publicExponent,
01930                                           object,CKA_PUBLIC_EXPONENT);
01931        break;
01932     case CKK_DSA:
01933        pubKey->keyType = NSSLOWKEYDSAKey;
01934        crv = sftk_Attribute2SSecItem(arena,&pubKey->u.dsa.params.prime,
01935                                                  object,CKA_PRIME);
01936        if (crv != CKR_OK) break;
01937        crv = sftk_Attribute2SSecItem(arena,&pubKey->u.dsa.params.subPrime,
01938                                                  object,CKA_SUBPRIME);
01939        if (crv != CKR_OK) break;
01940        crv = sftk_Attribute2SSecItem(arena,&pubKey->u.dsa.params.base,
01941                                                  object,CKA_BASE);
01942        if (crv != CKR_OK) break;
01943        crv = sftk_Attribute2SSecItem(arena,&pubKey->u.dsa.publicValue,
01944                                                  object,CKA_VALUE);
01945        break;
01946     case CKK_DH:
01947        pubKey->keyType = NSSLOWKEYDHKey;
01948        crv = sftk_Attribute2SSecItem(arena,&pubKey->u.dh.prime,
01949                                                  object,CKA_PRIME);
01950        if (crv != CKR_OK) break;
01951        crv = sftk_Attribute2SSecItem(arena,&pubKey->u.dh.base,
01952                                                  object,CKA_BASE);
01953        if (crv != CKR_OK) break;
01954        crv = sftk_Attribute2SSecItem(arena,&pubKey->u.dh.publicValue,
01955                                                  object,CKA_VALUE);
01956        break;
01957 #ifdef NSS_ENABLE_ECC
01958     case CKK_EC:
01959        pubKey->keyType = NSSLOWKEYECKey;
01960        crv = sftk_Attribute2SSecItem(arena,
01961                                      &pubKey->u.ec.ecParams.DEREncoding,
01962                                      object,CKA_EC_PARAMS);
01963        if (crv != CKR_OK) break;
01964 
01965        /* Fill out the rest of the ecParams structure 
01966         * based on the encoded params
01967         */
01968        if (EC_FillParams(arena, &pubKey->u.ec.ecParams.DEREncoding,
01969                   &pubKey->u.ec.ecParams) != SECSuccess) {
01970            crv = CKR_DOMAIN_PARAMS_INVALID;
01971            break;
01972        }
01973            
01974        crv = sftk_Attribute2SSecItem(arena,&pubKey->u.ec.publicValue,
01975                                      object,CKA_EC_POINT);
01976        break;
01977 #endif /* NSS_ENABLE_ECC */
01978     default:
01979        crv = CKR_KEY_TYPE_INCONSISTENT;
01980        break;
01981     }
01982     *crvp = crv;
01983     if (crv != CKR_OK) {
01984        PORT_FreeArena(arena,PR_FALSE);
01985        return NULL;
01986     }
01987 
01988     object->objectInfo = pubKey;
01989     object->infoFree = (SFTKFree) nsslowkey_DestroyPublicKey;
01990     return pubKey;
01991 }
01992 
01993 /* make a private key from a verified object */
01994 static NSSLOWKEYPrivateKey *
01995 sftk_mkPrivKey(SFTKObject *object, CK_KEY_TYPE key_type, CK_RV *crvp)
01996 {
01997     NSSLOWKEYPrivateKey *privKey;
01998     PLArenaPool *arena;
01999     CK_RV crv = CKR_OK;
02000     SECStatus rv;
02001 
02002     PORT_Assert(!sftk_isToken(object->handle));
02003     arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
02004     if (arena == NULL) {
02005        *crvp = CKR_HOST_MEMORY;
02006        return NULL;
02007     }
02008 
02009     privKey = (NSSLOWKEYPrivateKey *)
02010                      PORT_ArenaZAlloc(arena,sizeof(NSSLOWKEYPrivateKey));
02011     if (privKey == NULL)  {
02012        PORT_FreeArena(arena,PR_FALSE);
02013        *crvp = CKR_HOST_MEMORY;
02014        return NULL;
02015     }
02016 
02017     /* in future this would be a switch on key_type */
02018     privKey->arena = arena;
02019     switch (key_type) {
02020     case CKK_RSA:
02021        privKey->keyType = NSSLOWKEYRSAKey;
02022        crv=sftk_Attribute2SSecItem(arena,&privKey->u.rsa.modulus,
02023                                                  object,CKA_MODULUS);
02024        if (crv != CKR_OK) break;
02025        crv=sftk_Attribute2SSecItem(arena,&privKey->u.rsa.publicExponent,object,
02026                                                  CKA_PUBLIC_EXPONENT);
02027        if (crv != CKR_OK) break;
02028        crv=sftk_Attribute2SSecItem(arena,&privKey->u.rsa.privateExponent,object,
02029                                                  CKA_PRIVATE_EXPONENT);
02030        if (crv != CKR_OK) break;
02031        crv=sftk_Attribute2SSecItem(arena,&privKey->u.rsa.prime1,object,
02032                                                         CKA_PRIME_1);
02033        if (crv != CKR_OK) break;
02034        crv=sftk_Attribute2SSecItem(arena,&privKey->u.rsa.prime2,object,
02035                                                         CKA_PRIME_2);
02036        if (crv != CKR_OK) break;
02037        crv=sftk_Attribute2SSecItem(arena,&privKey->u.rsa.exponent1,
02038                                           object, CKA_EXPONENT_1);
02039        if (crv != CKR_OK) break;
02040        crv=sftk_Attribute2SSecItem(arena,&privKey->u.rsa.exponent2,
02041                                                  object, CKA_EXPONENT_2);
02042        if (crv != CKR_OK) break;
02043        crv=sftk_Attribute2SSecItem(arena,&privKey->u.rsa.coefficient,object,
02044                                                        CKA_COEFFICIENT);
02045        if (crv != CKR_OK) break;
02046         rv = DER_SetUInteger(privKey->arena, &privKey->u.rsa.version,
02047                           NSSLOWKEY_VERSION);
02048        if (rv != SECSuccess) crv = CKR_HOST_MEMORY;
02049        break;
02050 
02051     case CKK_DSA:
02052        privKey->keyType = NSSLOWKEYDSAKey;
02053        crv = sftk_Attribute2SSecItem(arena,&privKey->u.dsa.params.prime,
02054                                                  object,CKA_PRIME);
02055        if (crv != CKR_OK) break;
02056        crv = sftk_Attribute2SSecItem(arena,&privKey->u.dsa.params.subPrime,
02057                                                  object,CKA_SUBPRIME);
02058        if (crv != CKR_OK) break;
02059        crv = sftk_Attribute2SSecItem(arena,&privKey->u.dsa.params.base,
02060                                                  object,CKA_BASE);
02061        if (crv != CKR_OK) break;
02062        crv = sftk_Attribute2SSecItem(arena,&privKey->u.dsa.privateValue,
02063                                                  object,CKA_VALUE);
02064        if (crv != CKR_OK) break;
02065        if (sftk_hasAttribute(object,CKA_NETSCAPE_DB)) {
02066            crv = sftk_Attribute2SSecItem(arena, &privKey->u.dsa.publicValue,
02067                                   object,CKA_NETSCAPE_DB);
02068            /* privKey was zero'd so public value is already set to NULL, 0
02069             * if we don't set it explicitly */
02070        }
02071        break;
02072 
02073     case CKK_DH:
02074        privKey->keyType = NSSLOWKEYDHKey;
02075        crv = sftk_Attribute2SSecItem(arena,&privKey->u.dh.prime,
02076                                                  object,CKA_PRIME);
02077        if (crv != CKR_OK) break;
02078        crv = sftk_Attribute2SSecItem(arena,&privKey->u.dh.base,
02079                                                  object,CKA_BASE);
02080        if (crv != CKR_OK) break;
02081        crv = sftk_Attribute2SSecItem(arena,&privKey->u.dh.privateValue,
02082                                                  object,CKA_VALUE);
02083        if (crv != CKR_OK) break;
02084        if (sftk_hasAttribute(object,CKA_NETSCAPE_DB)) {
02085            crv = sftk_Attribute2SSecItem(arena, &privKey->u.dh.publicValue,
02086                                   object,CKA_NETSCAPE_DB);
02087            /* privKey was zero'd so public value is already set to NULL, 0
02088             * if we don't set it explicitly */
02089        }
02090        break;
02091 
02092 #ifdef NSS_ENABLE_ECC
02093     case CKK_EC:
02094        privKey->keyType = NSSLOWKEYECKey;
02095        crv = sftk_Attribute2SSecItem(arena, 
02096                                      &privKey->u.ec.ecParams.DEREncoding,
02097                                      object,CKA_EC_PARAMS);
02098        if (crv != CKR_OK) break;
02099 
02100        /* Fill out the rest of the ecParams structure
02101         * based on the encoded params
02102         */
02103        if (EC_FillParams(arena, &privKey->u.ec.ecParams.DEREncoding,
02104                   &privKey->u.ec.ecParams) != SECSuccess) {
02105            crv = CKR_DOMAIN_PARAMS_INVALID;
02106            break;
02107        }
02108        crv = sftk_Attribute2SSecItem(arena,&privKey->u.ec.privateValue,
02109                                                  object,CKA_VALUE);
02110        if (crv != CKR_OK) break;
02111        if (sftk_hasAttribute(object,CKA_NETSCAPE_DB)) {
02112            crv = sftk_Attribute2SSecItem(arena, &privKey->u.ec.publicValue,
02113                                   object,CKA_NETSCAPE_DB);
02114            if (crv != CKR_OK) break;
02115            /* privKey was zero'd so public value is already set to NULL, 0
02116             * if we don't set it explicitly */
02117        }
02118         rv = DER_SetUInteger(privKey->arena, &privKey->u.ec.version,
02119                           NSSLOWKEY_EC_PRIVATE_KEY_VERSION);
02120        if (rv != SECSuccess) crv = CKR_HOST_MEMORY;
02121        break;
02122 #endif /* NSS_ENABLE_ECC */
02123 
02124     default:
02125        crv = CKR_KEY_TYPE_INCONSISTENT;
02126        break;
02127     }
02128     *crvp = crv;
02129     if (crv != CKR_OK) {
02130        PORT_FreeArena(arena,PR_FALSE);
02131        return NULL;
02132     }
02133     return privKey;
02134 }
02135 
02136 
02137 /* Generate a low private key structure from an object */
02138 NSSLOWKEYPrivateKey *
02139 sftk_GetPrivKey(SFTKObject *object,CK_KEY_TYPE key_type, CK_RV *crvp)
02140 {
02141     NSSLOWKEYPrivateKey *priv = NULL;
02142 
02143     if (object->objclass != CKO_PRIVATE_KEY) {
02144        *crvp = CKR_KEY_TYPE_INCONSISTENT;
02145        return NULL;
02146     }
02147     if (object->objectInfo) {
02148        *crvp = CKR_OK;
02149        return (NSSLOWKEYPrivateKey *)object->objectInfo;
02150     }
02151 
02152     if (sftk_isToken(object->handle)) {
02153        /* grab it from the data base */
02154        SFTKTokenObject *to = sftk_narrowToTokenObject(object);
02155 
02156        PORT_Assert(to);
02157        priv = sftk_FindKeyByPublicKey(object->slot, &to->dbKey);
02158        *crvp = (priv == NULL) ? CKR_DEVICE_ERROR : CKR_OK;
02159     } else {
02160        priv = sftk_mkPrivKey(object, key_type, crvp);
02161     }
02162     object->objectInfo = priv;
02163     object->infoFree = (SFTKFree) nsslowkey_DestroyPrivateKey;
02164     return priv;
02165 }
02166 
02167 /*
02168  **************************** Symetric Key utils ************************
02169  */
02170 /*
02171  * set the DES key with parity bits correctly
02172  */
02173 void
02174 sftk_FormatDESKey(unsigned char *key, int length)
02175 {
02176     int i;
02177 
02178     /* format the des key */
02179     for (i=0; i < length; i++) {
02180        key[i] = parityTable[key[i]>>1];
02181     }
02182 }
02183 
02184 /*
02185  * check a des key (des2 or des3 subkey) for weak keys.
02186  */
02187 PRBool
02188 sftk_CheckDESKey(unsigned char *key)
02189 {
02190     int i;
02191 
02192     /* format the des key with parity  */
02193     sftk_FormatDESKey(key, 8);
02194 
02195     for (i=0; i < sftk_desWeakTableSize; i++) {
02196        if (PORT_Memcmp(key,sftk_desWeakTable[i],8) == 0) {
02197            return PR_TRUE;
02198        }
02199     }
02200     return PR_FALSE;
02201 }
02202 
02203 /*
02204  * check if a des or triple des key is weak.
02205  */
02206 PRBool
02207 sftk_IsWeakKey(unsigned char *key,CK_KEY_TYPE key_type)
02208 {
02209 
02210     switch(key_type) {
02211     case CKK_DES:
02212        return sftk_CheckDESKey(key);
02213     case CKM_DES2_KEY_GEN:
02214        if (sftk_CheckDESKey(key)) return PR_TRUE;
02215        return sftk_CheckDESKey(&key[8]);
02216     case CKM_DES3_KEY_GEN:
02217        if (sftk_CheckDESKey(key)) return PR_TRUE;
02218        if (sftk_CheckDESKey(&key[8])) return PR_TRUE;
02219        return sftk_CheckDESKey(&key[16]);
02220     default:
02221        break;
02222     }
02223     return PR_FALSE;
02224 }
02225 
02226 
02227 /* make a fake private key representing a symmetric key */
02228 static NSSLOWKEYPrivateKey *
02229 sftk_mkSecretKeyRep(SFTKObject *object)
02230 {
02231     NSSLOWKEYPrivateKey *privKey = 0;
02232     PLArenaPool *arena = 0;
02233     CK_KEY_TYPE keyType;
02234     PRUint32 keyTypeStorage;
02235     SECItem keyTypeItem;
02236     CK_RV crv;
02237     SECStatus rv;
02238     static unsigned char derZero[1] = { 0 };
02239 
02240     arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
02241     if (arena == NULL) { crv = CKR_HOST_MEMORY; goto loser; }
02242 
02243     privKey = (NSSLOWKEYPrivateKey *)
02244                      PORT_ArenaZAlloc(arena,sizeof(NSSLOWKEYPrivateKey));
02245     if (privKey == NULL) { crv = CKR_HOST_MEMORY; goto loser; }
02246 
02247     privKey->arena = arena;
02248 
02249     /* Secret keys are represented in the database as "fake" RSA keys.  The RSA key
02250      * is marked as a secret key representation by setting the public exponent field
02251      * to 0, which is an invalid RSA exponent.  The other fields are set as follows:
02252      *   modulus - CKA_ID value for the secret key
02253      *   private exponent - CKA_VALUE (the key itself)
02254      *   coefficient - CKA_KEY_TYPE, which indicates what encryption algorithm
02255      *      is used for the key.
02256      *   all others - set to integer 0
02257      */
02258     privKey->keyType = NSSLOWKEYRSAKey;
02259 
02260     /* The modulus is set to the key id of the symmetric key */
02261     crv=sftk_Attribute2SecItem(arena,&privKey->u.rsa.modulus,object,CKA_ID);
02262     if (crv != CKR_OK) goto loser;
02263 
02264     /* The public exponent is set to 0 length to indicate a special key */
02265     privKey->u.rsa.publicExponent.len = sizeof derZero;
02266     privKey->u.rsa.publicExponent.data = derZero;
02267 
02268     /* The private exponent is the actual key value */
02269     crv=sftk_Attribute2SecItem(arena,&privKey->u.rsa.privateExponent,object,CKA_VALUE);
02270     if (crv != CKR_OK) goto loser;
02271 
02272     /* All other fields empty - needs testing */
02273     privKey->u.rsa.prime1.len = sizeof derZero;
02274     privKey->u.rsa.prime1.data = derZero;
02275 
02276     privKey->u.rsa.prime2.len = sizeof derZero;
02277     privKey->u.rsa.prime2.data = derZero;
02278 
02279     privKey->u.rsa.exponent1.len = sizeof derZero;
02280     privKey->u.rsa.exponent1.data = derZero;
02281 
02282     privKey->u.rsa.exponent2.len = sizeof derZero;
02283     privKey->u.rsa.exponent2.data = derZero;
02284 
02285     /* Coeficient set to KEY_TYPE */
02286     crv = sftk_GetULongAttribute(object, CKA_KEY_TYPE, &keyType);
02287     if (crv != CKR_OK) goto loser; 
02288     /* on 64 bit platforms, we still want to store 32 bits of keyType (This is
02289      * safe since the PKCS #11 defines for all types are 32 bits or less). */
02290     keyTypeStorage = (PRUint32) keyType;
02291     keyTypeStorage = PR_htonl(keyTypeStorage);
02292     keyTypeItem.data = (unsigned char *)&keyTypeStorage;
02293     keyTypeItem.len = sizeof (keyTypeStorage);
02294     rv = SECITEM_CopyItem(arena, &privKey->u.rsa.coefficient, &keyTypeItem);
02295     if (rv != SECSuccess) {
02296        crv = CKR_HOST_MEMORY;
02297        goto loser;
02298     }
02299     
02300     /* Private key version field set normally for compatibility */
02301     rv = DER_SetUInteger(privKey->arena, 
02302                      &privKey->u.rsa.version, NSSLOWKEY_VERSION);
02303     if (rv != SECSuccess) { crv = CKR_HOST_MEMORY; goto loser; }
02304 
02305 loser:
02306     if (crv != CKR_OK) {
02307        PORT_FreeArena(arena,PR_FALSE);
02308        privKey = 0;
02309     }
02310 
02311     return privKey;
02312 }
02313 
02314 static PRBool
02315 isSecretKey(NSSLOWKEYPrivateKey *privKey)
02316 {
02317   if (privKey->keyType == NSSLOWKEYRSAKey && 
02318               privKey->u.rsa.publicExponent.len == 1 &&
02319                             privKey->u.rsa.publicExponent.data[0] == 0)
02320     return PR_TRUE;
02321 
02322   return PR_FALSE;
02323 }
02324 
02325 /**********************************************************************
02326  *
02327  *     Start of PKCS 11 functions 
02328  *
02329  **********************************************************************/
02330 
02331 
02332 /* return the function list */
02333 CK_RV NSC_GetFunctionList(CK_FUNCTION_LIST_PTR *pFunctionList)
02334 {
02335     *pFunctionList = (CK_FUNCTION_LIST_PTR) &sftk_funcList;
02336     return CKR_OK;
02337 }
02338 
02339 /* return the function list */
02340 CK_RV C_GetFunctionList(CK_FUNCTION_LIST_PTR *pFunctionList)
02341 {
02342     return NSC_GetFunctionList(pFunctionList);
02343 }
02344 
02345 static PLHashNumber
02346 sftk_HashNumber(const void *key)
02347 {
02348     return (PLHashNumber) key;
02349 }
02350 
02351 /*
02352  * eventually I'd like to expunge all occurances of XXX_SLOT_ID and
02353  * just go with the info in the slot. This is one place, however,
02354  * where it might be a little difficult.
02355  */
02356 const char *
02357 sftk_getDefTokName(CK_SLOT_ID slotID)
02358 {
02359     static char buf[33];
02360 
02361     switch (slotID) {
02362     case NETSCAPE_SLOT_ID:
02363        return "NSS Generic Crypto Services     ";
02364     case PRIVATE_KEY_SLOT_ID:
02365        return "NSS Certificate DB              ";
02366     case FIPS_SLOT_ID:
02367         return "NSS FIPS 140-2 Certificate DB   ";
02368     default:
02369        break;
02370     }
02371     sprintf(buf,"NSS Application Token %08x  ",(unsigned int) slotID);
02372     return buf;
02373 }
02374 
02375 const char *
02376 sftk_getDefSlotName(CK_SLOT_ID slotID)
02377 {
02378     static char buf[65];
02379 
02380     switch (slotID) {
02381     case NETSCAPE_SLOT_ID:
02382        return 
02383         "NSS Internal Cryptographic Services                             ";
02384     case PRIVATE_KEY_SLOT_ID:
02385        return 
02386         "NSS User Private Key and Certificate Services                   ";
02387     case FIPS_SLOT_ID:
02388         return 
02389          "NSS FIPS 140-2 User Private Key Services                        ";
02390     default:
02391        break;
02392     }
02393     sprintf(buf,
02394      "NSS Application Slot %08x                                   ",
02395                                                  (unsigned int) slotID);
02396     return buf;
02397 }
02398 
02399 static CK_ULONG nscSlotCount[2] = {0 , 0};
02400 static CK_SLOT_ID_PTR nscSlotList[2] = {NULL, NULL};
02401 static CK_ULONG nscSlotListSize[2] = {0, 0};
02402 static PLHashTable *nscSlotHashTable[2] = {NULL, NULL};
02403 
02404 static int
02405 sftk_GetModuleIndex(CK_SLOT_ID slotID)
02406 {
02407     if ((slotID == FIPS_SLOT_ID) || (slotID >= SFTK_MIN_FIPS_USER_SLOT_ID)) {
02408        return NSC_FIPS_MODULE;
02409     }
02410     return NSC_NON_FIPS_MODULE;
02411 }
02412 
02413 /* look up a slot structure from the ID (used to be a macro when we only
02414  * had two slots) */
02415 /* if all is true, return the slot even if it has been 'unloaded' */
02416 /* if all is false, only return the slots which are present */
02417 SFTKSlot *
02418 sftk_SlotFromID(CK_SLOT_ID slotID, PRBool all)
02419 {
02420     SFTKSlot *slot;
02421     int index = sftk_GetModuleIndex(slotID);
02422     
02423     if (nscSlotHashTable[index] == NULL) return NULL;
02424     slot = (SFTKSlot *)PL_HashTableLookupConst(nscSlotHashTable[index], 
02425                                                  (void *)slotID);
02426     /* cleared slots shouldn't 'show up' */
02427     if (slot && !all && !slot->present) slot = NULL;
02428     return slot;
02429 }
02430 
02431 SFTKSlot *
02432 sftk_SlotFromSessionHandle(CK_SESSION_HANDLE handle)
02433 {
02434     CK_ULONG slotIDIndex = (handle >> 24) & 0x7f;
02435     CK_ULONG moduleIndex = (handle >> 31) & 1;
02436 
02437     if (slotIDIndex >= nscSlotCount[moduleIndex]) {
02438        return NULL;
02439     }
02440 
02441     return sftk_SlotFromID(nscSlotList[moduleIndex][slotIDIndex], PR_FALSE);
02442 }
02443  
02444 static CK_RV
02445 sftk_RegisterSlot(SFTKSlot *slot, int moduleIndex)
02446 {
02447     PLHashEntry *entry;
02448     int index;
02449 
02450     index = sftk_GetModuleIndex(slot->slotID);
02451 
02452     /* make sure the slotID for this module is valid */
02453     if (moduleIndex != index) {
02454        return CKR_SLOT_ID_INVALID;
02455     }
02456 
02457     if (nscSlotList[index] == NULL) {
02458        nscSlotListSize[index] = NSC_SLOT_LIST_BLOCK_SIZE;
02459        nscSlotList[index] = (CK_SLOT_ID *)
02460               PORT_ZAlloc(nscSlotListSize[index]*sizeof(CK_SLOT_ID));
02461        if (nscSlotList[index] == NULL) {
02462            return CKR_HOST_MEMORY;
02463        }
02464     }
02465     if (nscSlotCount[index] >= nscSlotListSize[index]) {
02466        CK_SLOT_ID* oldNscSlotList = nscSlotList[index];
02467        CK_ULONG oldNscSlotListSize = nscSlotListSize[index];
02468        nscSlotListSize[index] += NSC_SLOT_LIST_BLOCK_SIZE;
02469        nscSlotList[index] = (CK_SLOT_ID *) PORT_Realloc(oldNscSlotList,
02470                             nscSlotListSize[index]*sizeof(CK_SLOT_ID));
02471        if (nscSlotList[index] == NULL) {
02472             nscSlotList[index] = oldNscSlotList;
02473             nscSlotListSize[index] = oldNscSlotListSize;
02474             return CKR_HOST_MEMORY;
02475        }
02476     }
02477 
02478     if (nscSlotHashTable[index] == NULL) {
02479        nscSlotHashTable[index] = PL_NewHashTable(64,sftk_HashNumber,
02480                             PL_CompareValues, PL_CompareValues, NULL, 0);
02481        if (nscSlotHashTable[index] == NULL) {
02482            return CKR_HOST_MEMORY;
02483        }
02484     }
02485 
02486     entry = PL_HashTableAdd(nscSlotHashTable[index],(void *)slot->slotID,slot);
02487     if (entry == NULL) {
02488        return CKR_HOST_MEMORY;
02489     }
02490     slot->index = (nscSlotCount[index] & 0x7f) | ((index << 7) & 0x80);
02491     nscSlotList[index][nscSlotCount[index]++] = slot->slotID;
02492 
02493     return CKR_OK;
02494 }
02495 
02496 typedef struct sftk_DBsStr {
02497     NSSLOWCERTCertDBHandle *certHandle;
02498     NSSLOWKEYDBHandle *keyHandle;
02499 } sftkDBs;
02500 
02501 static SECStatus
02502 sftk_set_user(NSSLOWCERTCertificate *cert, SECItem *dummy, void *arg)
02503 {
02504     sftkDBs *param = (sftkDBs *)arg;
02505     NSSLOWCERTCertTrust trust = *cert->trust;
02506 
02507     if (param->keyHandle && 
02508                 nsslowkey_KeyForCertExists(param->keyHandle,cert)) {
02509        trust.sslFlags |= CERTDB_USER;
02510        trust.emailFlags |= CERTDB_USER;
02511        trust.objectSigningFlags |= CERTDB_USER;
02512     } else {
02513        trust.sslFlags &= ~CERTDB_USER;
02514        trust.emailFlags &= ~CERTDB_USER;
02515        trust.objectSigningFlags &= ~CERTDB_USER;
02516     }
02517 
02518     if (PORT_Memcmp(&trust,cert->trust, sizeof (trust)) != 0) {
02519        nsslowcert_ChangeCertTrust(param->certHandle, cert, &trust);
02520     }
02521 
02522     /* should check for email address and make sure we have an s/mime profile */
02523     return SECSuccess;
02524 }
02525 
02526 /*
02527  * this function fixes up old databases that may not have the CERTDB_USER
02528  * flags set correctly. it expects the owner already has references to
02529  * the cert and key handles.
02530  */
02531 static  void
02532 sftk_DBVerify(NSSLOWCERTCertDBHandle *certHandle, NSSLOWKEYDBHandle *keyHandle)
02533 {
02534     /* walk through all the certs and check to see if there are any 
02535      * user certs, and make sure there are s/mime profiles for all certs with
02536      * email addresses */
02537     sftkDBs param;
02538     param.certHandle = certHandle;
02539     param.keyHandle = keyHandle;
02540 
02541     nsslowcert_TraversePermCerts(certHandle, sftk_set_user, &param);
02542 
02543     return;
02544 }
02545 
02546 
02547 /*
02548  * ths function has all the common initialization that happens whenever we
02549  * create a new slot or repurpose an old slot (only valid for slotID's 4 
02550  * and greater).
02551  *
02552  * things that are not reinitialized are:
02553  *   slotID (can't change)
02554  *   slotDescription (can't change once defined) 
02555  *   the locks and hash tables (difficult to change in running code, and
02556  *     unnecessary. hash tables and list are cleared on shutdown, but they
02557  *     are cleared in a 'friendly' way).
02558  *   session and object ID counters -- so any old sessions and objects in the
02559  *     application will get properly notified that the world has changed.
02560  * 
02561  * things that are reinitialized:
02562  *   database (otherwise what would the point be;).
02563  *   state variables related to databases.
02564  *   session count stat info.
02565  *   tokenDescription.
02566  *
02567  * NOTE: slotID's 4 and greater show up as removable devices.
02568  *
02569  */
02570 CK_RV
02571 SFTK_SlotReInit(SFTKSlot *slot,
02572        char *configdir,sftk_token_parameters *params, int moduleIndex)
02573 {
02574     PRBool needLogin = !params->noKeyDB;
02575     CK_RV crv;
02576 
02577     slot->hasTokens = PR_FALSE;
02578     slot->sessionIDConflict = 0;
02579     slot->sessionCount = 0;
02580     slot->rwSessionCount = 0;
02581     slot->needLogin = PR_FALSE;
02582     slot->isLoggedIn = PR_FALSE;
02583     slot->ssoLoggedIn = PR_FALSE;
02584     slot->DB_loaded = PR_FALSE;
02585     slot->certDB = NULL;
02586     slot->keyDB = NULL;
02587     slot->minimumPinLen = 0;
02588     slot->readOnly = params->readOnly;
02589     sftk_setStringName(params->tokdes ? params->tokdes : 
02590        sftk_getDefTokName(slot->slotID), slot->tokDescription, 
02591                                           sizeof(slot->tokDescription));
02592 
02593     if ((!params->noCertDB) || (!params->noKeyDB)) {
02594        NSSLOWCERTCertDBHandle * certHandle = NULL;
02595        NSSLOWKEYDBHandle *keyHandle = NULL;
02596        crv = sftk_DBInit(params->configdir ? params->configdir : configdir,
02597               params->certPrefix, params->keyPrefix, params->readOnly,
02598               params->noCertDB, params->noKeyDB, params->forceOpen, 
02599                                           &certHandle, &keyHandle);
02600        if (crv != CKR_OK) {
02601            goto loser;
02602        }
02603 
02604        if (nsslowcert_needDBVerify(certHandle)) {
02605            sftk_DBVerify(certHandle, keyHandle);
02606        }
02607        slot->certDB = certHandle;
02608        slot->keyDB = keyHandle;
02609     }
02610     if (needLogin) {
02611        /* if the data base is initialized with a null password,remember that */
02612        slot->needLogin = 
02613               (PRBool)!sftk_hasNullPassword(slot->keyDB,&slot->password);
02614        if ((params->minPW >= 0) && (params->minPW <= SFTK_MAX_PIN)) {
02615            slot->minimumPinLen = params->minPW;
02616        }
02617        if ((slot->minimumPinLen == 0) && (params->pwRequired)) {
02618            slot->minimumPinLen = 1;
02619        }
02620        if ((moduleIndex == NSC_FIPS_MODULE) &&
02621               (slot->minimumPinLen < FIPS_MIN_PIN)) {
02622            slot->minimumPinLen = FIPS_MIN_PIN;
02623        }
02624     }
02625 
02626     slot->present = PR_TRUE;
02627     return CKR_OK;
02628 
02629 loser:
02630     SFTK_ShutdownSlot(slot);
02631     return crv;
02632 }
02633 
02634 /*
02635  * initialize one of the slot structures. figure out which by the ID
02636  */
02637 CK_RV
02638 SFTK_SlotInit(char *configdir,sftk_token_parameters *params, int moduleIndex)
02639 {
02640     unsigned int i;
02641     CK_SLOT_ID slotID = params->slotID;
02642     SFTKSlot *slot;
02643     CK_RV crv = CKR_HOST_MEMORY;
02644 
02645     /*
02646      * first we initialize everything that is 'permanent' with this slot.
02647      * that is everything we aren't going to shutdown if we close this slot
02648      * and open it up again with different databases */
02649 
02650     slot = PORT_ZNew(SFTKSlot);
02651 
02652     if (slot == NULL) {
02653        return CKR_HOST_MEMORY;
02654     }
02655 
02656     slot->optimizeSpace = params->optimizeSpace;
02657     if (slot->optimizeSpace) {
02658        slot->tokObjHashSize = SPACE_TOKEN_OBJECT_HASH_SIZE;
02659        slot->sessHashSize = SPACE_SESSION_HASH_SIZE;
02660        slot->numSessionLocks = 1;
02661     } else {
02662        slot->tokObjHashSize = TIME_TOKEN_OBJECT_HASH_SIZE;
02663        slot->sessHashSize = TIME_SESSION_HASH_SIZE;
02664        slot->numSessionLocks = slot->sessHashSize/BUCKETS_PER_SESSION_LOCK;
02665     }
02666     slot->sessionLockMask = slot->numSessionLocks-1;
02667 
02668     slot->slotLock = PZ_NewLock(nssILockSession);
02669     if (slot->slotLock == NULL)
02670        goto mem_loser;
02671     slot->sessionLock = PORT_ZNewArray(PZLock *, slot->numSessionLocks);
02672     if (slot->sessionLock == NULL)
02673        goto mem_loser;
02674     for (i=0; i < slot->numSessionLocks; i++) {
02675         slot->sessionLock[i] = PZ_NewLock(nssILockSession);
02676         if (slot->sessionLock[i] == NULL) 
02677            goto mem_loser;
02678     }
02679     slot->objectLock = PZ_NewLock(nssILockObject);
02680     if (slot->objectLock == NULL) 
02681        goto mem_loser;
02682     slot->pwCheckLock = PR_NewLock();
02683     if (slot->pwCheckLock == NULL) 
02684        goto mem_loser;
02685     slot->head = PORT_ZNewArray(SFTKSession *, slot->sessHashSize);
02686     if (slot->head == NULL) 
02687        goto mem_loser;
02688     slot->tokObjects = PORT_ZNewArray(SFTKObject *, slot->tokObjHashSize);
02689     if (slot->tokObjects == NULL) 
02690        goto mem_loser;
02691     slot->tokenHashTable = PL_NewHashTable(64,sftk_HashNumber,PL_CompareValues,
02692                                    SECITEM_HashCompare, NULL, 0);
02693     if (slot->tokenHashTable == NULL) 
02694        goto mem_loser;
02695 
02696     slot->sessionIDCount = 0;
02697     slot->tokenIDCount = 1;
02698     slot->slotID = slotID;
02699     sftk_setStringName(params->slotdes ? params->slotdes : 
02700              sftk_getDefSlotName(slotID), slot->slotDescription, 
02701                                           sizeof(slot->slotDescription));
02702 
02703     /* call the reinit code to set everything that changes between token
02704      * init calls */
02705     crv = SFTK_SlotReInit(slot, configdir, params, moduleIndex);
02706     if (crv != CKR_OK) {
02707        goto loser;
02708     }
02709     crv = sftk_RegisterSlot(slot, moduleIndex);
02710     if (crv != CKR_OK) {
02711        goto loser;
02712     }
02713     return CKR_OK;
02714 
02715 mem_loser:
02716     crv = CKR_HOST_MEMORY;
02717 loser:
02718    SFTK_DestroySlotData(slot);
02719     return crv;
02720 }
02721 
02722 
02723 static CK_RV sft_CloseAllSession(SFTKSlot *slot)
02724 {
02725     SECItem *pw = NULL;
02726     SFTKSession *session;
02727     unsigned int i;
02728     /* first log out the card */
02729     PZ_Lock(slot->slotLock);
02730     pw = slot->password;
02731     slot->isLoggedIn = PR_FALSE;
02732     slot->password = NULL;
02733     PZ_Unlock(slot->slotLock);
02734     if (pw) SECITEM_ZfreeItem(pw, PR_TRUE);
02735 
02736     /* now close all the current sessions */
02737     /* NOTE: If you try to open new sessions before NSC_CloseAllSessions
02738      * completes, some of those new sessions may or may not be closed by
02739      * NSC_CloseAllSessions... but any session running when this code starts
02740      * will guarrenteed be close, and no session will be partially closed */
02741     for (i=0; i < slot->sessHashSize; i++) {
02742        PZLock *lock = SFTK_SESSION_LOCK(slot,i);
02743        do {
02744            PZ_Lock(lock);
02745            session = slot->head[i];
02746            /* hand deque */
02747            /* this duplicates function of NSC_close session functions, but 
02748             * because we know that we are freeing all the sessions, we can
02749             * do more efficient processing */
02750            if (session) {
02751               slot->head[i] = session->next;
02752               if (session->next) session->next->prev = NULL;
02753               session->next = session->prev = NULL;
02754               PZ_Unlock(lock);
02755               PZ_Lock(slot->slotLock);
02756               --slot->sessionCount;
02757               PZ_Unlock(slot->slotLock);
02758               if (session->info.flags & CKF_RW_SESSION) {
02759                   PR_AtomicDecrement(&slot->rwSessionCount);
02760               }
02761            } else {
02762               PZ_Unlock(lock);
02763            }
02764            if (session) sftk_FreeSession(session);
02765        } while (session != NULL);
02766     }
02767     return CKR_OK;
02768 }
02769 
02770 /*
02771  * shut down the databases.
02772  * we get the slot lock (which also protects slot->certDB and slot->keyDB)
02773  * and clear the values so the new users will not find the databases.
02774  * once things are clear, we can release our references to the databases.
02775  * The databases will close when the last reference is released.
02776  *
02777  * We use reference counts so that we don't crash if someone shuts down
02778  * a token that another thread is actively using.
02779  */
02780 static void
02781 sftk_DBShutdown(SFTKSlot *slot)
02782 {
02783     NSSLOWCERTCertDBHandle *certHandle;
02784     NSSLOWKEYDBHandle      *keyHandle;
02785     PZ_Lock(slot->slotLock);
02786     certHandle = slot->certDB;
02787     slot->certDB = NULL;
02788     keyHandle = slot->keyDB;
02789     slot->keyDB = NULL;
02790     PZ_Unlock(slot->slotLock);
02791     if (certHandle) {
02792        PORT_Assert(certHandle->ref == 1 || slot->slotID > FIPS_SLOT_ID);
02793        sftk_freeCertDB(certHandle);
02794     }
02795     if (keyHandle) {
02796        PORT_Assert(keyHandle->ref == 1 || slot->slotID > FIPS_SLOT_ID);
02797        sftk_freeKeyDB(keyHandle);
02798     }
02799 }
02800 
02801 CK_RV
02802 SFTK_ShutdownSlot(SFTKSlot *slot)
02803 {
02804     /* make sure no new PK11 calls work except C_GetSlotInfo */
02805     slot->present = PR_FALSE;
02806 
02807     /* close all outstanding sessions
02808      * the sessHashSize variable guarentees we have all the session
02809      * mechanism set up */
02810     if (slot->head) {
02811        sft_CloseAllSession(slot);
02812      }
02813 
02814     /* clear all objects.. session objects are cleared as a result of
02815      * closing all the sessions. We just need to clear the token object
02816      * cache. slot->tokenHashTable guarentees we have the token 
02817      * infrastructure set up. */
02818     if (slot->tokenHashTable) {
02819        SFTK_ClearTokenKeyHashTable(slot);
02820     }
02821 
02822     /* clear the slot description for the next guy */
02823     PORT_Memset(slot->tokDescription, 0, sizeof(slot->tokDescription));
02824 
02825     /* now shut down the databases. */
02826     sftk_DBShutdown(slot);
02827     return CKR_OK;
02828 }
02829 
02830 /*
02831  * initialize one of the slot structures. figure out which by the ID
02832  */
02833 CK_RV
02834 SFTK_DestroySlotData(SFTKSlot *slot)
02835 {
02836     unsigned int i;
02837 
02838     SFTK_ShutdownSlot(slot);
02839 
02840     if (slot->tokenHashTable) {
02841        PL_HashTableDestroy(slot->tokenHashTable);
02842        slot->tokenHashTable = NULL;
02843     }
02844 
02845     if (slot->tokObjects) {
02846        PORT_Free(slot->tokObjects);
02847        slot->tokObjects = NULL;
02848     }
02849     slot->tokObjHashSize = 0;
02850 
02851     if (slot->head) {
02852        PORT_Free(slot->head);
02853        slot->head = NULL;
02854     }
02855     slot->sessHashSize = 0;
02856 
02857     /* OK everything has been disassembled, now we can finally get rid
02858      * of the locks */
02859     if (slot->slotLock) {
02860        PZ_DestroyLock(slot->slotLock);
02861        slot->slotLock = NULL;
02862     }
02863     if (slot->sessionLock) {
02864        for (i=0; i < slot->numSessionLocks; i++) {
02865            if (slot->sessionLock[i]) {
02866               PZ_DestroyLock(slot->sessionLock[i]);
02867               slot->sessionLock[i] = NULL;
02868            }
02869        }
02870        PORT_Free(slot->sessionLock);
02871        slot->sessionLock = NULL;
02872     }
02873     if (slot->objectLock) {
02874        PZ_DestroyLock(slot->objectLock);
02875        slot->objectLock = NULL;
02876     }
02877     if (slot->pwCheckLock) {
02878        PR_DestroyLock(slot->pwCheckLock);
02879        slot->pwCheckLock = NULL;
02880     }
02881     PORT_Free(slot);
02882     return CKR_OK;
02883 }
02884 
02885 /*
02886  * handle the SECMOD.db
02887  */
02888 char **
02889 NSC_ModuleDBFunc(unsigned long function,char *parameters, void *args)
02890 {
02891     char *secmod = NULL;
02892     char *appName = NULL;
02893     char *filename = NULL;
02894     PRBool rw;
02895     static char *success="Success";
02896     char **rvstr = NULL;
02897 
02898     secmod = secmod_getSecmodName(parameters,&appName,&filename, &rw);
02899 
02900     switch (function) {
02901     case SECMOD_MODULE_DB_FUNCTION_FIND:
02902        rvstr = secmod_ReadPermDB(appName,filename,secmod,(char *)parameters,rw);
02903        break;
02904     case SECMOD_MODULE_DB_FUNCTION_ADD:
02905        rvstr = (secmod_AddPermDB(appName,filename,secmod,(char *)args,rw) 
02906                             == SECSuccess) ? &success: NULL;
02907        break;
02908     case SECMOD_MODULE_DB_FUNCTION_DEL:
02909        rvstr = (secmod_DeletePermDB(appName,filename,secmod,(char *)args,rw)
02910                              == SECSuccess) ? &success: NULL;
02911        break;
02912     case SECMOD_MODULE_DB_FUNCTION_RELEASE:
02913        rvstr = (secmod_ReleasePermDBData(appName,filename,secmod,
02914                      (char **)args,rw) == SECSuccess) ? &success: NULL;
02915        break;
02916     }
02917     if (secmod) PR_smprintf_free(secmod);
02918     if (appName) PORT_Free(appName);
02919     if (filename) PORT_Free(filename);
02920     return rvstr;
02921 }
02922 
02923 static void nscFreeAllSlots(int moduleIndex)
02924 {
02925     /* free all the slots */
02926     SFTKSlot *slot = NULL;
02927     CK_SLOT_ID slotID;
02928     int i;
02929 
02930     if (nscSlotList[moduleIndex]) {
02931        CK_ULONG tmpSlotCount = nscSlotCount[moduleIndex];
02932        CK_SLOT_ID_PTR tmpSlotList = nscSlotList[moduleIndex];
02933        PLHashTable *tmpSlotHashTable = nscSlotHashTable[moduleIndex];
02934 
02935        /* first close all the session */
02936        for (i=0; i < (int) tmpSlotCount; i++) {
02937            slotID = tmpSlotList[i];
02938            (void) NSC_CloseAllSessions(slotID);
02939        }
02940 
02941        /* now clear out the statics */
02942        nscSlotList[moduleIndex] = NULL;
02943        nscSlotCount[moduleIndex] = 0;
02944        nscSlotHashTable[moduleIndex] = NULL;
02945        nscSlotListSize[moduleIndex] = 0;
02946 
02947        for (i=0; i < (int) tmpSlotCount; i++) {
02948            slotID = tmpSlotList[i];
02949            slot = (SFTKSlot *)
02950                      PL_HashTableLookup(tmpSlotHashTable, (void *)slotID);
02951            PORT_Assert(slot);
02952            if (!slot) continue;
02953            SFTK_DestroySlotData(slot);
02954            PL_HashTableRemove(tmpSlotHashTable, (void *)slotID);
02955        }
02956        PORT_Free(tmpSlotList);
02957        PL_HashTableDestroy(tmpSlotHashTable);
02958     }
02959 }
02960 
02961 static void
02962 sftk_closePeer(PRBool isFIPS)
02963 {
02964     CK_SLOT_ID slotID = isFIPS ? PRIVATE_KEY_SLOT_ID: FIPS_SLOT_ID;
02965     SFTKSlot *slot;
02966     int moduleIndex = isFIPS? NSC_NON_FIPS_MODULE : NSC_FIPS_MODULE;
02967     PLHashTable *tmpSlotHashTable = nscSlotHashTable[moduleIndex];
02968 
02969     slot = (SFTKSlot *) PL_HashTableLookup(tmpSlotHashTable, (void *)slotID);
02970     if (slot == NULL) {
02971        return;
02972     }
02973     sftk_DBShutdown(slot);
02974     return;
02975 }
02976 
02977 static PRBool nsc_init = PR_FALSE;
02978 extern SECStatus secoid_Init(void);
02979 
02980 /* NSC_Initialize initializes the Cryptoki library. */
02981 CK_RV nsc_CommonInitialize(CK_VOID_PTR pReserved, PRBool isFIPS)
02982 {
02983     CK_RV crv = CKR_OK;
02984     SECStatus rv;
02985     CK_C_INITIALIZE_ARGS *init_args = (CK_C_INITIALIZE_ARGS *) pReserved;
02986     int i;
02987     int moduleIndex = isFIPS? NSC_FIPS_MODULE : NSC_NON_FIPS_MODULE;
02988 
02989 
02990     if (isFIPS) {
02991        loginWaitTime = PR_SecondsToInterval(1);
02992     }
02993 
02994     rv = secoid_Init();
02995     if (rv != SECSuccess) {
02996        crv = CKR_DEVICE_ERROR;
02997        return crv;
02998     }
02999 
03000     rv = RNG_RNGInit();         /* initialize random number generator */
03001     if (rv != SECSuccess) {
03002        crv = CKR_DEVICE_ERROR;
03003        return crv;
03004     }
03005     RNG_SystemInfoForRNG();
03006 
03007     rv = nsslowcert_InitLocks();
03008     if (rv != SECSuccess) {
03009        crv = CKR_DEVICE_ERROR;
03010        return crv;
03011     }
03012 
03013 
03014     /* NOTE:
03015      * we should be getting out mutexes from this list, not statically binding
03016      * them from NSPR. This should happen before we allow the internal to split
03017      * off from the rest on NSS.
03018      */
03019 
03020     /* initialize the key and cert db's */
03021     nsslowkey_SetDefaultKeyDBAlg
03022                           (SEC_OID_PKCS12_PBE_WITH_SHA1_AND_TRIPLE_DES_CBC);
03023     if (init_args && (!(init_args->flags & CKF_OS_LOCKING_OK))) {
03024         if (init_args->CreateMutex && init_args->DestroyMutex &&
03025             init_args->LockMutex && init_args->UnlockMutex) {
03026             /* softoken always uses NSPR (ie. OS locking), and doesn't know how
03027              * to use the lock functions provided by the application.
03028              */
03029             crv = CKR_CANT_LOCK;
03030             return crv;
03031         }
03032         if (init_args->CreateMutex || init_args->DestroyMutex ||
03033             init_args->LockMutex || init_args->UnlockMutex) {
03034             /* only some of the lock functions were provided by the
03035              * application. This is invalid per PKCS#11 spec.
03036              */
03037             crv = CKR_ARGUMENTS_BAD;
03038             return crv;
03039         }
03040     }
03041     crv = CKR_ARGUMENTS_BAD;
03042     if ((init_args && init_args->LibraryParameters)) {
03043        sftk_parameters paramStrings;
03044        
03045        crv = secmod_parseParameters
03046               ((char *)init_args->LibraryParameters, &paramStrings, isFIPS);
03047        if (crv != CKR_OK) {
03048            return crv;
03049        }
03050        crv = sftk_configure(paramStrings.man, paramStrings.libdes);
03051         if (crv != CKR_OK) {
03052            goto loser;
03053        }
03054 
03055        /* if we have a peer already open, have him close his DB's so we
03056         * don't clobber each other. */
03057        if ((isFIPS && nsc_init) || (!isFIPS && nsf_init)) {
03058            sftk_closePeer(isFIPS);
03059            if (sftk_audit_enabled) {
03060               if (isFIPS && nsc_init) {
03061                   sftk_LogAuditMessage(NSS_AUDIT_INFO, "enabled FIPS mode");
03062               } else {
03063                   sftk_LogAuditMessage(NSS_AUDIT_INFO, "disabled FIPS mode");
03064               }
03065            }
03066        }
03067 
03068        for (i=0; i < paramStrings.token_count; i++) {
03069            crv = SFTK_SlotInit(paramStrings.configdir, 
03070                      &paramStrings.tokens[i],
03071                      moduleIndex);
03072            if (crv != CKR_OK) {
03073                 nscFreeAllSlots(moduleIndex);
03074                 break;
03075             }
03076        }
03077 loser:
03078        secmod_freeParams(&paramStrings);
03079     }
03080     if (CKR_OK == crv) {
03081         sftk_InitFreeLists();
03082     }
03083 
03084     return crv;
03085 }
03086 
03087 CK_RV NSC_Initialize(CK_VOID_PTR pReserved)
03088 {
03089     CK_RV crv;
03090     if (nsc_init) {
03091        return CKR_CRYPTOKI_ALREADY_INITIALIZED;
03092     }
03093     crv = nsc_CommonInitialize(pReserved,PR_FALSE);
03094     nsc_init = (PRBool) (crv == CKR_OK);
03095     return crv;
03096 }
03097 
03098 extern SECStatus SECOID_Shutdown(void);
03099 
03100 /* NSC_Finalize indicates that an application is done with the 
03101  * Cryptoki library.*/
03102 CK_RV nsc_CommonFinalize (CK_VOID_PTR pReserved, PRBool isFIPS)
03103 {
03104     
03105 
03106     nscFreeAllSlots(isFIPS ? NSC_FIPS_MODULE : NSC_NON_FIPS_MODULE);
03107 
03108     /* don't muck with the globals is our peer is still initialized */
03109     if (isFIPS && nsc_init) {
03110        return CKR_OK;
03111     }
03112     if (!isFIPS && nsf_init) {
03113        return CKR_OK;
03114     }
03115 
03116     sftk_CleanupFreeLists();
03117     nsslowcert_DestroyFreeLists();
03118     nsslowcert_DestroyGlobalLocks();
03119 
03120     /* This function does not discard all our previously aquired entropy. */
03121     RNG_RNGShutdown();
03122 
03123     /* tell freeBL to clean up after itself */
03124     BL_Cleanup();
03125     /* unload freeBL shared library from memory */
03126     BL_Unload();
03127     /* clean up the default OID table */
03128     SECOID_Shutdown();
03129     nsc_init = PR_FALSE;
03130 
03131     return CKR_OK;
03132 }
03133 
03134 /* NSC_Finalize indicates that an application is done with the 
03135  * Cryptoki library.*/
03136 CK_RV NSC_Finalize (CK_VOID_PTR pReserved)
03137 {
03138     CK_RV crv;
03139 
03140     if (!nsc_init) {
03141        return CKR_OK;
03142     }
03143 
03144     crv = nsc_CommonFinalize (pReserved, PR_FALSE);
03145 
03146     nsc_init = (PRBool) !(crv == CKR_OK);
03147 
03148     return crv;
03149 }
03150 
03151 extern const char __nss_softokn_rcsid[];
03152 extern const char __nss_softokn_sccsid[];
03153 
03154 /* NSC_GetInfo returns general information about Cryptoki. */
03155 CK_RV  NSC_GetInfo(CK_INFO_PTR pInfo)
03156 {
03157     volatile char c; /* force a reference that won't get optimized away */
03158 
03159     c = __nss_softokn_rcsid[0] + __nss_softokn_sccsid[0]; 
03160     pInfo->cryptokiVersion.major = 2;
03161     pInfo->cryptokiVersion.minor = 20;
03162     PORT_Memcpy(pInfo->manufacturerID,manufacturerID,32);
03163     pInfo->libraryVersion.major = NSS_VMAJOR;
03164     pInfo->libraryVersion.minor = NSS_VMINOR;
03165     PORT_Memcpy(pInfo->libraryDescription,libraryDescription,32);
03166     pInfo->flags = 0;
03167     return CKR_OK;
03168 }
03169 
03170 
03171 /* NSC_GetSlotList obtains a list of slots in the system. */
03172 CK_RV nsc_CommonGetSlotList(CK_BBOOL tokenPresent, 
03173        CK_SLOT_ID_PTR       pSlotList, CK_ULONG_PTR pulCount, int moduleIndex)
03174 {
03175     *pulCount = nscSlotCount[moduleIndex];
03176     if (pSlotList != NULL) {
03177        PORT_Memcpy(pSlotList,nscSlotList[moduleIndex],
03178                             nscSlotCount[moduleIndex]*sizeof(CK_SLOT_ID));
03179     }
03180     return CKR_OK;
03181 }
03182 
03183 /* NSC_GetSlotList obtains a list of slots in the system. */
03184 CK_RV NSC_GetSlotList(CK_BBOOL tokenPresent,
03185                      CK_SLOT_ID_PTR       pSlotList, CK_ULONG_PTR pulCount)
03186 {
03187     return nsc_CommonGetSlotList(tokenPresent, pSlotList, pulCount, 
03188                                                  NSC_NON_FIPS_MODULE);
03189 }
03190        
03191 /* NSC_GetSlotInfo obtains information about a particular slot in the system. */
03192 CK_RV NSC_GetSlotInfo(CK_SLOT_ID slotID, CK_SLOT_INFO_PTR pInfo)
03193 {
03194     SFTKSlot *slot = sftk_SlotFromID(slotID, PR_TRUE);
03195     if (slot == NULL) return CKR_SLOT_ID_INVALID;
03196 
03197     pInfo->firmwareVersion.major = 0;
03198     pInfo->firmwareVersion.minor = 0;
03199 
03200     PORT_Memcpy(pInfo->manufacturerID,manufacturerID,32);
03201     PORT_Memcpy(pInfo->slotDescription,slot->slotDescription,64);
03202     pInfo->flags = (slot->present) ? CKF_TOKEN_PRESENT : 0;
03203     /* all user defined slots are defined as removable */
03204     if (slotID >= SFTK_MIN_USER_SLOT_ID) {
03205        pInfo->flags |= CKF_REMOVABLE_DEVICE;
03206     }
03207     /* ok we really should read it out of the keydb file. */
03208     /* pInfo->hardwareVersion.major = NSSLOWKEY_DB_FILE_VERSION; */
03209     pInfo->hardwareVersion.major = NSS_VMAJOR;
03210     pInfo->hardwareVersion.minor = NSS_VMINOR;
03211     return CKR_OK;
03212 }
03213 
03214 /*
03215  * check the current state of the 'needLogin' flag in case the database has
03216  * been changed underneath us.
03217  */
03218 static PRBool
03219 sftk_checkNeedLogin(SFTKSlot *slot, NSSLOWKEYDBHandle *keyHandle)
03220 {
03221     if (slot->password) {
03222        SECStatus rv;
03223        rv = nsslowkey_CheckKeyDBPassword(keyHandle,slot->password);
03224        if ( rv == SECSuccess) {
03225            return slot->needLogin;
03226        } else {
03227            SECITEM_FreeItem(slot->password, PR_TRUE);
03228            slot->password = NULL;
03229            slot->isLoggedIn = PR_FALSE;
03230        }
03231     }
03232     slot->needLogin = 
03233               (PRBool)!sftk_hasNullPassword(keyHandle,&slot->password);
03234     return (slot->needLogin);
03235 }
03236 
03237 /* NSC_GetTokenInfo obtains information about a particular token in 
03238  * the system. */
03239 CK_RV NSC_GetTokenInfo(CK_SLOT_ID slotID,CK_TOKEN_INFO_PTR pInfo)
03240 {
03241     SFTKSlot *slot; 
03242     NSSLOWKEYDBHandle *handle;
03243 
03244     if (!nsc_init && !nsf_init) return CKR_CRYPTOKI_NOT_INITIALIZED;
03245     slot = sftk_SlotFromID(slotID, PR_FALSE);
03246     if (slot == NULL) return CKR_SLOT_ID_INVALID;
03247 
03248     PORT_Memcpy(pInfo->manufacturerID,manufacturerID,32);
03249     PORT_Memcpy(pInfo->model,"NSS 3           ",16);
03250     PORT_Memcpy(pInfo->serialNumber,"0000000000000000",16);
03251     PORT_Memcpy(pInfo->utcTime,"0000000000000000",16);
03252     pInfo->ulMaxSessionCount = 0; /* arbitrarily large */
03253     pInfo->ulSessionCount = slot->sessionCount;
03254     pInfo->ulMaxRwSessionCount = 0; /* arbitarily large */
03255     pInfo->ulRwSessionCount = slot->rwSessionCount;
03256     pInfo->firmwareVersion.major = 0;
03257     pInfo->firmwareVersion.minor = 0;
03258     PORT_Memcpy(pInfo->label,slot->tokDescription,32);
03259     handle = sftk_getKeyDB(slot);
03260     pInfo->flags = CKF_RNG | CKF_DUAL_CRYPTO_OPERATIONS;
03261     if (handle == NULL) {
03262        pInfo->flags |= CKF_WRITE_PROTECTED;
03263        pInfo->ulMaxPinLen = 0;
03264        pInfo->ulMinPinLen = 0;
03265        pInfo->ulTotalPublicMemory = 0;
03266        pInfo->ulFreePublicMemory = 0;
03267        pInfo->ulTotalPrivateMemory = 0;
03268        pInfo->ulFreePrivateMemory = 0;
03269        pInfo->hardwareVersion.major = 4;
03270        pInfo->hardwareVersion.minor = 0;
03271     } else {
03272        /*
03273         * we have three possible states which we may be in:
03274         *   (1) No DB password has been initialized. This also means we
03275         *   have no keys in the key db.
03276         *   (2) Password initialized to NULL. This means we have keys, but
03277         *   the user has chosen not use a password.
03278         *   (3) Finally we have an initialized password whicn is not NULL, and
03279         *   we will need to prompt for it.
03280         */
03281        if (nsslowkey_HasKeyDBPassword(handle) == SECFailure) {
03282            pInfo->flags |= CKF_LOGIN_REQUIRED;
03283        } else if (!sftk_checkNeedLogin(slot,handle)) {
03284            pInfo->flags |= CKF_USER_PIN_INITIALIZED;
03285        } else {
03286            pInfo->flags |= CKF_LOGIN_REQUIRED | CKF_USER_PIN_INITIALIZED;
03287        }
03288        pInfo->ulMaxPinLen = SFTK_MAX_PIN;
03289        pInfo->ulMinPinLen = (CK_ULONG)slot->minimumPinLen;
03290        pInfo->ulTotalPublicMemory = 1;
03291        pInfo->ulFreePublicMemory = 1;
03292        pInfo->ulTotalPrivateMemory = 1;
03293        pInfo->ulFreePrivateMemory = 1;
03294        pInfo->hardwareVersion.major = CERT_DB_FILE_VERSION;
03295        pInfo->hardwareVersion.minor = handle->version;
03296         sftk_freeKeyDB(handle);
03297     }
03298     /*
03299      * CKF_LOGIN_REQUIRED CKF_USER_PIN_INITIALIZED  how CKF_TOKEN_INITIALIZED
03300      *                                              should be set
03301      *         0                   0                           1
03302      *         1                   0                           0
03303      *         0                   1                           1
03304      *         1                   1                           1
03305      */
03306     if (!(pInfo->flags & CKF_LOGIN_REQUIRED) ||
03307        (pInfo->flags & CKF_USER_PIN_INITIALIZED)) {
03308        pInfo->flags |= CKF_TOKEN_INITIALIZED;
03309     }
03310     return CKR_OK;
03311 }
03312 
03313 /* NSC_GetMechanismList obtains a list of mechanism types 
03314  * supported by a token. */
03315 CK_RV NSC_GetMechanismList(CK_SLOT_ID slotID,
03316        CK_MECHANISM_TYPE_PTR pMechanismList, CK_ULONG_PTR pulCount)
03317 {
03318     CK_ULONG i;
03319 
03320     switch (slotID) {
03321     /* default: */
03322     case NETSCAPE_SLOT_ID:
03323        *pulCount = mechanismCount;
03324        if (pMechanismList != NULL) {
03325            for (i=0; i < mechanismCount; i++) {
03326               pMechanismList[i] = mechanisms[i].type;
03327            }
03328        }
03329        break;
03330      default:
03331        *pulCount = 0;
03332        for (i=0; i < mechanismCount; i++) {
03333            if (mechanisms[i].privkey) {
03334               (*pulCount)++;
03335               if (pMechanismList != NULL) {
03336                   *pMechanismList++ = mechanisms[i].type;
03337               }
03338            }
03339        }
03340        break;
03341     }
03342     return CKR_OK;
03343 }
03344 
03345 
03346 /* NSC_GetMechanismInfo obtains information about a particular mechanism 
03347  * possibly supported by a token. */
03348 CK_RV NSC_GetMechanismInfo(CK_SLOT_ID slotID, CK_MECHANISM_TYPE type,
03349                                    CK_MECHANISM_INFO_PTR pInfo)
03350 {
03351     PRBool isPrivateKey;
03352     CK_ULONG i;
03353 
03354     switch (slotID) {
03355     case NETSCAPE_SLOT_ID:
03356        isPrivateKey = PR_FALSE;
03357        break;
03358     default:
03359        isPrivateKey = PR_TRUE;
03360        break;
03361     }
03362     for (i=0; i < mechanismCount; i++) {
03363         if (type == mechanisms[i].type) {
03364            if (isPrivateKey && !mechanisms[i].privkey) {
03365               return CKR_MECHANISM_INVALID;
03366            }
03367            PORT_Memcpy(pInfo,&mechanisms[i].info, sizeof(CK_MECHANISM_INFO));
03368            return CKR_OK;
03369        }
03370     }
03371     return CKR_MECHANISM_INVALID;
03372 }
03373 
03374 CK_RV sftk_MechAllowsOperation(CK_MECHANISM_TYPE type, CK_ATTRIBUTE_TYPE op)
03375 {
03376     CK_ULONG i;
03377     CK_FLAGS flags;
03378 
03379     switch (op) {
03380     case CKA_ENCRYPT:         flags = CKF_ENCRYPT;         break;
03381     case CKA_DECRYPT:         flags = CKF_DECRYPT;         break;
03382     case CKA_WRAP:            flags = CKF_WRAP;            break;
03383     case CKA_UNWRAP:          flags = CKF_UNWRAP;          break;
03384     case CKA_SIGN:            flags = CKF_SIGN;            break;
03385     case CKA_SIGN_RECOVER:    flags = CKF_SIGN_RECOVER;    break;
03386     case CKA_VERIFY:          flags = CKF_VERIFY;          break;
03387     case CKA_VERIFY_RECOVER:  flags = CKF_VERIFY_RECOVER;  break;
03388     case CKA_DERIVE:          flags = CKF_DERIVE;          break;
03389     default:
03390        return CKR_ARGUMENTS_BAD;
03391     }
03392     for (i=0; i < mechanismCount; i++) {
03393         if (type == mechanisms[i].type) {
03394            return (flags & mechanisms[i].info.flags) ? CKR_OK 
03395                                                      : CKR_MECHANISM_INVALID;
03396        }
03397     }
03398     return CKR_MECHANISM_INVALID;
03399 }
03400 
03401 
03402 static SECStatus
03403 sftk_TurnOffUser(NSSLOWCERTCertificate *cert, SECItem *k, void *arg)
03404 {
03405    NSSLOWCERTCertTrust trust;
03406    SECStatus rv;
03407 
03408    rv = nsslowcert_GetCertTrust(cert,&trust);
03409    if (rv == SECSuccess && ((trust.emailFlags & CERTDB_USER) ||
03410                          (trust.sslFlags & CERTDB_USER) ||
03411                          (trust.objectSigningFlags & CERTDB_USER))) {
03412        trust.emailFlags &= ~CERTDB_USER;
03413        trust.sslFlags &= ~CERTDB_USER;
03414        trust.objectSigningFlags &= ~CERTDB_USER;
03415        nsslowcert_ChangeCertTrust(cert->dbhandle,cert,&trust);
03416    }
03417    return SECSuccess;
03418 }
03419 
03420 /* NSC_InitToken initializes a token. */
03421 CK_RV NSC_InitToken(CK_SLOT_ID slotID,CK_CHAR_PTR pPin,
03422                             CK_ULONG ulPinLen,CK_CHAR_PTR pLabel) {
03423     SFTKSlot *slot = sftk_SlotFromID(slotID, PR_FALSE);
03424     NSSLOWKEYDBHandle *handle;
03425     NSSLOWCERTCertDBHandle *certHandle;
03426     SECStatus rv;
03427     unsigned int i;
03428     SFTKObject *object;
03429 
03430     if (slot == NULL) return CKR_SLOT_ID_INVALID;
03431 
03432     /* don't initialize the database if we aren't talking to a token
03433      * that uses the key database.
03434      */
03435     if (slotID == NETSCAPE_SLOT_ID) {
03436        return CKR_TOKEN_WRITE_PROTECTED;
03437     }
03438 
03439     /* first, delete all our loaded key and cert objects from our 
03440      * internal list. */
03441     PZ_Lock(slot->objectLock);
03442     for (i=0; i < slot->tokObjHashSize; i++) {
03443        do {
03444            object = slot->tokObjects[i];
03445            /* hand deque */
03446            /* this duplicates function of NSC_close session functions, but 
03447             * because we know that we are freeing all the sessions, we can
03448             * do more efficient processing */
03449            if (object) {
03450               slot->tokObjects[i] = object->next;
03451 
03452               if (object->next) object->next->prev = NULL;
03453               object->next = object->prev = NULL;
03454            }
03455            if (object) sftk_FreeObject(object);
03456        } while (object != NULL);
03457     }
03458     slot->DB_loaded = PR_FALSE;
03459     PZ_Unlock(slot->objectLock);
03460 
03461     /* then clear out the key database */
03462     handle = sftk_getKeyDB(slot);
03463     if (handle == NULL) {
03464        return CKR_TOKEN_WRITE_PROTECTED;
03465     }
03466 
03467     rv = nsslowkey_ResetKeyDB(handle);
03468     sftk_freeKeyDB(handle);
03469     if (rv != SECSuccess) {
03470        return CKR_DEVICE_ERROR;
03471     }
03472 
03473     /* finally  mark all the user certs as non-user certs */
03474     certHandle = sftk_getCertDB(slot);
03475     if (certHandle == NULL) return CKR_OK;
03476 
03477     nsslowcert_TraversePermCerts(certHandle,sftk_TurnOffUser, NULL);
03478     sftk_freeCertDB(certHandle);
03479 
03480     return CKR_OK; /*is this the right function for not implemented*/
03481 }
03482 
03483 
03484 /* NSC_InitPIN initializes the normal user's PIN. */
03485 CK_RV NSC_InitPIN(CK_SESSION_HANDLE hSession,
03486                                    CK_CHAR_PTR pPin, CK_ULONG ulPinLen)
03487 {
03488     SFTKSession *sp = NULL;
03489     SFTKSlot *slot;
03490     NSSLOWKEYDBHandle *handle = NULL;
03491     SECItem *newPin;
03492     char newPinStr[SFTK_MAX_PIN+1];
03493     SECStatus rv;
03494     CK_RV crv = CKR_SESSION_HANDLE_INVALID;
03495 
03496     
03497     sp = sftk_SessionFromHandle(hSession);
03498     if (sp == NULL) {
03499        goto loser;
03500     }
03501 
03502     slot = sftk_SlotFromSession(sp);
03503     if (slot == NULL) {
03504        goto loser;
03505     }
03506 
03507     handle = sftk_getKeyDB(slot);
03508     if (handle == NULL) {
03509        crv = CKR_PIN_LEN_RANGE;
03510        goto loser;
03511     }
03512 
03513 
03514     if (sp->info.state != CKS_RW_SO_FUNCTIONS) {
03515        crv = CKR_USER_NOT_LOGGED_IN;
03516        goto loser;
03517     }
03518 
03519     sftk_FreeSession(sp);
03520     sp = NULL;
03521 
03522     /* make sure the pins aren't too long */
03523     if (ulPinLen > SFTK_MAX_PIN) {
03524        crv = CKR_PIN_LEN_RANGE;
03525        goto loser;
03526     }
03527     if (ulPinLen < (CK_ULONG)slot->minimumPinLen) {
03528        crv = CKR_PIN_LEN_RANGE;
03529        goto loser;
03530     }
03531 
03532     if (nsslowkey_HasKeyDBPassword(handle) != SECFailure) {
03533        crv = CKR_DEVICE_ERROR;
03534        goto loser;
03535     }
03536 
03537     /* convert to null terminated string */
03538     PORT_Memcpy(newPinStr,pPin,ulPinLen);
03539     newPinStr[ulPinLen] = 0; 
03540 
03541     /* build the hashed pins which we pass around */
03542     newPin = nsslowkey_HashPassword(newPinStr,handle->global_salt);
03543     PORT_Memset(newPinStr,0,sizeof(newPinStr));
03544 
03545     /* change the data base */
03546     rv = nsslowkey_SetKeyDBPassword(handle,newPin);
03547     sftk_freeKeyDB(handle);
03548     handle = NULL;
03549 
03550     /* Now update our local copy of the pin */
03551     if (rv == SECSuccess) {
03552        if (slot->password) {
03553            SECITEM_ZfreeItem(slot->password, PR_TRUE);
03554        }
03555        slot->password = newPin;
03556        if (ulPinLen == 0) slot->needLogin = PR_FALSE;
03557        return CKR_OK;
03558     }
03559     SECITEM_ZfreeItem(newPin, PR_TRUE);
03560     crv = CKR_PIN_INCORRECT;
03561 
03562 loser:
03563     if (sp) {
03564        sftk_FreeSession(sp);
03565     }
03566     if (handle) {
03567        sftk_freeKeyDB(handle);
03568     }
03569     return crv;
03570 }
03571 
03572 
03573 /* NSC_SetPIN modifies the PIN of user that is currently logged in. */
03574 /* NOTE: This is only valid for the PRIVATE_KEY_SLOT */
03575 CK_RV NSC_SetPIN(CK_SESSION_HANDLE hSession, CK_CHAR_PTR pOldPin,
03576     CK_ULONG ulOldLen, CK_CHAR_PTR pNewPin, CK_ULONG ulNewLen)
03577 {
03578     SFTKSession *sp = NULL;
03579     SFTKSlot *slot;
03580     NSSLOWKEYDBHandle *handle = NULL;
03581     SECItem *newPin;
03582     SECItem *oldPin;
03583     char newPinStr[SFTK_MAX_PIN+1],oldPinStr[SFTK_MAX_PIN+1];
03584     SECStatus rv;
03585     CK_RV crv = CKR_SESSION_HANDLE_INVALID;
03586 
03587     
03588     sp = sftk_SessionFromHandle(hSession);
03589     if (sp == NULL) {
03590        goto loser;
03591     }
03592 
03593     slot = sftk_SlotFromSession(sp);
03594     if (!slot) {
03595        goto loser;
03596     }
03597 
03598     handle = sftk_getKeyDB(slot);
03599     if (handle == NULL) {
03600        sftk_FreeSession(sp);
03601        return CKR_PIN_LEN_RANGE; /* XXX FIXME wrong return value */
03602     }
03603 
03604     if (slot->needLogin && sp->info.state != CKS_RW_USER_FUNCTIONS) {
03605        crv = CKR_USER_NOT_LOGGED_IN;
03606        goto loser;
03607     }
03608 
03609     sftk_FreeSession(sp);
03610     sp = NULL;
03611 
03612     /* make sure the pins aren't too long */
03613     if ((ulNewLen > SFTK_MAX_PIN) || (ulOldLen > SFTK_MAX_PIN)) {
03614        crv = CKR_PIN_LEN_RANGE;
03615        goto loser;
03616     }
03617     if (ulNewLen < (CK_ULONG)slot->minimumPinLen) {
03618        crv = CKR_PIN_LEN_RANGE;
03619        goto loser;
03620     }
03621 
03622 
03623     /* convert to null terminated string */
03624     PORT_Memcpy(newPinStr,pNewPin,ulNewLen);
03625     newPinStr[ulNewLen] = 0; 
03626     PORT_Memcpy(oldPinStr,pOldPin,ulOldLen);
03627     oldPinStr[ulOldLen] = 0; 
03628 
03629     /* build the hashed pins which we pass around */
03630     newPin = nsslowkey_HashPassword(newPinStr,handle->global_salt);
03631     oldPin = nsslowkey_HashPassword(oldPinStr,handle->global_salt);
03632     PORT_Memset(newPinStr,0,sizeof(newPinStr));
03633     PORT_Memset(oldPinStr,0,sizeof(oldPinStr));
03634 
03635     /* change the data base password */
03636     PR_Lock(slot->pwCheckLock);
03637     rv = nsslowkey_ChangeKeyDBPassword(handle,oldPin,newPin);
03638     sftk_freeKeyDB(handle);
03639     handle = NULL;
03640     if ((rv != SECSuccess) && (slot->slotID == FIPS_SLOT_ID)) {
03641        PR_Sleep(loginWaitTime);
03642     }
03643     PR_Unlock(slot->pwCheckLock);
03644 
03645     /* Now update our local copy of the pin */
03646     SECITEM_ZfreeItem(oldPin, PR_TRUE);
03647     if (rv == SECSuccess) {
03648        if (slot->password) {
03649            SECITEM_ZfreeItem(slot->password, PR_TRUE);
03650        }
03651        slot->password = newPin;
03652        slot->needLogin = (PRBool)(ulNewLen != 0);
03653        return CKR_OK;
03654     }
03655     SECITEM_ZfreeItem(newPin, PR_TRUE);
03656     crv = CKR_PIN_INCORRECT;
03657 loser:
03658     if (sp) {
03659        sftk_FreeSession(sp);
03660     }
03661     if (handle) {
03662        sftk_freeKeyDB(handle);
03663     }
03664     return crv;
03665 }
03666 
03667 /* NSC_OpenSession opens a session between an application and a token. */
03668 CK_RV NSC_OpenSession(CK_SLOT_ID slotID, CK_FLAGS flags,
03669    CK_VOID_PTR pApplication,CK_NOTIFY Notify,CK_SESSION_HANDLE_PTR phSession)
03670 {
03671     SFTKSlot *slot;
03672     CK_SESSION_HANDLE sessionID;
03673     SFTKSession *session;
03674     SFTKSession *sameID;
03675 
03676     slot = sftk_SlotFromID(slotID, PR_FALSE);
03677     if (slot == NULL) return CKR_SLOT_ID_INVALID;
03678 
03679     /* new session (we only have serial sessions) */
03680     session = sftk_NewSession(slotID, Notify, pApplication,
03681                                            flags | CKF_SERIAL_SESSION);
03682     if (session == NULL) return CKR_HOST_MEMORY;
03683 
03684     if (slot->readOnly && (flags & CKF_RW_SESSION)) {
03685        /* NETSCAPE_SLOT_ID is Read ONLY */
03686        session->info.flags &= ~CKF_RW_SESSION;
03687     }
03688     PZ_Lock(slot->slotLock);
03689     ++slot->sessionCount;
03690     PZ_Unlock(slot->slotLock);
03691     if (session->info.flags & CKF_RW_SESSION) {
03692        PR_AtomicIncrement(&slot->rwSessionCount);
03693     }
03694 
03695     do {
03696         PZLock *lock;
03697         do {
03698             sessionID = (PR_AtomicIncrement(&slot->sessionIDCount) & 0xffffff)
03699                         | (slot->index << 24);
03700         } while (sessionID == CK_INVALID_HANDLE);
03701         lock = SFTK_SESSION_LOCK(slot,sessionID);
03702         PZ_Lock(lock);
03703         sftkqueue_find(sameID, sessionID, slot->head, slot->sessHashSize);
03704         if (sameID == NULL) {
03705             session->handle = sessionID;
03706             sftk_update_state(slot, session);
03707             sftkqueue_add(session, sessionID, slot->head,slot->sessHashSize);
03708         } else {
03709             slot->sessionIDConflict++;  /* for debugging */
03710         }
03711         PZ_Unlock(lock);
03712     } while (sameID != NULL);
03713 
03714     *phSession = sessionID;
03715     return CKR_OK;
03716 }
03717 
03718 
03719 /* NSC_CloseSession closes a session between an application and a token. */
03720 CK_RV NSC_CloseSession(CK_SESSION_HANDLE hSession)
03721 {
03722     SFTKSlot *slot;
03723     SFTKSession *session;
03724     SECItem *pw = NULL;
03725     PRBool sessionFound;
03726     PZLock *lock;
03727 
03728     session = sftk_SessionFromHandle(hSession);
03729     if (session == NULL) return CKR_SESSION_HANDLE_INVALID;
03730     slot = sftk_SlotFromSession(session);
03731     sessionFound = PR_FALSE;
03732 
03733     /* lock */
03734     lock = SFTK_SESSION_LOCK(slot,hSession);
03735     PZ_Lock(lock);
03736     if (sftkqueue_is_queued(session,hSession,slot->head,slot->sessHashSize)) {
03737        sessionFound = PR_TRUE;
03738        sftkqueue_delete(session,hSession,slot->head,slot->sessHashSize);
03739        session->refCount--; /* can't go to zero while we hold the reference */
03740        PORT_Assert(session->refCount > 0);
03741     }
03742     PZ_Unlock(lock);
03743 
03744     if (sessionFound) {
03745        PZ_Lock(slot->slotLock);
03746        if (--slot->sessionCount == 0) {
03747            pw = slot->password;
03748            slot->isLoggedIn = PR_FALSE;
03749            slot->password = NULL;
03750        }
03751        PZ_Unlock(slot->slotLock);
03752        if (session->info.flags & CKF_RW_SESSION) {
03753            PR_AtomicDecrement(&slot->rwSessionCount);
03754        }
03755     }
03756 
03757     sftk_FreeSession(session);
03758     if (pw) SECITEM_ZfreeItem(pw, PR_TRUE);
03759     return CKR_OK;
03760 }
03761 
03762 
03763 /* NSC_CloseAllSessions closes all sessions with a token. */
03764 CK_RV NSC_CloseAllSessions (CK_SLOT_ID slotID)
03765 {
03766     SFTKSlot *slot;
03767 
03768     slot = sftk_SlotFromID(slotID, PR_FALSE);
03769     if (slot == NULL) return CKR_SLOT_ID_INVALID;
03770 
03771     return sft_CloseAllSession(slot);
03772 }
03773 
03774 
03775 
03776 /* NSC_GetSessionInfo obtains information about the session. */
03777 CK_RV NSC_GetSessionInfo(CK_SESSION_HANDLE hSession,
03778                                           CK_SESSION_INFO_PTR pInfo)
03779 {
03780     SFTKSession *session;
03781 
03782     session = sftk_SessionFromHandle(hSession);
03783     if (session == NULL) return CKR_SESSION_HANDLE_INVALID;
03784 
03785     PORT_Memcpy(pInfo,&session->info,sizeof(CK_SESSION_INFO));
03786     sftk_FreeSession(session);
03787     return CKR_OK;
03788 }
03789 
03790 /* NSC_Login logs a user into a token. */
03791 CK_RV NSC_Login(CK_SESSION_HANDLE hSession, CK_USER_TYPE userType,
03792                                 CK_CHAR_PTR pPin, CK_ULONG ulPinLen)
03793 {
03794     SFTKSlot *slot;
03795     SFTKSession *session;
03796     NSSLOWKEYDBHandle *handle;
03797     CK_FLAGS sessionFlags;
03798     SECStatus rv;
03799     CK_RV crv;
03800     SECItem *pin;
03801     char pinStr[SFTK_MAX_PIN+1];
03802 
03803 
03804     /* get the slot */
03805     slot = sftk_SlotFromSessionHandle(hSession);
03806 
03807     /* make sure the session is valid */
03808     session = sftk_SessionFromHandle(hSession);
03809     if (session == NULL) {
03810        return CKR_SESSION_HANDLE_INVALID;
03811     }
03812     sessionFlags = session->info.flags;
03813     sftk_FreeSession(session);
03814     session = NULL;
03815 
03816     /* can't log into the Netscape Slot */
03817     if (slot->slotID == NETSCAPE_SLOT_ID) {
03818         return CKR_USER_TYPE_INVALID;
03819     }
03820 
03821     if (slot->isLoggedIn) return CKR_USER_ALREADY_LOGGED_IN;
03822     slot->ssoLoggedIn = PR_FALSE;
03823 
03824     if (ulPinLen > SFTK_MAX_PIN) return CKR_PIN_LEN_RANGE;
03825 
03826     /* convert to null terminated string */
03827     PORT_Memcpy(pinStr,pPin,ulPinLen);
03828     pinStr[ulPinLen] = 0; 
03829 
03830     handle = sftk_getKeyDB(slot);
03831     if (handle == NULL) {
03832         return CKR_USER_TYPE_INVALID;
03833     }
03834 
03835     /*
03836      * Deal with bootstrap. We allow the SSO to login in with a NULL
03837      * password if and only if we haven't initialized the KEY DB yet.
03838      * We only allow this on a RW session.
03839      */
03840     rv = nsslowkey_HasKeyDBPassword(handle);
03841     if (rv == SECFailure) {
03842        /* allow SSO's to log in only if there is not password on the
03843         * key database */
03844        if (((userType == CKU_SO) && (sessionFlags & CKF_RW_SESSION))
03845            /* fips always needs to authenticate, even if there isn't a db */
03846                                    || (slot->slotID == FIPS_SLOT_ID)) {
03847            /* should this be a fixed password? */
03848            if (ulPinLen == 0) {
03849               SECItem *pw;
03850               PZ_Lock(slot->slotLock);
03851               pw = slot->password;
03852               slot->password = NULL;
03853               slot->isLoggedIn = PR_TRUE;
03854               slot->ssoLoggedIn = (PRBool)(userType == CKU_SO);
03855               PZ_Unlock(slot->slotLock);
03856               sftk_update_all_states(slot);
03857               SECITEM_ZfreeItem(pw,PR_TRUE);
03858               crv = CKR_OK;
03859               goto done;
03860            }
03861            crv = CKR_PIN_INCORRECT;
03862            goto done;
03863        } 
03864        crv = CKR_USER_TYPE_INVALID;
03865        goto done;
03866     } 
03867 
03868     /* don't allow the SSO to log in if the user is already initialized */
03869     if (userType != CKU_USER) { 
03870        crv = CKR_USER_TYPE_INVALID; 
03871        goto done;
03872     }
03873 
03874 
03875     /* build the hashed pins which we pass around */
03876     pin = nsslowkey_HashPassword(pinStr,handle->global_salt);
03877     if (pin == NULL) {
03878        crv = CKR_HOST_MEMORY;
03879        goto done;
03880     }
03881 
03882     PR_Lock(slot->pwCheckLock);
03883     rv = nsslowkey_CheckKeyDBPassword(handle,pin);
03884     sftk_freeKeyDB(handle);
03885     handle = NULL;
03886     if ((rv != SECSuccess) && (slot->slotID == FIPS_SLOT_ID)) {
03887        PR_Sleep(loginWaitTime);
03888     }
03889     PR_Unlock(slot->pwCheckLock);
03890     if (rv == SECSuccess) {
03891        SECItem *tmp;
03892        PZ_Lock(slot->slotLock);
03893        tmp = slot->password;
03894        slot->isLoggedIn = PR_TRUE;
03895        slot->password = pin;
03896        PZ_Unlock(slot->slotLock);
03897         if (tmp) SECITEM_ZfreeItem(tmp, PR_TRUE);
03898 
03899        /* update all sessions */
03900        sftk_update_all_states(slot);
03901        return CKR_OK;
03902     }
03903 
03904     SECITEM_ZfreeItem(pin, PR_TRUE);
03905     crv = CKR_PIN_INCORRECT;
03906 done:
03907     if (handle) {
03908        sftk_freeKeyDB(handle);
03909     }
03910     return crv;
03911 }
03912 
03913 /* NSC_Logout logs a user out from a token. */
03914 CK_RV NSC_Logout(CK_SESSION_HANDLE hSession)
03915 {
03916     SFTKSlot *slot = sftk_SlotFromSessionHandle(hSession);
03917     SFTKSession *session;
03918     SECItem *pw = NULL;
03919 
03920     session = sftk_SessionFromHandle(hSession);
03921     if (session == NULL) return CKR_SESSION_HANDLE_INVALID;
03922     sftk_FreeSession(session);
03923     session = NULL;
03924 
03925     if (!slot->isLoggedIn) return CKR_USER_NOT_LOGGED_IN;
03926 
03927     PZ_Lock(slot->slotLock);
03928     pw = slot->password;
03929     slot->isLoggedIn = PR_FALSE;
03930     slot->ssoLoggedIn = PR_FALSE;
03931     slot->password = NULL;
03932     PZ_Unlock(slot->slotLock);
03933     if (pw) SECITEM_ZfreeItem(pw, PR_TRUE);
03934 
03935     sftk_update_all_states(slot);
03936     return CKR_OK;
03937 }
03938 
03939 /*
03940  * Create a new slot on the fly. The slot that is passed in is the
03941  * slot the request came from. Only the crypto or FIPS slots can
03942  * be used. The resulting slot will live in the same module as
03943  * the slot the request was passed to. object is the creation object
03944  * that specifies the module spec for the new slot.
03945  */
03946 static CK_RV sftk_CreateNewSlot(SFTKSlot *slot, CK_OBJECT_CLASS class,
03947                                 SFTKObject *object)
03948 {
03949     CK_SLOT_ID idMin, idMax;
03950     PRBool isFIPS = PR_FALSE;
03951     unsigned long moduleIndex;
03952     SFTKAttribute *attribute;
03953     sftk_parameters paramStrings;
03954     char *paramString;
03955     CK_SLOT_ID slotID = 0;
03956     SFTKSlot *newSlot = NULL;
03957     CK_RV crv = CKR_OK;
03958 
03959     /* only the crypto or FIPS slots can create new slot objects */
03960     if (slot->slotID == NETSCAPE_SLOT_ID) {
03961        idMin = SFTK_MIN_USER_SLOT_ID;
03962        idMax = SFTK_MAX_USER_SLOT_ID;
03963        moduleIndex = NSC_NON_FIPS_MODULE;
03964        isFIPS = PR_FALSE;
03965     } else if (slot->slotID == FIPS_SLOT_ID) {
03966        idMin = SFTK_MIN_FIPS_USER_SLOT_ID;
03967        idMax = SFTK_MAX_FIPS_USER_SLOT_ID;
03968        moduleIndex = NSC_FIPS_MODULE;
03969        isFIPS = PR_TRUE;
03970     } else {
03971        return CKR_ATTRIBUTE_VALUE_INVALID;
03972     }
03973     attribute = sftk_FindAttribute(object,CKA_NETSCAPE_MODULE_SPEC);
03974     if (attribute == NULL) {
03975        return CKR_TEMPLATE_INCOMPLETE;
03976     }
03977     paramString = (char *)attribute->attrib.pValue;
03978     crv = secmod_parseParameters(paramString, &paramStrings, isFIPS);
03979     if (crv != CKR_OK) {
03980        goto loser;
03981     }
03982 
03983     /* enforce only one at a time */
03984     if (paramStrings.token_count != 1) {
03985        crv = CKR_ATTRIBUTE_VALUE_INVALID;
03986        goto loser;
03987     }
03988 
03989     slotID = paramStrings.tokens[0].slotID;
03990 
03991     /* stay within the valid ID space */
03992     if ((slotID < idMin) || (slotID > idMax)) {
03993        crv = CKR_ATTRIBUTE_VALUE_INVALID;
03994        goto loser;
03995     }
03996 
03997     /* unload any existing slot at this id */
03998     newSlot = sftk_SlotFromID(slotID, PR_TRUE);
03999     if (newSlot && newSlot->present) {
04000        crv = SFTK_ShutdownSlot(newSlot);
04001        if (crv != CKR_OK) {
04002            goto loser;
04003        }
04004     }
04005 
04006     /* if we were just planning on deleting the slot, then do so now */
04007     if (class == CKO_NETSCAPE_DELSLOT) {
04008        /* sort of a unconventional use of this error code, be we are
04009          * overusing CKR_ATTRIBUTE_VALUE_INVALID, and it does apply */
04010        crv = newSlot ? CKR_OK : CKR_SLOT_ID_INVALID;
04011        goto loser; /* really exit */
04012     }
04013 
04014     if (newSlot) {
04015        crv = SFTK_SlotReInit(newSlot, paramStrings.configdir, 
04016                      &paramStrings.tokens[0], moduleIndex);
04017     } else {
04018        crv = SFTK_SlotInit(paramStrings.configdir, 
04019                      &paramStrings.tokens[0], moduleIndex);
04020     }
04021     if (crv != CKR_OK) {
04022        goto loser;
04023     }
04024 loser:
04025     secmod_freeParams(&paramStrings);
04026     sftk_FreeAttribute(attribute);
04027 
04028     return crv;
04029 }
04030 
04031 
04032 /* NSC_CreateObject creates a new object. */
04033 CK_RV NSC_CreateObject(CK_SESSION_HANDLE hSession,
04034               CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount, 
04035                                    CK_OBJECT_HANDLE_PTR phObject)
04036 {
04037     SFTKSlot *slot = sftk_SlotFromSessionHandle(hSession);
04038     SFTKSession *session;
04039     SFTKObject *object;
04040     /* make sure class isn't randomly CKO_NETSCAPE_NEWSLOT or
04041      * CKO_NETSCPE_DELSLOT. */
04042     CK_OBJECT_CLASS class = CKO_VENDOR_DEFINED;
04043     CK_RV crv;
04044     int i;
04045 
04046     *phObject = CK_INVALID_HANDLE;
04047 
04048     /*
04049      * now lets create an object to hang the attributes off of
04050      */
04051     object = sftk_NewObject(slot); /* fill in the handle later */
04052     if (object == NULL) {
04053        return CKR_HOST_MEMORY;
04054     }
04055 
04056     /*
04057      * load the template values into the object
04058      */
04059     for (i=0; i < (int) ulCount; i++) {
04060        crv = sftk_AddAttributeType(object,sftk_attr_expand(&pTemplate[i]));
04061        if (crv != CKR_OK) {
04062            sftk_FreeObject(object);
04063            return crv;
04064        }
04065        if ((pTemplate[i].type == CKA_CLASS) && pTemplate[i].pValue) {
04066            class = *(CK_OBJECT_CLASS *)pTemplate[i].pValue;
04067        }
04068     }
04069 
04070     /* get the session */
04071     session = sftk_SessionFromHandle(hSession);
04072     if (session == NULL) {
04073        sftk_FreeObject(object);
04074         return CKR_SESSION_HANDLE_INVALID;
04075     }
04076 
04077     /*
04078      * handle pseudo objects (CKO_NEWSLOT)
04079      */
04080     if ((class == CKO_NETSCAPE_NEWSLOT)  || (class == CKO_NETSCAPE_DELSLOT)) {
04081        crv = sftk_CreateNewSlot(slot, class, object);
04082        goto done;
04083     } 
04084 
04085     /*
04086      * handle the base object stuff
04087      */
04088     crv = sftk_handleObject(object,session);
04089     *phObject = object->handle;
04090 done:
04091     sftk_FreeSession(session);
04092     sftk_FreeObject(object);
04093 
04094     return crv;
04095 }
04096 
04097 
04098 
04099 /* NSC_CopyObject copies an object, creating a new object for the copy. */
04100 CK_RV NSC_CopyObject(CK_SESSION_HANDLE hSession,
04101        CK_OBJECT_HANDLE hObject, CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount,
04102                                    CK_OBJECT_HANDLE_PTR phNewObject) 
04103 {
04104     SFTKObject *destObject,*srcObject;
04105     SFTKSession *session;
04106     CK_RV crv = CKR_OK;
04107     SFTKSlot *slot = sftk_SlotFromSessionHandle(hSession);
04108     int i;
04109 
04110     /* Get srcObject so we can find the class */
04111     session = sftk_SessionFromHandle(hSession);
04112     if (session == NULL) {
04113         return CKR_SESSION_HANDLE_INVALID;
04114     }
04115     srcObject = sftk_ObjectFromHandle(hObject,session);
04116     if (srcObject == NULL) {
04117        sftk_FreeSession(session);
04118        return CKR_OBJECT_HANDLE_INVALID;
04119     }
04120     /*
04121      * create an object to hang the attributes off of
04122      */
04123     destObject = sftk_NewObject(slot); /* fill in the handle later */
04124     if (destObject == NULL) {
04125        sftk_FreeSession(session);
04126         sftk_FreeObject(srcObject);
04127        return CKR_HOST_MEMORY;
04128     }
04129 
04130     /*
04131      * load the template values into the object
04132      */
04133     for (i=0; i < (int) ulCount; i++) {
04134        if (sftk_modifyType(pTemplate[i].type,srcObject->objclass) == SFTK_NEVER) {
04135            crv = CKR_ATTRIBUTE_READ_ONLY;
04136            break;
04137        }
04138        crv = sftk_AddAttributeType(destObject,sftk_attr_expand(&pTemplate[i]));
04139        if (crv != CKR_OK) { break; }
04140     }
04141     if (crv != CKR_OK) {
04142        sftk_FreeSession(session);
04143         sftk_FreeObject(srcObject);
04144        sftk_FreeObject(destObject);
04145        return crv;
04146     }
04147 
04148     /* sensitive can only be changed to CK_TRUE */
04149     if (sftk_hasAttribute(destObject,CKA_SENSITIVE)) {
04150        if (!sftk_isTrue(destObject,CKA_SENSITIVE)) {
04151            sftk_FreeSession(session);
04152             sftk_FreeObject(srcObject);
04153            sftk_FreeObject(destObject);
04154            return CKR_ATTRIBUTE_READ_ONLY;
04155        }
04156     }
04157 
04158     /*
04159      * now copy the old attributes from the new attributes
04160      */
04161     /* don't create a token object if we aren't in a rw session */
04162     /* we need to hold the lock to copy a consistant version of
04163      * the object. */
04164     crv = sftk_CopyObject(destObject,srcObject);
04165 
04166     destObject->objclass = srcObject->objclass;
04167     sftk_FreeObject(srcObject);
04168     if (crv != CKR_OK) {
04169        sftk_FreeObject(destObject);
04170        sftk_FreeSession(session);
04171         return crv;
04172     }
04173 
04174     crv = sftk_handleObject(destObject,session);
04175     *phNewObject = destObject->handle;
04176     sftk_FreeSession(session);
04177     sftk_FreeObject(destObject);
04178     
04179     return crv;
04180 }
04181 
04182 
04183 /* NSC_GetObjectSize gets the size of an object in bytes. */
04184 CK_RV NSC_GetObjectSize(CK_SESSION_HANDLE hSession,
04185                      CK_OBJECT_HANDLE hObject, CK_ULONG_PTR pulSize) {
04186     *pulSize = 0;
04187     return CKR_OK;
04188 }
04189 
04190 
04191 /* NSC_GetAttributeValue obtains the value of one or more object attributes. */
04192 CK_RV NSC_GetAttributeValue(CK_SESSION_HANDLE hSession,
04193     CK_OBJECT_HANDLE hObject,CK_ATTRIBUTE_PTR pTemplate,CK_ULONG ulCount) {
04194     SFTKSlot *slot = sftk_SlotFromSessionHandle(hSession);
04195     SFTKSession *session;
04196     SFTKObject *object;
04197     SFTKAttribute *attribute;
04198     PRBool sensitive;
04199     CK_RV crv;
04200     int i;
04201 
04202     /*
04203      * make sure we're allowed
04204      */
04205     session = sftk_SessionFromHandle(hSession);
04206     if (session == NULL) {
04207         return CKR_SESSION_HANDLE_INVALID;
04208     }
04209 
04210     object = sftk_ObjectFromHandle(hObject,session);
04211     sftk_FreeSession(session);
04212     if (object == NULL) {
04213        return CKR_OBJECT_HANDLE_INVALID;
04214     }
04215 
04216     /* don't read a private object if we aren't logged in */
04217     if ((!slot->isLoggedIn) && (slot->needLogin) &&
04218                             (sftk_isTrue(object,CKA_PRIVATE))) {
04219        sftk_FreeObject(object);
04220        return CKR_USER_NOT_LOGGED_IN;
04221     }
04222 
04223     crv = CKR_OK;
04224     sensitive = sftk_isTrue(object,CKA_SENSITIVE);
04225     for (i=0; i < (int) ulCount; i++) {
04226        /* Make sure that this attribute is retrievable */
04227        if (sensitive && sftk_isSensitive(pTemplate[i].type,object->objclass)) {
04228            crv = CKR_ATTRIBUTE_SENSITIVE;
04229            pTemplate[i].ulValueLen = -1;
04230            continue;
04231        }
04232        attribute = sftk_FindAttribute(object,pTemplate[i].type);
04233        if (attribute == NULL) {
04234            crv = CKR_ATTRIBUTE_TYPE_INVALID;
04235            pTemplate[i].ulValueLen = -1;
04236            continue;
04237        }
04238        if (pTemplate[i].pValue != NULL) {
04239            PORT_Memcpy(pTemplate[i].pValue,attribute->attrib.pValue,
04240                                           attribute->attrib.ulValueLen);
04241        }
04242        pTemplate[i].ulValueLen = attribute->attrib.ulValueLen;
04243        sftk_FreeAttribute(attribute);
04244     }
04245 
04246     sftk_FreeObject(object);
04247     return crv;
04248 }
04249 
04250 /* NSC_SetAttributeValue modifies the value of one or more object attributes */
04251 CK_RV NSC_SetAttributeValue (CK_SESSION_HANDLE hSession,
04252  CK_OBJECT_HANDLE hObject,CK_ATTRIBUTE_PTR pTemplate,CK_ULONG ulCount) {
04253     SFTKSlot *slot = sftk_SlotFromSessionHandle(hSession);
04254     SFTKSession *session;
04255     SFTKAttribute *attribute;
04256     SFTKObject *object;
04257     PRBool isToken;
04258     CK_RV crv = CKR_OK;
04259     CK_BBOOL legal;
04260     int i;
04261 
04262     /*
04263      * make sure we're allowed
04264      */
04265     session = sftk_SessionFromHandle(hSession);
04266     if (session == NULL) {
04267         return CKR_SESSION_HANDLE_INVALID;
04268     }
04269 
04270     object = sftk_ObjectFromHandle(hObject,session);
04271     if (object == NULL) {
04272         sftk_FreeSession(session);
04273        return CKR_OBJECT_HANDLE_INVALID;
04274     }
04275 
04276     /* don't modify a private object if we aren't logged in */
04277     if ((!slot->isLoggedIn) && (slot->needLogin) &&
04278                             (sftk_isTrue(object,CKA_PRIVATE))) {
04279        sftk_FreeSession(session);
04280        sftk_FreeObject(object);
04281        return CKR_USER_NOT_LOGGED_IN;
04282     }
04283 
04284     /* don't modify a token object if we aren't in a rw session */
04285     isToken = sftk_isTrue(object,CKA_TOKEN);
04286     if (((session->info.flags & CKF_RW_SESSION) == 0) && isToken) {
04287        sftk_FreeSession(session);
04288        sftk_FreeObject(object);
04289        return CKR_SESSION_READ_ONLY;
04290     }
04291     sftk_FreeSession(session);
04292 
04293     /* only change modifiable objects */
04294     if (!sftk_isTrue(object,CKA_MODIFIABLE)) {
04295        sftk_FreeObject(object);
04296        return CKR_ATTRIBUTE_READ_ONLY;
04297     }
04298 
04299     for (i=0; i < (int) ulCount; i++) {
04300        /* Make sure that this attribute is changeable */
04301        switch (sftk_modifyType(pTemplate[i].type,object->objclass)) {
04302        case SFTK_NEVER:
04303        case SFTK_ONCOPY:
04304         default:
04305            crv = CKR_ATTRIBUTE_READ_ONLY;
04306            break;
04307 
04308         case SFTK_SENSITIVE:
04309            legal = (pTemplate[i].type == CKA_EXTRACTABLE) ? CK_FALSE : CK_TRUE;
04310            if ((*(CK_BBOOL *)pTemplate[i].pValue) != legal) {
04311                crv = CKR_ATTRIBUTE_READ_ONLY;
04312            }
04313            break;
04314         case SFTK_ALWAYS:
04315            break;
04316        }
04317        if (crv != CKR_OK) break;
04318 
04319        /* find the old attribute */
04320        attribute = sftk_FindAttribute(object,pTemplate[i].type);
04321        if (attribute == NULL) {
04322            crv =CKR_ATTRIBUTE_TYPE_INVALID;
04323            break;
04324        }
04325        sftk_FreeAttribute(attribute);
04326        crv = sftk_forceAttribute(object,sftk_attr_expand(&pTemplate[i]));
04327        if (crv != CKR_OK) break;
04328 
04329     }
04330 
04331     sftk_FreeObject(object);
04332     return crv;
04333 }
04334 
04335 /*
04336  * find any certs that may match the template and load them.
04337  */
04338 #define NSC_CERT     0x00000001
04339 #define NSC_TRUST    0x00000002
04340 #define NSC_CRL             0x00000004
04341 #define NSC_SMIME    0x00000008
04342 #define NSC_PRIVATE  0x00000010
04343 #define NSC_PUBLIC   0x00000020
04344 #define NSC_KEY             0x00000040
04345 
04346 /*
04347  * structure to collect key handles.
04348  */
04349 typedef struct sftkCrlDataStr {
04350     SFTKSlot *slot;
04351     SFTKSearchResults *searchHandles;
04352     CK_ATTRIBUTE *template;
04353     CK_ULONG templ_count;
04354 } sftkCrlData;
04355 
04356 
04357 static SECStatus
04358 sftk_crl_collect(SECItem *data, SECItem *key, certDBEntryType type, void *arg)
04359 {
04360     sftkCrlData *crlData;
04361     CK_OBJECT_HANDLE class_handle;
04362     SFTKSlot *slot;
04363     
04364     crlData = (sftkCrlData *)arg;
04365     slot = crlData->slot;
04366 
04367     class_handle = (type == certDBEntryTypeRevocation) ? SFTK_TOKEN_TYPE_CRL :
04368                                                  SFTK_TOKEN_KRL_HANDLE;
04369     if (sftk_tokenMatch(slot, key, class_handle,
04370                      crlData->template, crlData->templ_count)) {
04371        sftk_addHandle(crlData->searchHandles,
04372                              sftk_mkHandle(slot,key,class_handle));
04373     }
04374     return(SECSuccess);
04375 }
04376 
04377 static void
04378 sftk_searchCrls(SFTKSlot *slot, SECItem *derSubject, PRBool isKrl, 
04379               unsigned long classFlags, SFTKSearchResults *search,
04380               CK_ATTRIBUTE *pTemplate, CK_ULONG ulCount)
04381 {
04382     NSSLOWCERTCertDBHandle *certHandle = NULL;
04383 
04384     certHandle = sftk_getCertDB(slot);
04385     if (certHandle == NULL) {
04386        return;
04387     }
04388     if (derSubject->data != NULL)  {
04389        certDBEntryRevocation *crl = 
04390            nsslowcert_FindCrlByKey(certHandle, derSubject, isKrl);
04391 
04392        if (crl != NULL) {
04393            sftk_addHandle(search, sftk_mkHandle(slot, derSubject,
04394               isKrl ? SFTK_TOKEN_KRL_HANDLE : SFTK_TOKEN_TYPE_CRL));
04395            nsslowcert_DestroyDBEntry((certDBEntry *)crl);
04396        }
04397     } else {
04398        sftkCrlData crlData;
04399 
04400        /* traverse */
04401        crlData.slot = slot;
04402        crlData.searchHandles = search;
04403        crlData.template = pTemplate;
04404        crlData.templ_count = ulCount;
04405        nsslowcert_TraverseDBEntries(certHandle, certDBEntryTypeRevocation,
04406               sftk_crl_collect, (void *)&crlData);
04407        nsslowcert_TraverseDBEntries(certHandle, certDBEntryTypeKeyRevocation,
04408               sftk_crl_collect, (void *)&crlData);
04409     } 
04410     sftk_freeCertDB(certHandle);
04411 }
04412 
04413 /*
04414  * structure to collect key handles.
04415  */
04416 typedef struct sftkKeyDataStr {
04417     SFTKSlot *slot;
04418     NSSLOWKEYDBHandle *keyHandle;
04419     SFTKSearchResults *searchHandles;
04420     SECItem *id;
04421     CK_ATTRIBUTE *template;
04422     CK_ULONG templ_count;
04423     unsigned long classFlags;
04424     PRBool isLoggedIn;
04425     PRBool strict;
04426 } sftkKeyData;
04427 
04428 
04429 static SECStatus
04430 sftk_key_collect(DBT *key, DBT *data, void *arg)
04431 {
04432     sftkKeyData *keyData;
04433     NSSLOWKEYPrivateKey *privKey = NULL;
04434     SECItem tmpDBKey;
04435     SFTKSlot *slot;
04436     
04437     keyData = (sftkKeyData *)arg;
04438     slot = keyData->slot;
04439 
04440     tmpDBKey.data = key->data;
04441     tmpDBKey.len = key->size;
04442     tmpDBKey.type = siBuffer;
04443 
04444     PORT_Assert(keyData->keyHandle);
04445     if (!keyData->strict && keyData->id) {
04446        SECItem result;
04447        PRBool haveMatch= PR_FALSE;
04448        unsigned char hashKey[SHA1_LENGTH];
04449        result.data = hashKey;
04450        result.len = sizeof(hashKey);
04451 
04452        if (keyData->id->len == 0) {
04453            /* Make sure this isn't a NSC_KEY */
04454            privKey = nsslowkey_FindKeyByPublicKey(keyData->keyHandle, 
04455                                    &tmpDBKey, keyData->slot->password);
04456            if (privKey) {
04457               haveMatch = isSecretKey(privKey) ?
04458                             (PRBool)(keyData->classFlags & NSC_KEY) != 0:
04459                             (PRBool)(keyData->classFlags & 
04460                                          (NSC_PRIVATE|NSC_PUBLIC)) != 0;
04461               nsslowkey_DestroyPrivateKey(privKey);
04462            }
04463        } else {
04464            SHA1_HashBuf( hashKey, key->data, key->size ); /* match id */
04465            haveMatch = SECITEM_ItemsAreEqual(keyData->id,&result);
04466            if (!haveMatch && ((unsigned char *)key->data)[0] == 0) {
04467               /* This is a fix for backwards compatibility.  The key
04468                * database indexes private keys by the public key, and
04469                * versions of NSS prior to 3.4 stored the public key as
04470                * a signed integer.  The public key is now treated as an
04471                * unsigned integer, with no leading zero.  In order to
04472                * correctly compute the hash of an old key, it is necessary
04473                * to fallback and detect the leading zero.
04474                */
04475               SHA1_HashBuf(hashKey, 
04476                            (unsigned char *)key->data + 1, key->size - 1);
04477               haveMatch = SECITEM_ItemsAreEqual(keyData->id,&result);
04478            }
04479        }
04480        if (haveMatch) {
04481            if (keyData->classFlags & NSC_PRIVATE)  {
04482               sftk_addHandle(keyData->searchHandles,
04483                      sftk_mkHandle(slot,&tmpDBKey,SFTK_TOKEN_TYPE_PRIV));
04484            }
04485            if (keyData->classFlags & NSC_PUBLIC) {
04486               sftk_addHandle(keyData->searchHandles,
04487                      sftk_mkHandle(slot,&tmpDBKey,SFTK_TOKEN_TYPE_PUB));
04488            }
04489            if (keyData->classFlags & NSC_KEY) {
04490               sftk_addHandle(keyData->searchHandles,
04491                      sftk_mkHandle(slot,&tmpDBKey,SFTK_TOKEN_TYPE_KEY));
04492            }
04493        }
04494        return SECSuccess;
04495     }
04496 
04497     privKey = nsslowkey_FindKeyByPublicKey(keyData->keyHandle, &tmpDBKey, 
04498                                            keyData->slot->password);
04499     if ( privKey == NULL ) {
04500        goto loser;
04501     }
04502 
04503     if (isSecretKey(privKey)) {
04504        if ((keyData->classFlags & NSC_KEY) && 
04505               sftk_tokenMatch(keyData->slot, &tmpDBKey, SFTK_TOKEN_TYPE_KEY,
04506                      keyData->template, keyData->templ_count)) {
04507            sftk_addHandle(keyData->searchHandles,
04508               sftk_mkHandle(keyData->slot, &tmpDBKey, SFTK_TOKEN_TYPE_KEY));
04509        }
04510     } else {
04511        if ((keyData->classFlags & NSC_PRIVATE) && 
04512               sftk_tokenMatch(keyData->slot, &tmpDBKey, SFTK_TOKEN_TYPE_PRIV,
04513                      keyData->template, keyData->templ_count)) {
04514            sftk_addHandle(keyData->searchHandles,
04515               sftk_mkHandle(keyData->slot,&tmpDBKey,SFTK_TOKEN_TYPE_PRIV));
04516        }
04517        if ((keyData->classFlags & NSC_PUBLIC) && 
04518               sftk_tokenMatch(keyData->slot, &tmpDBKey, SFTK_TOKEN_TYPE_PUB,
04519                      keyData->template, keyData->templ_count)) {
04520            sftk_addHandle(keyData->searchHandles,
04521               sftk_mkHandle(keyData->slot, &tmpDBKey,SFTK_TOKEN_TYPE_PUB));
04522        }
04523     }
04524 
04525 loser:
04526     if ( privKey ) {
04527        nsslowkey_DestroyPrivateKey(privKey);
04528     }
04529     return(SECSuccess);
04530 }
04531 
04532 static void
04533 sftk_searchKeys(SFTKSlot *slot, SECItem *key_id, PRBool isLoggedIn,
04534        unsigned long classFlags, SFTKSearchResults *search, PRBool mustStrict,
04535        CK_ATTRIBUTE *pTemplate, CK_ULONG ulCount)
04536 {
04537     NSSLOWKEYDBHandle *keyHandle = NULL;
04538     NSSLOWKEYPrivateKey *privKey;
04539     sftkKeyData keyData;
04540     PRBool found = PR_FALSE;
04541 
04542     keyHandle = sftk_getKeyDB(slot);
04543     if (keyHandle == NULL) {
04544        return;
04545     }
04546 
04547     if (key_id->data) {
04548        privKey = nsslowkey_FindKeyByPublicKey(keyHandle, key_id, slot->password);
04549        if (privKey) {
04550            if ((classFlags & NSC_KEY) && isSecretKey(privKey)) {
04551                sftk_addHandle(search,
04552                      sftk_mkHandle(slot,key_id,SFTK_TOKEN_TYPE_KEY));
04553               found = PR_TRUE;
04554            }
04555            if ((classFlags & NSC_PRIVATE) && !isSecretKey(privKey)) {
04556                sftk_addHandle(search,
04557                      sftk_mkHandle(slot,key_id,SFTK_TOKEN_TYPE_PRIV));
04558               found = PR_TRUE;
04559            }
04560            if ((classFlags & NSC_PUBLIC) && !isSecretKey(privKey)) {
04561                sftk_addHandle(search,
04562                      sftk_mkHandle(slot,key_id,SFTK_TOKEN_TYPE_PUB));
04563               found = PR_TRUE;
04564            }
04565            nsslowkey_DestroyPrivateKey(privKey);
04566        }
04567        /* don't do the traversal if we have an up to date db */
04568        if (keyHandle->version != 3) {
04569            goto loser;
04570        }
04571        /* don't do the traversal if it can't possibly be the correct id */
04572        /* all soft token id's are SHA1_HASH_LEN's */
04573        if (key_id->len != SHA1_LENGTH) {
04574            goto loser;
04575        }
04576        if (found) {
04577           /* if we already found some keys, don't do the traversal */
04578           goto loser;
04579        }
04580     }
04581     keyData.slot = slot;
04582     keyData.keyHandle = keyHandle;
04583     keyData.searchHandles = search;
04584     keyData.id = key_id;
04585     keyData.template = pTemplate;
04586     keyData.templ_count = ulCount;
04587     keyData.isLoggedIn = isLoggedIn;
04588     keyData.classFlags = classFlags;
04589     keyData.strict = mustStrict ? mustStrict : NSC_STRICT;
04590 
04591     nsslowkey_TraverseKeys(keyHandle, sftk_key_collect, &keyData);
04592 loser:
04593     sftk_freeKeyDB(keyHandle);
04594        
04595 }
04596 
04597 /*
04598  * structure to collect certs into
04599  */
04600 typedef struct sftkCertDataStr {
04601     SFTKSlot *slot;
04602     int cert_count;
04603     int max_cert_count;
04604     NSSLOWCERTCertificate **certs;
04605     CK_ATTRIBUTE *template;
04606     CK_ULONG  templ_count;
04607     unsigned long classFlags;
04608     PRBool    strict;
04609 } sftkCertData;
04610 
04611 /*
04612  * collect all the certs from the traverse call.
04613  */    
04614 static SECStatus
04615 sftk_cert_collect(NSSLOWCERTCertificate *cert,void *arg)
04616 {
04617     sftkCertData *cd = (sftkCertData *)arg;
04618 
04619     if (cert == NULL) {
04620        return SECSuccess;
04621     }
04622 
04623     if (cd->certs == NULL) {
04624        return SECFailure;
04625     }
04626 
04627     if (cd->strict) {
04628        if ((cd->classFlags & NSC_CERT) && !sftk_tokenMatch(cd->slot,
04629          &cert->certKey, SFTK_TOKEN_TYPE_CERT, cd->template,cd->templ_count)) {
04630            return SECSuccess;
04631        }
04632        if ((cd->classFlags & NSC_TRUST) && !sftk_tokenMatch(cd->slot,
04633          &cert->certKey, SFTK_TOKEN_TYPE_TRUST, 
04634                                         cd->template, cd->templ_count)) {
04635            return SECSuccess;
04636        }
04637     }
04638 
04639     /* allocate more space if we need it. This should only happen in
04640      * the general traversal case */
04641     if (cd->cert_count >= cd->max_cert_count) {
04642        int size;
04643        cd->max_cert_count += NSC_CERT_BLOCK_SIZE;
04644        size = cd->max_cert_count * sizeof (NSSLOWCERTCertificate *);
04645        cd->certs = (NSSLOWCERTCertificate **)PORT_Realloc(cd->certs,size);
04646        if (cd->certs == NULL) {
04647            return SECFailure;
04648        }
04649     }
04650 
04651     cd->certs[cd->cert_count++] = nsslowcert_DupCertificate(cert);
04652     return SECSuccess;
04653 }
04654 
04655 /* provide impedence matching ... */
04656 static SECStatus
04657 sftk_cert_collect2(NSSLOWCERTCertificate *cert, SECItem *dymmy, void *arg)
04658 {
04659     return sftk_cert_collect(cert, arg);
04660 }
04661 
04662 static void
04663 sftk_searchSingleCert(sftkCertData *certData,NSSLOWCERTCertificate *cert)
04664 {
04665     if (cert == NULL) {
04666            return;
04667     }
04668     if (certData->strict && 
04669        !sftk_tokenMatch(certData->slot, &cert->certKey, SFTK_TOKEN_TYPE_CERT, 
04670                             certData->template,certData->templ_count)) {
04671        nsslowcert_DestroyCertificate(cert);
04672        return;
04673     }
04674     certData->certs = (NSSLOWCERTCertificate **) 
04675                             PORT_Alloc(sizeof (NSSLOWCERTCertificate *));
04676     if (certData->certs == NULL) {
04677        nsslowcert_DestroyCertificate(cert);
04678        return;
04679     }
04680     certData->certs[0] = cert;
04681     certData->cert_count = 1;
04682 }
04683 
04684 static void
04685 sftk_CertSetupData(sftkCertData *certData,int count)
04686 {
04687     certData->max_cert_count = count;
04688 
04689     if (certData->max_cert_count <= 0) {
04690        return;
04691     }
04692     certData->certs = (NSSLOWCERTCertificate **)
04693                       PORT_Alloc( count * sizeof(NSSLOWCERTCertificate *));
04694     return;
04695 }
04696 
04697 static void
04698 sftk_searchCertsAndTrust(SFTKSlot *slot, SECItem *derCert, SECItem *name, 
04699                      SECItem *derSubject, NSSLOWCERTIssuerAndSN *issuerSN, 
04700                      SECItem *email,
04701                      unsigned long classFlags, SFTKSearchResults *handles, 
04702                      CK_ATTRIBUTE *pTemplate, CK_LONG ulCount)
04703 {
04704     NSSLOWCERTCertDBHandle *certHandle = NULL;
04705     sftkCertData certData;
04706     int i;
04707 
04708     certHandle = sftk_getCertDB(slot);
04709     if (certHandle == NULL) return;
04710 
04711     certData.slot = slot;
04712     certData.max_cert_count = 0;
04713     certData.certs = NULL;
04714     certData.cert_count = 0;
04715     certData.template = pTemplate;
04716     certData.templ_count = ulCount;
04717     certData.classFlags = classFlags; 
04718     certData.strict = NSC_STRICT; 
04719 
04720 
04721     /*
04722      * Find the Cert.
04723      */
04724     if (derCert->data != NULL) {
04725        NSSLOWCERTCertificate *cert = 
04726                      nsslowcert_FindCertByDERCert(certHandle,derCert);
04727        sftk_searchSingleCert(&certData,cert);
04728     } else if (name->data != NULL) {
04729        char *tmp_name = (char*)PORT_Alloc(name->len+1);
04730        int count;
04731 
04732        if (tmp_name == NULL) {
04733            return;
04734        }
04735        PORT_Memcpy(tmp_name,name->data,name->len);
04736        tmp_name[name->len] = 0;
04737 
04738        count= nsslowcert_NumPermCertsForNickname(certHandle,tmp_name);
04739        sftk_CertSetupData(&certData,count);
04740        nsslowcert_TraversePermCertsForNickname(certHandle,tmp_name,
04741                             sftk_cert_collect, &certData);
04742        PORT_Free(tmp_name);
04743     } else if (derSubject->data != NULL) {
04744        int count;
04745 
04746        count = nsslowcert_NumPermCertsForSubject(certHandle,derSubject);
04747        sftk_CertSetupData(&certData,count);
04748        nsslowcert_TraversePermCertsForSubject(certHandle,derSubject,
04749                             sftk_cert_collect, &certData);
04750     } else if ((issuerSN->derIssuer.data != NULL) && 
04751                      (issuerSN->serialNumber.data != NULL)) {
04752         if (classFlags & NSC_CERT) {
04753            NSSLOWCERTCertificate *cert = 
04754               nsslowcert_FindCertByIssuerAndSN(certHandle,issuerSN);
04755 
04756            sftk_searchSingleCert(&certData,cert);
04757        }
04758        if (classFlags & NSC_TRUST) {
04759            NSSLOWCERTTrust *trust = 
04760               nsslowcert_FindTrustByIssuerAndSN(certHandle, issuerSN);
04761 
04762            if (trust) {
04763               sftk_addHandle(handles,
04764                   sftk_mkHandle(slot,&trust->dbKey,SFTK_TOKEN_TYPE_TRUST));
04765               nsslowcert_DestroyTrust(trust);
04766            }
04767        }
04768     } else if (email->data != NULL) {
04769        char *tmp_name = (char*)PORT_Alloc(email->len+1);
04770        certDBEntrySMime *entry = NULL;
04771 
04772        if (tmp_name == NULL) {
04773            return;
04774        }
04775        PORT_Memcpy(tmp_name,email->data,email->len);
04776        tmp_name[email->len] = 0;
04777 
04778        entry = nsslowcert_ReadDBSMimeEntry(certHandle,tmp_name);
04779        if (entry) {
04780            int count;
04781            SECItem *subjectName = &entry->subjectName;
04782 
04783            count = nsslowcert_NumPermCertsForSubject(certHandle, subjectName);
04784            sftk_CertSetupData(&certData,count);
04785            nsslowcert_TraversePermCertsForSubject(certHandle, subjectName, 
04786                                           sftk_cert_collect, &certData);
04787 
04788            nsslowcert_DestroyDBEntry((certDBEntry *)entry);
04789        }
04790        PORT_Free(tmp_name);
04791     } else {
04792        /* we aren't filtering the certs, we are working on all, so turn
04793         * on the strict filters. */
04794        certData.strict = PR_TRUE;
04795        sftk_CertSetupData(&certData,NSC_CERT_BLOCK_SIZE);
04796        nsslowcert_TraversePermCerts(certHandle, sftk_cert_collect2, &certData);
04797     }
04798     sftk_freeCertDB(certHandle);
04799 
04800     /*
04801      * build the handles
04802      */       
04803     for (i=0 ; i < certData.cert_count ; i++) {
04804        NSSLOWCERTCertificate *cert = certData.certs[i];
04805 
04806        /* if we filtered it would have been on the stuff above */
04807        if (classFlags & NSC_CERT) {
04808            sftk_addHandle(handles,
04809               sftk_mkHandle(slot,&cert->certKey,SFTK_TOKEN_TYPE_CERT));
04810        }
04811        if ((classFlags & NSC_TRUST) && nsslowcert_hasTrust(cert->trust)) {
04812            sftk_addHandle(handles,
04813               sftk_mkHandle(slot,&cert->certKey,SFTK_TOKEN_TYPE_TRUST));
04814        }
04815        nsslowcert_DestroyCertificate(cert);
04816     }
04817 
04818     if (certData.certs) PORT_Free(certData.certs);
04819     return;
04820 }
04821 
04822 static void
04823 sftk_searchSMime(SFTKSlot *slot, SECItem *email, SFTKSearchResults *handles, 
04824                      CK_ATTRIBUTE *pTemplate, CK_LONG ulCount)
04825 {
04826     NSSLOWCERTCertDBHandle *certHandle = NULL;
04827     certDBEntrySMime *entry;
04828 
04829     certHandle = sftk_getCertDB(slot);
04830     if (certHandle == NULL) return;
04831 
04832     if (email->data != NULL) {
04833        char *tmp_name = (char*)PORT_Alloc(email->len+1);
04834 
04835        if (tmp_name == NULL) {
04836            sftk_freeCertDB(certHandle);
04837            return;
04838        }
04839        PORT_Memcpy(tmp_name,email->data,email->len);
04840        tmp_name[email->len] = 0;
04841 
04842        entry = nsslowcert_ReadDBSMimeEntry(certHandle,tmp_name);
04843        if (entry) {
04844            SECItem emailKey;
04845 
04846            emailKey.data = (unsigned char *)tmp_name;
04847            emailKey.len = PORT_Strlen(tmp_name)+1;
04848            emailKey.type = 0;
04849            sftk_addHandle(handles,
04850               sftk_mkHandle(slot,&emailKey,SFTK_TOKEN_TYPE_SMIME));
04851            nsslowcert_DestroyDBEntry((certDBEntry *)entry);
04852        }
04853        PORT_Free(tmp_name);
04854     }
04855     sftk_freeCertDB(certHandle);
04856     return;
04857 }
04858 
04859 static CK_RV
04860 sftk_searchTokenList(SFTKSlot *slot, SFTKSearchResults *search,
04861                      CK_ATTRIBUTE *pTemplate, CK_LONG ulCount, 
04862                      PRBool *tokenOnly, PRBool isLoggedIn)
04863 {
04864     int i;
04865     PRBool isKrl = PR_FALSE;
04866     SECItem derCert = { siBuffer, NULL, 0 };
04867     SECItem derSubject = { siBuffer, NULL, 0 };
04868     SECItem name = { siBuffer, NULL, 0 };
04869     SECItem email = { siBuffer, NULL, 0 };
04870     SECItem key_id = { siBuffer, NULL, 0 };
04871     SECItem cert_sha1_hash = { siBuffer, NULL, 0 };
04872     SECItem cert_md5_hash  = { siBuffer, NULL, 0 };
04873     NSSLOWCERTIssuerAndSN issuerSN = {
04874        { siBuffer, NULL, 0 },
04875        { siBuffer, NULL, 0 }
04876     };
04877     SECItem *copy = NULL;
04878     unsigned long classFlags = 
04879        NSC_CERT|NSC_TRUST|NSC_PRIVATE|NSC_PUBLIC|NSC_KEY|NSC_SMIME|NSC_CRL;
04880 
04881     /* if we aren't logged in, don't look for private or secret keys */
04882     if (!isLoggedIn) {
04883        classFlags &= ~(NSC_PRIVATE|NSC_KEY);
04884     }
04885 
04886     /*
04887      * look for things to search on token objects for. If the right options
04888      * are specified, we can use them as direct indeces into the database
04889      * (rather than using linear searches. We can also use the attributes to
04890      * limit the kinds of objects we are searching for. Later we can use this
04891      * array to filter the remaining objects more finely.
04892      */
04893     for (i=0 ;classFlags && i < (int)ulCount; i++) {
04894 
04895        switch (pTemplate[i].type) {
04896        case CKA_SUBJECT:
04897            copy = &derSubject;
04898            classFlags &= (NSC_CERT|NSC_PRIVATE|NSC_PUBLIC|NSC_SMIME|NSC_CRL);
04899            break;
04900        case CKA_ISSUER: 
04901            copy = &issuerSN.derIssuer;
04902            classFlags &= (NSC_CERT|NSC_TRUST);
04903            break;
04904        case CKA_SERIAL_NUMBER: 
04905            copy = &issuerSN.serialNumber;
04906            classFlags &= (NSC_CERT|NSC_TRUST);
04907            break;
04908        case CKA_VALUE:
04909            copy = &derCert;
04910            classFlags &= (NSC_CERT|NSC_CRL|NSC_SMIME);
04911            break;
04912        case CKA_LABEL:
04913            copy = &name;
04914            break;
04915        case CKA_NETSCAPE_EMAIL:
04916            copy = &email;
04917            classFlags &= NSC_SMIME|NSC_CERT;
04918            break;
04919        case CKA_NETSCAPE_SMIME_TIMESTAMP:
04920            classFlags &= NSC_SMIME;
04921            break;
04922        case CKA_CLASS:
04923            if (pTemplate[i].ulValueLen != sizeof(CK_OBJECT_CLASS)) {
04924               classFlags = 0;
04925               break;;
04926            }
04927            switch (*((CK_OBJECT_CLASS *)pTemplate[i].pValue)) {
04928            case CKO_CERTIFICATE:
04929               classFlags &= NSC_CERT;
04930               break;
04931            case CKO_NETSCAPE_TRUST:
04932               classFlags &= NSC_TRUST;
04933               break;
04934            case CKO_NETSCAPE_CRL:
04935               classFlags &= NSC_CRL;
04936               break;
04937            case CKO_NETSCAPE_SMIME:
04938               classFlags &= NSC_SMIME;
04939               break;
04940            case CKO_PRIVATE_KEY:
04941               classFlags &= NSC_PRIVATE;
04942               break;
04943            case CKO_PUBLIC_KEY:
04944               classFlags &= NSC_PUBLIC;
04945               break;
04946            case CKO_SECRET_KEY:
04947               classFlags &= NSC_KEY;
04948               break;
04949            default:
04950               classFlags = 0;
04951               break;
04952            }
04953            break;
04954        case CKA_PRIVATE:
04955            if (pTemplate[i].ulValueLen != sizeof(CK_BBOOL)) {
04956               classFlags = 0;
04957            }
04958            if (*((CK_BBOOL *)pTemplate[i].pValue) == CK_TRUE) {
04959               classFlags &= (NSC_PRIVATE|NSC_KEY);
04960            } else {
04961               classFlags &= ~(NSC_PRIVATE|NSC_KEY);
04962            }
04963            break;
04964        case CKA_SENSITIVE:
04965            if (pTemplate[i].ulValueLen != sizeof(CK_BBOOL)) {
04966               classFlags = 0;
04967            }
04968            if (*((CK_BBOOL *)pTemplate[i].pValue) == CK_TRUE) {
04969               classFlags &= (NSC_PRIVATE|NSC_KEY);
04970            } else {
04971               classFlags = 0;
04972            }
04973            break;
04974        case CKA_TOKEN:
04975            if (pTemplate[i].ulValueLen != sizeof(CK_BBOOL)) {
04976               classFlags = 0;
04977            }
04978            if (*((CK_BBOOL *)pTemplate[i].pValue) == CK_TRUE) {
04979               *tokenOnly = PR_TRUE;
04980            } else {
04981               classFlags = 0;
04982            }
04983            break;
04984        case CKA_CERT_SHA1_HASH:
04985            classFlags &= NSC_TRUST;
04986            copy = &cert_sha1_hash; break;
04987        case CKA_CERT_MD5_HASH:
04988            classFlags &= NSC_TRUST;
04989            copy = &cert_md5_hash; break;
04990        case CKA_CERTIFICATE_TYPE:
04991            if (pTemplate[i].ulValueLen != sizeof(CK_CERTIFICATE_TYPE)) {
04992               classFlags = 0;
04993            }
04994            classFlags &= NSC_CERT;
04995            if (*((CK_CERTIFICATE_TYPE *)pTemplate[i].pValue) != CKC_X_509) {
04996               classFlags = 0;
04997            }
04998            break;
04999        case CKA_ID:
05000            copy = &key_id;
05001            classFlags &= (NSC_CERT|NSC_PRIVATE|NSC_KEY|NSC_PUBLIC);
05002            break;
05003        case CKA_NETSCAPE_KRL:
05004            if (pTemplate[i].ulValueLen != sizeof(CK_BBOOL)) {
05005               classFlags = 0;
05006            }
05007            classFlags &= NSC_CRL;
05008            isKrl = (PRBool)(*((CK_BBOOL *)pTemplate[i].pValue) == CK_TRUE);
05009            break;
05010        case CKA_MODIFIABLE:
05011             break;
05012        case CKA_KEY_TYPE:
05013        case CKA_DERIVE:
05014            classFlags &= NSC_PUBLIC|NSC_PRIVATE|NSC_KEY;
05015            break;
05016        case CKA_VERIFY_RECOVER:
05017            classFlags &= NSC_PUBLIC;
05018            break;
05019        case CKA_SIGN_RECOVER:
05020            classFlags &= NSC_PRIVATE;
05021            break;
05022        case CKA_ENCRYPT:
05023        case CKA_VERIFY:
05024        case CKA_WRAP:
05025            classFlags &= NSC_PUBLIC|NSC_KEY;
05026            break;
05027        case CKA_DECRYPT:
05028        case CKA_SIGN:
05029        case CKA_UNWRAP:
05030        case CKA_ALWAYS_SENSITIVE:
05031        case CKA_EXTRACTABLE:
05032        case CKA_NEVER_EXTRACTABLE:
05033            classFlags &= NSC_PRIVATE|NSC_KEY;
05034            break;
05035        /* can't be a certificate if it doesn't match one of the above 
05036         * attributes */
05037        default: 
05038             classFlags  = 0;
05039             break;
05040        }
05041        if (copy) {
05042            copy->data = (unsigned char*)pTemplate[i].pValue;
05043            copy->len = pTemplate[i].ulValueLen;
05044        }
05045        copy = NULL;
05046     }
05047 
05048 
05049     /* certs */
05050     if (classFlags & (NSC_CERT|NSC_TRUST)) {
05051        sftk_searchCertsAndTrust(slot,&derCert,&name,&derSubject,
05052                              &issuerSN, &email,classFlags,search, 
05053                             pTemplate, ulCount);
05054     }
05055 
05056     /* keys */
05057     if (classFlags & (NSC_PRIVATE|NSC_PUBLIC|NSC_KEY)) {
05058        PRBool mustStrict = ((classFlags & NSC_KEY) != 0) && (name.len != 0);
05059        sftk_searchKeys(slot, &key_id, isLoggedIn, classFlags, search,
05060                       mustStrict, pTemplate, ulCount);
05061     }
05062 
05063     /* crl's */
05064     if (classFlags & NSC_CRL) {
05065        sftk_searchCrls(slot, &derSubject, isKrl, classFlags, search,
05066                      pTemplate, ulCount);
05067     }
05068     /* Add S/MIME entry stuff */
05069     if (classFlags & NSC_SMIME) {
05070        sftk_searchSMime(slot, &email, search, pTemplate, ulCount);
05071     }
05072     return CKR_OK;
05073 }
05074        
05075 
05076 /* NSC_FindObjectsInit initializes a search for token and session objects 
05077  * that match a template. */
05078 CK_RV NSC_FindObjectsInit(CK_SESSION_HANDLE hSession,
05079                      CK_ATTRIBUTE_PTR pTemplate,CK_ULONG ulCount)
05080 {
05081     SFTKSearchResults *search = NULL, *freeSearch = NULL;
05082     SFTKSession *session = NULL;
05083     SFTKSlot *slot = sftk_SlotFromSessionHandle(hSession);
05084     PRBool tokenOnly = PR_FALSE;
05085     CK_RV crv = CKR_OK;
05086     PRBool isLoggedIn;
05087     
05088     session = sftk_SessionFromHandle(hSession);
05089     if (session == NULL) {
05090        crv = CKR_SESSION_HANDLE_INVALID;
05091        goto loser;
05092     }
05093    
05094     search = (SFTKSearchResults *)PORT_Alloc(sizeof(SFTKSearchResults));
05095     if (search == NULL) {
05096        crv = CKR_HOST_MEMORY;
05097        goto loser;
05098     }
05099     search->handles = (CK_OBJECT_HANDLE *)
05100               PORT_Alloc(sizeof(CK_OBJECT_HANDLE) * NSC_SEARCH_BLOCK_SIZE);
05101     if (search->handles == NULL) {
05102        crv = CKR_HOST_MEMORY;
05103        goto loser;
05104     }
05105     search->index = 0;
05106     search->size = 0;
05107     search->array_size = NSC_SEARCH_BLOCK_SIZE;
05108     isLoggedIn = (PRBool)((!slot->needLogin) || slot->isLoggedIn);
05109 
05110     crv = sftk_searchTokenList(slot, search, pTemplate, ulCount, &tokenOnly,
05111                                                         isLoggedIn);
05112     if (crv != CKR_OK) {
05113        goto loser;
05114     }
05115     
05116     /* build list of found objects in the session */
05117     if (!tokenOnly) {
05118        crv = sftk_searchObjectList(search, slot->tokObjects, 
05119                             slot->tokObjHashSize, slot->objectLock, 
05120                                    pTemplate, ulCount, isLoggedIn);
05121     }
05122     if (crv != CKR_OK) {
05123        goto loser;
05124     }
05125 
05126     if ((freeSearch = session->search) != NULL) {
05127        session->search = NULL;
05128        sftk_FreeSearch(freeSearch);
05129     }
05130     session->search = search;
05131     sftk_FreeSession(session);
05132     return CKR_OK;
05133 
05134 loser:
05135     if (search) {
05136        sftk_FreeSearch(search);
05137     }
05138     if (session) {
05139        sftk_FreeSession(session);
05140     }
05141     return crv;
05142 }
05143 
05144 
05145 /* NSC_FindObjects continues a search for token and session objects 
05146  * that match a template, obtaining additional object handles. */
05147 CK_RV NSC_FindObjects(CK_SESSION_HANDLE hSession,
05148     CK_OBJECT_HANDLE_PTR phObject,CK_ULONG ulMaxObjectCount,
05149                                    CK_ULONG_PTR pulObjectCount)
05150 {
05151     SFTKSession *session;
05152     SFTKSearchResults *search;
05153     int       transfer;
05154     int left;
05155 
05156     *pulObjectCount = 0;
05157     session = sftk_SessionFromHandle(hSession);
05158     if (session == NULL) return CKR_SESSION_HANDLE_INVALID;
05159     if (session->search == NULL) {
05160        sftk_FreeSession(session);
05161        return CKR_OK;
05162     }
05163     search = session->search;
05164     left = session->search->size - session->search->index;
05165     transfer = ((int)ulMaxObjectCount > left) ? left : ulMaxObjectCount;
05166     if (transfer > 0) {
05167        PORT_Memcpy(phObject,&search->handles[search->index],
05168                                         transfer*sizeof(CK_OBJECT_HANDLE_PTR));
05169     } else {
05170        *phObject = CK_INVALID_HANDLE;
05171     }
05172 
05173     search->index += transfer;
05174     if (search->index == search->size) {
05175        session->search = NULL;
05176        sftk_FreeSearch(search);
05177     }
05178     *pulObjectCount = transfer;
05179     sftk_FreeSession(session);
05180     return CKR_OK;
05181 }
05182 
05183 /* NSC_FindObjectsFinal finishes a search for token and session objects. */
05184 CK_RV NSC_FindObjectsFinal(CK_SESSION_HANDLE hSession)
05185 {
05186     SFTKSession *session;
05187     SFTKSearchResults *search;
05188 
05189     session = sftk_SessionFromHandle(hSession);
05190     if (session == NULL) return CKR_SESSION_HANDLE_INVALID;
05191     search = session->search;
05192     session->search = NULL;
05193     sftk_FreeSession(session);
05194     if (search != NULL) {
05195        sftk_FreeSearch(search);
05196     }
05197     return CKR_OK;
05198 }
05199 
05200 
05201 
05202 CK_RV NSC_WaitForSlotEvent(CK_FLAGS flags, CK_SLOT_ID_PTR pSlot,
05203                                                   CK_VOID_PTR pReserved)
05204 {
05205     return CKR_FUNCTION_NOT_SUPPORTED;
05206 }