security/nss/lib/softoken/pkcs11.c

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

     1 /* This Source Code Form is subject to the terms of the Mozilla Public
     2  * License, v. 2.0. If a copy of the MPL was not distributed with this
     3  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     4 /*
     5  * This file implements PKCS 11 on top of our existing security modules
     6  *
     7  * For more information about PKCS 11 See PKCS 11 Token Inteface Standard.
     8  *   This implementation has two slots:
     9  *	slot 1 is our generic crypto support. It does not require login.
    10  *   It supports Public Key ops, and all they bulk ciphers and hashes. 
    11  *   It can also support Private Key ops for imported Private keys. It does 
    12  *   not have any token storage.
    13  *	slot 2 is our private key support. It requires a login before use. It
    14  *   can store Private Keys and Certs as token objects. Currently only private
    15  *   keys and their associated Certificates are saved on the token.
    16  *
    17  *   In this implementation, session objects are only visible to the session
    18  *   that created or generated them.
    19  */
    20 #include "seccomon.h"
    21 #include "secitem.h"
    22 #include "pkcs11.h"
    23 #include "pkcs11i.h"
    24 #include "softoken.h"
    25 #include "lowkeyi.h"
    26 #include "blapi.h"
    27 #include "secder.h"
    28 #include "secport.h"
    29 #include "secrng.h"
    30 #include "prtypes.h"
    31 #include "nspr.h"
    32 #include "softkver.h"
    33 #include "secoid.h"
    34 #include "sftkdb.h"
    35 #include "utilpars.h" 
    36 #include "ec.h"
    37 #include "secasn1.h"
    38 #include "secerr.h"
    39 #include "lgglue.h"
    41 PRBool parentForkedAfterC_Initialize;
    43 #ifndef NO_FORK_CHECK
    45 PRBool sftkForkCheckDisabled;
    47 #if defined(CHECK_FORK_PTHREAD) || defined(CHECK_FORK_MIXED)
    48 PRBool forked = PR_FALSE;
    49 #endif
    51 #if defined(CHECK_FORK_GETPID) || defined(CHECK_FORK_MIXED)
    52 #include <unistd.h>
    53 pid_t myPid;
    54 #endif
    56 #ifdef CHECK_FORK_MIXED
    57 #include <sys/systeminfo.h>
    58 PRBool usePthread_atfork;
    59 #endif
    61 #endif
    63 /*
    64  * ******************** Static data *******************************
    65  */
    67 /* The next three strings must be exactly 32 characters long */
    68 static char *manufacturerID      = "Mozilla Foundation              ";
    69 static char manufacturerID_space[33];
    70 static char *libraryDescription  = "NSS Internal Crypto Services    ";
    71 static char libraryDescription_space[33];
    73 /*
    74  * In FIPS mode, we disallow login attempts for 1 second after a login
    75  * failure so that there are at most 60 login attempts per minute.
    76  */
    77 static PRIntervalTime loginWaitTime;
    78 static PRUint32	      minSessionObjectHandle = 1U;
    80 #define __PASTE(x,y)    x##y
    82 /*
    83  * we renamed all our internal functions, get the correct
    84  * definitions for them...
    85  */ 
    86 #undef CK_PKCS11_FUNCTION_INFO
    87 #undef CK_NEED_ARG_LIST
    89 #define CK_EXTERN extern
    90 #define CK_PKCS11_FUNCTION_INFO(func) \
    91 		CK_RV __PASTE(NS,func)
    92 #define CK_NEED_ARG_LIST	1
    94 #include "pkcs11f.h"
    98 /* build the crypto module table */
    99 static const CK_FUNCTION_LIST sftk_funcList = {
   100     { 1, 10 },
   102 #undef CK_PKCS11_FUNCTION_INFO
   103 #undef CK_NEED_ARG_LIST
   105 #define CK_PKCS11_FUNCTION_INFO(func) \
   106 				__PASTE(NS,func),
   107 #include "pkcs11f.h"
   109 };
   111 #undef CK_PKCS11_FUNCTION_INFO
   112 #undef CK_NEED_ARG_LIST
   115 #undef __PASTE
   117 /* List of DES Weak Keys */ 
   118 typedef unsigned char desKey[8];
   119 static const desKey  sftk_desWeakTable[] = {
   120 #ifdef noParity
   121     /* weak */
   122     { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
   123     { 0x1e, 0x1e, 0x1e, 0x1e, 0x0e, 0x0e, 0x0e, 0x0e },
   124     { 0xe0, 0xe0, 0xe0, 0xe0, 0xf0, 0xf0, 0xf0, 0xf0 },
   125     { 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe },
   126     /* semi-weak */
   127     { 0x00, 0xfe, 0x00, 0xfe, 0x00, 0xfe, 0x00, 0xfe },
   128     { 0xfe, 0x00, 0xfe, 0x00, 0x00, 0xfe, 0x00, 0xfe },
   130     { 0x1e, 0xe0, 0x1e, 0xe0, 0x0e, 0xf0, 0x0e, 0xf0 },
   131     { 0xe0, 0x1e, 0xe0, 0x1e, 0xf0, 0x0e, 0xf0, 0x0e },
   133     { 0x00, 0xe0, 0x00, 0xe0, 0x00, 0x0f, 0x00, 0x0f },
   134     { 0xe0, 0x00, 0xe0, 0x00, 0xf0, 0x00, 0xf0, 0x00 },
   136     { 0x1e, 0xfe, 0x1e, 0xfe, 0x0e, 0xfe, 0x0e, 0xfe },
   137     { 0xfe, 0x1e, 0xfe, 0x1e, 0xfe, 0x0e, 0xfe, 0x0e },
   139     { 0x00, 0x1e, 0x00, 0x1e, 0x00, 0x0e, 0x00, 0x0e },
   140     { 0x1e, 0x00, 0x1e, 0x00, 0x0e, 0x00, 0x0e, 0x00 },
   142     { 0xe0, 0xfe, 0xe0, 0xfe, 0xf0, 0xfe, 0xf0, 0xfe },
   143     { 0xfe, 0xe0, 0xfe, 0xe0, 0xfe, 0xf0, 0xfe, 0xf0 },
   144 #else
   145     /* weak */
   146     { 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 },
   147     { 0x1f, 0x1f, 0x1f, 0x1f, 0x0e, 0x0e, 0x0e, 0x0e },
   148     { 0xe0, 0xe0, 0xe0, 0xe0, 0xf1, 0xf1, 0xf1, 0xf1 },
   149     { 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe },
   151     /* semi-weak */
   152     { 0x01, 0xfe, 0x01, 0xfe, 0x01, 0xfe, 0x01, 0xfe },
   153     { 0xfe, 0x01, 0xfe, 0x01, 0xfe, 0x01, 0xfe, 0x01 },
   155     { 0x1f, 0xe0, 0x1f, 0xe0, 0x0e, 0xf1, 0x0e, 0xf1 },
   156     { 0xe0, 0x1f, 0xe0, 0x1f, 0xf1, 0x0e, 0xf1, 0x0e },
   158     { 0x01, 0xe0, 0x01, 0xe0, 0x01, 0xf1, 0x01, 0xf1 },
   159     { 0xe0, 0x01, 0xe0, 0x01, 0xf1, 0x01, 0xf1, 0x01 },
   161     { 0x1f, 0xfe, 0x1f, 0xfe, 0x0e, 0xfe, 0x0e, 0xfe },
   162     { 0xfe, 0x1f, 0xfe, 0x1f, 0xfe, 0x0e, 0xfe, 0x0e },
   164     { 0x01, 0x1f, 0x01, 0x1f, 0x01, 0x0e, 0x01, 0x0e },
   165     { 0x1f, 0x01, 0x1f, 0x01, 0x0e, 0x01, 0x0e, 0x01 },
   167     { 0xe0, 0xfe, 0xe0, 0xfe, 0xf1, 0xfe, 0xf1, 0xfe }, 
   168     { 0xfe, 0xe0, 0xfe, 0xe0, 0xfe, 0xf1, 0xfe, 0xf1 }
   169 #endif
   170 };
   173 static const int sftk_desWeakTableSize = sizeof(sftk_desWeakTable)/
   174 						sizeof(sftk_desWeakTable[0]);
   176 /* DES KEY Parity conversion table. Takes each byte/2 as an index, returns
   177  * that byte with the proper parity bit set */
   178 static const unsigned char parityTable[256] = {
   179 /* Even...0x00,0x02,0x04,0x06,0x08,0x0a,0x0c,0x0e */
   180 /* E */   0x01,0x02,0x04,0x07,0x08,0x0b,0x0d,0x0e,
   181 /* Odd....0x10,0x12,0x14,0x16,0x18,0x1a,0x1c,0x1e */
   182 /* O */   0x10,0x13,0x15,0x16,0x19,0x1a,0x1c,0x1f,
   183 /* Odd....0x20,0x22,0x24,0x26,0x28,0x2a,0x2c,0x2e */
   184 /* O */   0x20,0x23,0x25,0x26,0x29,0x2a,0x2c,0x2f,
   185 /* Even...0x30,0x32,0x34,0x36,0x38,0x3a,0x3c,0x3e */
   186 /* E */   0x31,0x32,0x34,0x37,0x38,0x3b,0x3d,0x3e,
   187 /* Odd....0x40,0x42,0x44,0x46,0x48,0x4a,0x4c,0x4e */
   188 /* O */   0x40,0x43,0x45,0x46,0x49,0x4a,0x4c,0x4f,
   189 /* Even...0x50,0x52,0x54,0x56,0x58,0x5a,0x5c,0x5e */
   190 /* E */   0x51,0x52,0x54,0x57,0x58,0x5b,0x5d,0x5e,
   191 /* Even...0x60,0x62,0x64,0x66,0x68,0x6a,0x6c,0x6e */
   192 /* E */   0x61,0x62,0x64,0x67,0x68,0x6b,0x6d,0x6e,
   193 /* Odd....0x70,0x72,0x74,0x76,0x78,0x7a,0x7c,0x7e */
   194 /* O */   0x70,0x73,0x75,0x76,0x79,0x7a,0x7c,0x7f,
   195 /* Odd....0x80,0x82,0x84,0x86,0x88,0x8a,0x8c,0x8e */
   196 /* O */   0x80,0x83,0x85,0x86,0x89,0x8a,0x8c,0x8f,
   197 /* Even...0x90,0x92,0x94,0x96,0x98,0x9a,0x9c,0x9e */
   198 /* E */   0x91,0x92,0x94,0x97,0x98,0x9b,0x9d,0x9e,
   199 /* Even...0xa0,0xa2,0xa4,0xa6,0xa8,0xaa,0xac,0xae */
   200 /* E */   0xa1,0xa2,0xa4,0xa7,0xa8,0xab,0xad,0xae,
   201 /* Odd....0xb0,0xb2,0xb4,0xb6,0xb8,0xba,0xbc,0xbe */
   202 /* O */   0xb0,0xb3,0xb5,0xb6,0xb9,0xba,0xbc,0xbf,
   203 /* Even...0xc0,0xc2,0xc4,0xc6,0xc8,0xca,0xcc,0xce */
   204 /* E */   0xc1,0xc2,0xc4,0xc7,0xc8,0xcb,0xcd,0xce,
   205 /* Odd....0xd0,0xd2,0xd4,0xd6,0xd8,0xda,0xdc,0xde */
   206 /* O */   0xd0,0xd3,0xd5,0xd6,0xd9,0xda,0xdc,0xdf,
   207 /* Odd....0xe0,0xe2,0xe4,0xe6,0xe8,0xea,0xec,0xee */
   208 /* O */   0xe0,0xe3,0xe5,0xe6,0xe9,0xea,0xec,0xef,
   209 /* Even...0xf0,0xf2,0xf4,0xf6,0xf8,0xfa,0xfc,0xfe */
   210 /* E */   0xf1,0xf2,0xf4,0xf7,0xf8,0xfb,0xfd,0xfe,
   211 };
   213 /* Mechanisms */
   214 struct mechanismList {
   215     CK_MECHANISM_TYPE	type;
   216     CK_MECHANISM_INFO	info;
   217     PRBool		privkey;
   218 };
   220 /*
   221  * the following table includes a complete list of mechanism defined by
   222  * PKCS #11 version 2.01. Those Mechanisms not supported by this PKCS #11
   223  * module are ifdef'ed out.
   224  */
   225 #define CKF_EN_DE		CKF_ENCRYPT      | CKF_DECRYPT
   226 #define CKF_WR_UN		CKF_WRAP         | CKF_UNWRAP
   227 #define CKF_SN_VR		CKF_SIGN         | CKF_VERIFY
   228 #define CKF_SN_RE		CKF_SIGN_RECOVER | CKF_VERIFY_RECOVER
   230 #define CKF_EN_DE_WR_UN 	CKF_EN_DE       | CKF_WR_UN
   231 #define CKF_SN_VR_RE		CKF_SN_VR       | CKF_SN_RE
   232 #define CKF_DUZ_IT_ALL		CKF_EN_DE_WR_UN | CKF_SN_VR_RE
   234 #define CKF_EC_PNU		CKF_EC_FP | CKF_EC_NAMEDCURVE | CKF_EC_UNCOMPRESS
   236 #define CKF_EC_BPNU		CKF_EC_F_2M | CKF_EC_PNU
   238 #define CK_MAX 0xffffffff
   240 static const struct mechanismList mechanisms[] = {
   242      /*
   243       * PKCS #11 Mechanism List.
   244       *
   245       * The first argument is the PKCS #11 Mechanism we support.
   246       * The second argument is Mechanism info structure. It includes:
   247       *    The minimum key size,
   248       *       in bits for RSA, DSA, DH, EC*, KEA, RC2 and RC4 * algs.
   249       *       in bytes for RC5, AES, Camellia, and CAST*
   250       *       ignored for DES*, IDEA and FORTEZZA based
   251       *    The maximum key size,
   252       *       in bits for RSA, DSA, DH, EC*, KEA, RC2 and RC4 * algs.
   253       *       in bytes for RC5, AES, Camellia, and CAST*
   254       *       ignored for DES*, IDEA and FORTEZZA based
   255       *     Flags
   256       *	      What operations are supported by this mechanism.
   257       *  The third argument is a bool which tells if this mechanism is 
   258       *    supported in the database token.
   259       *
   260       */
   262      /* ------------------------- RSA Operations ---------------------------*/
   263      {CKM_RSA_PKCS_KEY_PAIR_GEN,{RSA_MIN_MODULUS_BITS,CK_MAX,
   264 				 CKF_GENERATE_KEY_PAIR},PR_TRUE},
   265      {CKM_RSA_PKCS,             {RSA_MIN_MODULUS_BITS,CK_MAX,
   266 				 CKF_DUZ_IT_ALL},       PR_TRUE},
   267      {CKM_RSA_PKCS_PSS,         {RSA_MIN_MODULUS_BITS,CK_MAX,
   268 				 CKF_SN_VR},            PR_TRUE},
   269      {CKM_RSA_PKCS_OAEP,        {RSA_MIN_MODULUS_BITS,CK_MAX,
   270                                  CKF_EN_DE_WR_UN},       PR_TRUE},
   271 #ifdef SFTK_RSA9796_SUPPORTED
   272      {CKM_RSA_9796,		{RSA_MIN_MODULUS_BITS,CK_MAX,
   273 				 CKF_DUZ_IT_ALL},       PR_TRUE},
   274 #endif
   275      {CKM_RSA_X_509,		{RSA_MIN_MODULUS_BITS,CK_MAX,
   276 				 CKF_DUZ_IT_ALL},       PR_TRUE},
   277      /* -------------- RSA Multipart Signing Operations -------------------- */
   278      {CKM_MD2_RSA_PKCS,		{RSA_MIN_MODULUS_BITS,CK_MAX,
   279 				 CKF_SN_VR}, 	PR_TRUE},
   280      {CKM_MD5_RSA_PKCS,		{RSA_MIN_MODULUS_BITS,CK_MAX,
   281 				 CKF_SN_VR}, 	PR_TRUE},
   282      {CKM_SHA1_RSA_PKCS,	{RSA_MIN_MODULUS_BITS,CK_MAX,
   283 				 CKF_SN_VR}, 	PR_TRUE},
   284      {CKM_SHA224_RSA_PKCS,	{RSA_MIN_MODULUS_BITS,CK_MAX,
   285 				 CKF_SN_VR}, 	PR_TRUE},
   286      {CKM_SHA256_RSA_PKCS,	{RSA_MIN_MODULUS_BITS,CK_MAX,
   287 				 CKF_SN_VR}, 	PR_TRUE},
   288      {CKM_SHA384_RSA_PKCS,	{RSA_MIN_MODULUS_BITS,CK_MAX,
   289 				 CKF_SN_VR}, 	PR_TRUE},
   290      {CKM_SHA512_RSA_PKCS,	{RSA_MIN_MODULUS_BITS,CK_MAX,
   291 				 CKF_SN_VR}, 	PR_TRUE},
   292      /* ------------------------- DSA Operations --------------------------- */
   293      {CKM_DSA_KEY_PAIR_GEN,	{DSA_MIN_P_BITS, DSA_MAX_P_BITS,
   294 				 CKF_GENERATE_KEY_PAIR}, PR_TRUE},
   295      {CKM_DSA,			{DSA_MIN_P_BITS, DSA_MAX_P_BITS, 
   296 				 CKF_SN_VR},              PR_TRUE},
   297      {CKM_DSA_PARAMETER_GEN,	{DSA_MIN_P_BITS, DSA_MAX_P_BITS, 
   298 				 CKF_GENERATE},           PR_TRUE},
   299      {CKM_DSA_SHA1,		{DSA_MIN_P_BITS, DSA_MAX_P_BITS,
   300 				 CKF_SN_VR},              PR_TRUE},
   301      /* -------------------- Diffie Hellman Operations --------------------- */
   302      /* no diffie hellman yet */
   303      {CKM_DH_PKCS_KEY_PAIR_GEN,	{DH_MIN_P_BITS, DH_MAX_P_BITS, 
   304 				 CKF_GENERATE_KEY_PAIR}, PR_TRUE}, 
   305      {CKM_DH_PKCS_DERIVE,	{DH_MIN_P_BITS, DH_MAX_P_BITS,
   306 				 CKF_DERIVE}, 	PR_TRUE}, 
   307 #ifndef NSS_DISABLE_ECC
   308      /* -------------------- Elliptic Curve Operations --------------------- */
   309      {CKM_EC_KEY_PAIR_GEN,      {EC_MIN_KEY_BITS, EC_MAX_KEY_BITS,
   310 				 CKF_GENERATE_KEY_PAIR|CKF_EC_BPNU}, PR_TRUE}, 
   311      {CKM_ECDH1_DERIVE,         {EC_MIN_KEY_BITS, EC_MAX_KEY_BITS,
   312 				 CKF_DERIVE|CKF_EC_BPNU}, PR_TRUE}, 
   313      {CKM_ECDSA,                {EC_MIN_KEY_BITS, EC_MAX_KEY_BITS,
   314 				 CKF_SN_VR|CKF_EC_BPNU}, PR_TRUE}, 
   315      {CKM_ECDSA_SHA1,           {EC_MIN_KEY_BITS, EC_MAX_KEY_BITS,
   316 				 CKF_SN_VR|CKF_EC_BPNU}, PR_TRUE}, 
   317 #endif /* NSS_DISABLE_ECC */
   318      /* ------------------------- RC2 Operations --------------------------- */
   319      {CKM_RC2_KEY_GEN,		{1, 128, CKF_GENERATE},		PR_TRUE},
   320      {CKM_RC2_ECB,		{1, 128, CKF_EN_DE_WR_UN},	PR_TRUE},
   321      {CKM_RC2_CBC,		{1, 128, CKF_EN_DE_WR_UN},	PR_TRUE},
   322      {CKM_RC2_MAC,		{1, 128, CKF_SN_VR},		PR_TRUE},
   323      {CKM_RC2_MAC_GENERAL,	{1, 128, CKF_SN_VR},		PR_TRUE},
   324      {CKM_RC2_CBC_PAD,		{1, 128, CKF_EN_DE_WR_UN},	PR_TRUE},
   325      /* ------------------------- RC4 Operations --------------------------- */
   326      {CKM_RC4_KEY_GEN,		{1, 256, CKF_GENERATE},		PR_FALSE},
   327      {CKM_RC4,			{1, 256, CKF_EN_DE_WR_UN},	PR_FALSE},
   328      /* ------------------------- DES Operations --------------------------- */
   329      {CKM_DES_KEY_GEN,		{ 8,  8, CKF_GENERATE},		PR_TRUE},
   330      {CKM_DES_ECB,		{ 8,  8, CKF_EN_DE_WR_UN},	PR_TRUE},
   331      {CKM_DES_CBC,		{ 8,  8, CKF_EN_DE_WR_UN},	PR_TRUE},
   332      {CKM_DES_MAC,		{ 8,  8, CKF_SN_VR},		PR_TRUE},
   333      {CKM_DES_MAC_GENERAL,	{ 8,  8, CKF_SN_VR},		PR_TRUE},
   334      {CKM_DES_CBC_PAD,		{ 8,  8, CKF_EN_DE_WR_UN},	PR_TRUE},
   335      {CKM_DES2_KEY_GEN,		{24, 24, CKF_GENERATE},		PR_TRUE},
   336      {CKM_DES3_KEY_GEN,		{24, 24, CKF_GENERATE},		PR_TRUE },
   337      {CKM_DES3_ECB,		{24, 24, CKF_EN_DE_WR_UN},	PR_TRUE },
   338      {CKM_DES3_CBC,		{24, 24, CKF_EN_DE_WR_UN},	PR_TRUE },
   339      {CKM_DES3_MAC,		{24, 24, CKF_SN_VR},		PR_TRUE },
   340      {CKM_DES3_MAC_GENERAL,	{24, 24, CKF_SN_VR},		PR_TRUE },
   341      {CKM_DES3_CBC_PAD,		{24, 24, CKF_EN_DE_WR_UN},	PR_TRUE },
   342      /* ------------------------- CDMF Operations --------------------------- */
   343      {CKM_CDMF_KEY_GEN,		{8,  8, CKF_GENERATE},		PR_TRUE},
   344      {CKM_CDMF_ECB,		{8,  8, CKF_EN_DE_WR_UN},	PR_TRUE},
   345      {CKM_CDMF_CBC,		{8,  8, CKF_EN_DE_WR_UN},	PR_TRUE},
   346      {CKM_CDMF_MAC,		{8,  8, CKF_SN_VR},		PR_TRUE},
   347      {CKM_CDMF_MAC_GENERAL,	{8,  8, CKF_SN_VR},		PR_TRUE},
   348      {CKM_CDMF_CBC_PAD,		{8,  8, CKF_EN_DE_WR_UN},	PR_TRUE},
   349      /* ------------------------- AES Operations --------------------------- */
   350      {CKM_AES_KEY_GEN,		{16, 32, CKF_GENERATE},		PR_TRUE},
   351      {CKM_AES_ECB,		{16, 32, CKF_EN_DE_WR_UN},	PR_TRUE},
   352      {CKM_AES_CBC,		{16, 32, CKF_EN_DE_WR_UN},	PR_TRUE},
   353      {CKM_AES_MAC,		{16, 32, CKF_SN_VR},		PR_TRUE},
   354      {CKM_AES_MAC_GENERAL,	{16, 32, CKF_SN_VR},		PR_TRUE},
   355      {CKM_AES_CBC_PAD,		{16, 32, CKF_EN_DE_WR_UN},	PR_TRUE},
   356      {CKM_AES_CTS,		{16, 32, CKF_EN_DE},		PR_TRUE},
   357      {CKM_AES_CTR,		{16, 32, CKF_EN_DE},		PR_TRUE},
   358      {CKM_AES_GCM,		{16, 32, CKF_EN_DE},		PR_TRUE},
   359      /* ------------------------- Camellia Operations --------------------- */
   360      {CKM_CAMELLIA_KEY_GEN,	{16, 32, CKF_GENERATE},         PR_TRUE},
   361      {CKM_CAMELLIA_ECB,  	{16, 32, CKF_EN_DE_WR_UN},      PR_TRUE},
   362      {CKM_CAMELLIA_CBC, 	{16, 32, CKF_EN_DE_WR_UN},      PR_TRUE},
   363      {CKM_CAMELLIA_MAC, 	{16, 32, CKF_SN_VR},            PR_TRUE},
   364      {CKM_CAMELLIA_MAC_GENERAL,	{16, 32, CKF_SN_VR},            PR_TRUE},
   365      {CKM_CAMELLIA_CBC_PAD,	{16, 32, CKF_EN_DE_WR_UN},      PR_TRUE},
   366      /* ------------------------- SEED Operations --------------------------- */
   367      {CKM_SEED_KEY_GEN,		{16, 16, CKF_GENERATE},		PR_TRUE},
   368      {CKM_SEED_ECB,		{16, 16, CKF_EN_DE_WR_UN},	PR_TRUE},
   369      {CKM_SEED_CBC,		{16, 16, CKF_EN_DE_WR_UN},	PR_TRUE},
   370      {CKM_SEED_MAC,		{16, 16, CKF_SN_VR},		PR_TRUE},
   371      {CKM_SEED_MAC_GENERAL,	{16, 16, CKF_SN_VR},		PR_TRUE},
   372      {CKM_SEED_CBC_PAD,		{16, 16, CKF_EN_DE_WR_UN},	PR_TRUE},
   373      /* ------------------------- Hashing Operations ----------------------- */
   374      {CKM_MD2,			{0,   0, CKF_DIGEST},		PR_FALSE},
   375      {CKM_MD2_HMAC,		{1, 128, CKF_SN_VR},		PR_TRUE},
   376      {CKM_MD2_HMAC_GENERAL,	{1, 128, CKF_SN_VR},		PR_TRUE},
   377      {CKM_MD5,			{0,   0, CKF_DIGEST},		PR_FALSE},
   378      {CKM_MD5_HMAC,		{1, 128, CKF_SN_VR},		PR_TRUE},
   379      {CKM_MD5_HMAC_GENERAL,	{1, 128, CKF_SN_VR},		PR_TRUE},
   380      {CKM_SHA_1,		{0,   0, CKF_DIGEST},		PR_FALSE},
   381      {CKM_SHA_1_HMAC,		{1, 128, CKF_SN_VR},		PR_TRUE},
   382      {CKM_SHA_1_HMAC_GENERAL,	{1, 128, CKF_SN_VR},		PR_TRUE},
   383      {CKM_SHA224,		{0,   0, CKF_DIGEST},		PR_FALSE},
   384      {CKM_SHA224_HMAC,		{1, 128, CKF_SN_VR},		PR_TRUE},
   385      {CKM_SHA224_HMAC_GENERAL,	{1, 128, CKF_SN_VR},		PR_TRUE},
   386      {CKM_SHA256,		{0,   0, CKF_DIGEST},		PR_FALSE},
   387      {CKM_SHA256_HMAC,		{1, 128, CKF_SN_VR},		PR_TRUE},
   388      {CKM_SHA256_HMAC_GENERAL,	{1, 128, CKF_SN_VR},		PR_TRUE},
   389      {CKM_SHA384,		{0,   0, CKF_DIGEST},		PR_FALSE},
   390      {CKM_SHA384_HMAC,		{1, 128, CKF_SN_VR},		PR_TRUE},
   391      {CKM_SHA384_HMAC_GENERAL,	{1, 128, CKF_SN_VR},		PR_TRUE},
   392      {CKM_SHA512,		{0,   0, CKF_DIGEST},		PR_FALSE},
   393      {CKM_SHA512_HMAC,		{1, 128, CKF_SN_VR},		PR_TRUE},
   394      {CKM_SHA512_HMAC_GENERAL,	{1, 128, CKF_SN_VR},		PR_TRUE},
   395      {CKM_TLS_PRF_GENERAL,	{0, 512, CKF_SN_VR},		PR_FALSE},
   396      {CKM_NSS_TLS_PRF_GENERAL_SHA256,
   397 				{0, 512, CKF_SN_VR},		PR_FALSE},
   398      /* ------------------------- HKDF Operations -------------------------- */
   399      {CKM_NSS_HKDF_SHA1,        {1, 128, CKF_DERIVE},           PR_TRUE},
   400      {CKM_NSS_HKDF_SHA256,      {1, 128, CKF_DERIVE},           PR_TRUE},
   401      {CKM_NSS_HKDF_SHA384,      {1, 128, CKF_DERIVE},           PR_TRUE},
   402      {CKM_NSS_HKDF_SHA512,      {1, 128, CKF_DERIVE},           PR_TRUE},
   403      /* ------------------------- CAST Operations --------------------------- */
   404 #ifdef NSS_SOFTOKEN_DOES_CAST
   405      /* Cast operations are not supported ( yet? ) */
   406      {CKM_CAST_KEY_GEN,		{1,  8, CKF_GENERATE},		PR_TRUE}, 
   407      {CKM_CAST_ECB,		{1,  8, CKF_EN_DE_WR_UN},	PR_TRUE}, 
   408      {CKM_CAST_CBC,		{1,  8, CKF_EN_DE_WR_UN},	PR_TRUE}, 
   409      {CKM_CAST_MAC,		{1,  8, CKF_SN_VR},		PR_TRUE}, 
   410      {CKM_CAST_MAC_GENERAL,	{1,  8, CKF_SN_VR},		PR_TRUE}, 
   411      {CKM_CAST_CBC_PAD,		{1,  8, CKF_EN_DE_WR_UN},	PR_TRUE}, 
   412      {CKM_CAST3_KEY_GEN,	{1, 16, CKF_GENERATE},		PR_TRUE}, 
   413      {CKM_CAST3_ECB,		{1, 16, CKF_EN_DE_WR_UN},	PR_TRUE}, 
   414      {CKM_CAST3_CBC,		{1, 16, CKF_EN_DE_WR_UN},	PR_TRUE}, 
   415      {CKM_CAST3_MAC,		{1, 16, CKF_SN_VR},		PR_TRUE}, 
   416      {CKM_CAST3_MAC_GENERAL,	{1, 16, CKF_SN_VR},		PR_TRUE}, 
   417      {CKM_CAST3_CBC_PAD,	{1, 16, CKF_EN_DE_WR_UN},	PR_TRUE}, 
   418      {CKM_CAST5_KEY_GEN,	{1, 16, CKF_GENERATE},		PR_TRUE}, 
   419      {CKM_CAST5_ECB,		{1, 16, CKF_EN_DE_WR_UN},	PR_TRUE}, 
   420      {CKM_CAST5_CBC,		{1, 16, CKF_EN_DE_WR_UN},	PR_TRUE}, 
   421      {CKM_CAST5_MAC,		{1, 16, CKF_SN_VR},		PR_TRUE}, 
   422      {CKM_CAST5_MAC_GENERAL,	{1, 16, CKF_SN_VR},		PR_TRUE}, 
   423      {CKM_CAST5_CBC_PAD,	{1, 16, CKF_EN_DE_WR_UN},	PR_TRUE}, 
   424 #endif
   425 #if NSS_SOFTOKEN_DOES_RC5
   426      /* ------------------------- RC5 Operations --------------------------- */
   427      {CKM_RC5_KEY_GEN,		{1, 32, CKF_GENERATE},          PR_TRUE},
   428      {CKM_RC5_ECB,		{1, 32, CKF_EN_DE_WR_UN},	PR_TRUE},
   429      {CKM_RC5_CBC,		{1, 32, CKF_EN_DE_WR_UN},	PR_TRUE},
   430      {CKM_RC5_MAC,		{1, 32, CKF_SN_VR},  		PR_TRUE},
   431      {CKM_RC5_MAC_GENERAL,	{1, 32, CKF_SN_VR},  		PR_TRUE},
   432      {CKM_RC5_CBC_PAD,		{1, 32, CKF_EN_DE_WR_UN}, 	PR_TRUE},
   433 #endif
   434 #ifdef NSS_SOFTOKEN_DOES_IDEA
   435      /* ------------------------- IDEA Operations -------------------------- */
   436      {CKM_IDEA_KEY_GEN,		{16, 16, CKF_GENERATE}, 	PR_TRUE}, 
   437      {CKM_IDEA_ECB,		{16, 16, CKF_EN_DE_WR_UN},	PR_TRUE}, 
   438      {CKM_IDEA_CBC,		{16, 16, CKF_EN_DE_WR_UN},	PR_TRUE}, 
   439      {CKM_IDEA_MAC,		{16, 16, CKF_SN_VR},		PR_TRUE}, 
   440      {CKM_IDEA_MAC_GENERAL,	{16, 16, CKF_SN_VR},		PR_TRUE}, 
   441      {CKM_IDEA_CBC_PAD,		{16, 16, CKF_EN_DE_WR_UN}, 	PR_TRUE}, 
   442 #endif
   443      /* --------------------- Secret Key Operations ------------------------ */
   444      {CKM_GENERIC_SECRET_KEY_GEN,	{1, 32, CKF_GENERATE}, PR_TRUE}, 
   445      {CKM_CONCATENATE_BASE_AND_KEY,	{1, 32, CKF_GENERATE}, PR_FALSE}, 
   446      {CKM_CONCATENATE_BASE_AND_DATA,	{1, 32, CKF_GENERATE}, PR_FALSE}, 
   447      {CKM_CONCATENATE_DATA_AND_BASE,	{1, 32, CKF_GENERATE}, PR_FALSE}, 
   448      {CKM_XOR_BASE_AND_DATA,		{1, 32, CKF_GENERATE}, PR_FALSE}, 
   449      {CKM_EXTRACT_KEY_FROM_KEY,		{1, 32, CKF_DERIVE},   PR_FALSE}, 
   450      /* ---------------------- SSL Key Derivations ------------------------- */
   451      {CKM_SSL3_PRE_MASTER_KEY_GEN,	{48, 48, CKF_GENERATE}, PR_FALSE}, 
   452      {CKM_SSL3_MASTER_KEY_DERIVE,	{48, 48, CKF_DERIVE},   PR_FALSE}, 
   453      {CKM_SSL3_MASTER_KEY_DERIVE_DH,	{8, 128, CKF_DERIVE},   PR_FALSE}, 
   454      {CKM_SSL3_KEY_AND_MAC_DERIVE,	{48, 48, CKF_DERIVE},   PR_FALSE}, 
   455      {CKM_SSL3_MD5_MAC,			{ 0, 16, CKF_DERIVE},   PR_FALSE}, 
   456      {CKM_SSL3_SHA1_MAC,		{ 0, 20, CKF_DERIVE},   PR_FALSE}, 
   457      {CKM_MD5_KEY_DERIVATION,		{ 0, 16, CKF_DERIVE},   PR_FALSE}, 
   458      {CKM_MD2_KEY_DERIVATION,		{ 0, 16, CKF_DERIVE},   PR_FALSE}, 
   459      {CKM_SHA1_KEY_DERIVATION,		{ 0, 20, CKF_DERIVE},   PR_FALSE}, 
   460      {CKM_SHA224_KEY_DERIVATION,	{ 0, 28, CKF_DERIVE},   PR_FALSE}, 
   461      {CKM_SHA256_KEY_DERIVATION,	{ 0, 32, CKF_DERIVE},   PR_FALSE}, 
   462      {CKM_SHA384_KEY_DERIVATION,	{ 0, 48, CKF_DERIVE},   PR_FALSE}, 
   463      {CKM_SHA512_KEY_DERIVATION,	{ 0, 64, CKF_DERIVE},   PR_FALSE}, 
   464      {CKM_TLS_MASTER_KEY_DERIVE,	{48, 48, CKF_DERIVE},   PR_FALSE}, 
   465      {CKM_NSS_TLS_MASTER_KEY_DERIVE_SHA256,
   466 					{48, 48, CKF_DERIVE},	PR_FALSE},
   467      {CKM_TLS_MASTER_KEY_DERIVE_DH,	{8, 128, CKF_DERIVE},   PR_FALSE}, 
   468      {CKM_NSS_TLS_MASTER_KEY_DERIVE_DH_SHA256,
   469 					{8, 128, CKF_DERIVE},	PR_FALSE},
   470      {CKM_TLS_KEY_AND_MAC_DERIVE,	{48, 48, CKF_DERIVE},   PR_FALSE}, 
   471      {CKM_NSS_TLS_KEY_AND_MAC_DERIVE_SHA256,
   472 					{48, 48, CKF_DERIVE},	PR_FALSE},
   473      /* ---------------------- PBE Key Derivations  ------------------------ */
   474      {CKM_PBE_MD2_DES_CBC,		{8, 8, CKF_DERIVE},   PR_TRUE},
   475      {CKM_PBE_MD5_DES_CBC,		{8, 8, CKF_DERIVE},   PR_TRUE},
   476      /* ------------------ NETSCAPE PBE Key Derivations  ------------------- */
   477      {CKM_NETSCAPE_PBE_SHA1_DES_CBC,	     { 8, 8, CKF_GENERATE}, PR_TRUE},
   478      {CKM_NETSCAPE_PBE_SHA1_FAULTY_3DES_CBC, {24,24, CKF_GENERATE}, PR_TRUE},
   479      {CKM_PBE_SHA1_DES3_EDE_CBC,	     {24,24, CKF_GENERATE}, PR_TRUE},
   480      {CKM_PBE_SHA1_DES2_EDE_CBC,	     {24,24, CKF_GENERATE}, PR_TRUE},
   481      {CKM_PBE_SHA1_RC2_40_CBC,		     {40,40, CKF_GENERATE}, PR_TRUE},
   482      {CKM_PBE_SHA1_RC2_128_CBC,		     {128,128, CKF_GENERATE}, PR_TRUE},
   483      {CKM_PBE_SHA1_RC4_40,		     {40,40, CKF_GENERATE}, PR_TRUE},
   484      {CKM_PBE_SHA1_RC4_128,		     {128,128, CKF_GENERATE}, PR_TRUE},
   485      {CKM_PBA_SHA1_WITH_SHA1_HMAC,	     {20,20, CKF_GENERATE}, PR_TRUE},
   486      {CKM_PKCS5_PBKD2,   		     {1,256, CKF_GENERATE}, PR_TRUE},
   487      {CKM_NETSCAPE_PBE_SHA1_HMAC_KEY_GEN,    {20,20, CKF_GENERATE}, PR_TRUE},
   488      {CKM_NETSCAPE_PBE_MD5_HMAC_KEY_GEN,     {16,16, CKF_GENERATE}, PR_TRUE},
   489      {CKM_NETSCAPE_PBE_MD2_HMAC_KEY_GEN,     {16,16, CKF_GENERATE}, PR_TRUE},
   490      /* ------------------ AES Key Wrap (also encrypt)  ------------------- */
   491      {CKM_NETSCAPE_AES_KEY_WRAP,	{16, 32, CKF_EN_DE_WR_UN},  PR_TRUE},
   492      {CKM_NETSCAPE_AES_KEY_WRAP_PAD,	{16, 32, CKF_EN_DE_WR_UN},  PR_TRUE},
   493      /* --------------------------- J-PAKE -------------------------------- */
   494      {CKM_NSS_JPAKE_ROUND1_SHA1,        {0, 0, CKF_GENERATE}, PR_TRUE},
   495      {CKM_NSS_JPAKE_ROUND1_SHA256,      {0, 0, CKF_GENERATE}, PR_TRUE},
   496      {CKM_NSS_JPAKE_ROUND1_SHA384,      {0, 0, CKF_GENERATE}, PR_TRUE},
   497      {CKM_NSS_JPAKE_ROUND1_SHA512,      {0, 0, CKF_GENERATE}, PR_TRUE},
   498      {CKM_NSS_JPAKE_ROUND2_SHA1,        {0, 0, CKF_DERIVE}, PR_TRUE},
   499      {CKM_NSS_JPAKE_ROUND2_SHA256,      {0, 0, CKF_DERIVE}, PR_TRUE},
   500      {CKM_NSS_JPAKE_ROUND2_SHA384,      {0, 0, CKF_DERIVE}, PR_TRUE},
   501      {CKM_NSS_JPAKE_ROUND2_SHA512,      {0, 0, CKF_DERIVE}, PR_TRUE},
   502      {CKM_NSS_JPAKE_FINAL_SHA1,         {0, 0, CKF_DERIVE}, PR_TRUE},
   503      {CKM_NSS_JPAKE_FINAL_SHA256,       {0, 0, CKF_DERIVE}, PR_TRUE},
   504      {CKM_NSS_JPAKE_FINAL_SHA384,       {0, 0, CKF_DERIVE}, PR_TRUE},
   505      {CKM_NSS_JPAKE_FINAL_SHA512,       {0, 0, CKF_DERIVE}, PR_TRUE},
   506      /* -------------------- Constant Time TLS MACs ----------------------- */
   507      {CKM_NSS_HMAC_CONSTANT_TIME,       {0, 0, CKF_DIGEST}, PR_TRUE},
   508      {CKM_NSS_SSL3_MAC_CONSTANT_TIME,   {0, 0, CKF_DIGEST}, PR_TRUE}
   509 };
   510 static const CK_ULONG mechanismCount = sizeof(mechanisms)/sizeof(mechanisms[0]);
   512 /* sigh global so fipstokn can read it */
   513 PRBool nsc_init = PR_FALSE;
   515 #if defined(CHECK_FORK_PTHREAD) || defined(CHECK_FORK_MIXED)
   517 #include <pthread.h>
   519 static void ForkedChild(void)
   520 {
   521     if (nsc_init || nsf_init) {
   522         forked = PR_TRUE;
   523     }
   524 }
   526 #endif
   528 static char *
   529 sftk_setStringName(const char *inString, char *buffer, int buffer_length, 		PRBool nullTerminate)
   530 {
   531     int full_length, string_length;
   533     full_length = nullTerminate ? buffer_length -1 : buffer_length;
   534     string_length = PORT_Strlen(inString);
   535     /* 
   536      *  shorten the string, respecting utf8 encoding
   537      *  to do so, we work backward from the end 
   538      *  bytes looking from the end are either:
   539      *    - ascii [0x00,0x7f]
   540      *    - the [2-n]th byte of a multibyte sequence 
   541      *        [0x3F,0xBF], i.e, most significant 2 bits are '10'
   542      *    - the first byte of a multibyte sequence [0xC0,0xFD],
   543      *        i.e, most significant 2 bits are '11'
   544      *
   545      *    When the string is too long, we lop off any trailing '10' bytes,
   546      *  if any. When these are all eliminated we lop off
   547      *  one additional byte. Thus if we lopped any '10'
   548      *  we'll be lopping a '11' byte (the first byte of the multibyte sequence),
   549      *  otherwise we're lopping off an ascii character.
   550      *
   551      *    To test for '10' bytes, we first AND it with 
   552      *  11000000 (0xc0) so that we get 10000000 (0x80) if and only if
   553      *  the byte starts with 10. We test for equality.
   554      */
   555     while ( string_length > full_length ) {
   556 	/* need to shorten */
   557 	while ( string_length > 0 && 
   558 	      ((inString[string_length-1]&(char)0xc0) == (char)0x80)) {
   559 	    /* lop off '10' byte */
   560 	    string_length--;
   561 	}
   562 	/* 
   563 	 * test string_length in case bad data is received
   564 	 * and string consisted of all '10' bytes,
   565 	 * avoiding any infinite loop
   566          */
   567 	if ( string_length ) {
   568 	    /* remove either '11' byte or an asci byte */
   569 	    string_length--;
   570 	}
   571     }
   572     PORT_Memset(buffer,' ',full_length);
   573     if (nullTerminate) {
   574 	buffer[full_length] = 0;
   575     }
   576     PORT_Memcpy(buffer,inString,string_length);
   577     return buffer;
   578 }
   579 /*
   580  * Configuration utils
   581  */
   582 static CK_RV
   583 sftk_configure(const char *man, const char *libdes)
   584 {
   586     /* make sure the internationalization was done correctly... */
   587     if (man) {
   588 	manufacturerID = sftk_setStringName(man,manufacturerID_space,
   589 					sizeof(manufacturerID_space), PR_TRUE);
   590     }
   591     if (libdes) {
   592 	libraryDescription = sftk_setStringName(libdes,
   593 		libraryDescription_space, sizeof(libraryDescription_space), 
   594 		PR_TRUE);
   595     }
   597     return CKR_OK;
   598 }
   600 /*
   601  * ******************** Password Utilities *******************************
   602  */
   604 /*
   605  * see if the key DB password is enabled
   606  */
   607 static PRBool
   608 sftk_hasNullPassword(SFTKSlot *slot, SFTKDBHandle *keydb)
   609 {
   610     PRBool pwenabled;
   612     pwenabled = PR_FALSE;
   613     if (sftkdb_HasPasswordSet(keydb) == SECSuccess) {
   614 	PRBool tokenRemoved = PR_FALSE;
   615     	SECStatus rv = sftkdb_CheckPassword(keydb, "", &tokenRemoved);
   616 	if (tokenRemoved) {
   617 	    sftk_CloseAllSessions(slot, PR_FALSE);
   618 	}
   619 	return (rv  == SECSuccess);
   620     }
   622     return pwenabled;
   623 }
   625 /*
   626  * ******************** Object Creation Utilities ***************************
   627  */
   630 /* Make sure a given attribute exists. If it doesn't, initialize it to
   631  * value and len
   632  */
   633 CK_RV
   634 sftk_defaultAttribute(SFTKObject *object,CK_ATTRIBUTE_TYPE type,
   635 					const void *value, unsigned int len)
   636 {
   637     if ( !sftk_hasAttribute(object, type)) {
   638 	return sftk_AddAttributeType(object,type,value,len);
   639     }
   640     return CKR_OK;
   641 }
   643 /*
   644  * check the consistancy and initialize a Data Object 
   645  */
   646 static CK_RV
   647 sftk_handleDataObject(SFTKSession *session,SFTKObject *object)
   648 {
   649     CK_RV crv;
   651     /* first reject private and token data objects */
   652     if (sftk_isTrue(object,CKA_PRIVATE) || sftk_isTrue(object,CKA_TOKEN)) {
   653 	return CKR_ATTRIBUTE_VALUE_INVALID;
   654     }
   656     /* now just verify the required date fields */
   657     crv = sftk_defaultAttribute(object,CKA_APPLICATION,NULL,0);
   658     if (crv != CKR_OK) return crv;
   659     crv = sftk_defaultAttribute(object,CKA_VALUE,NULL,0);
   660     if (crv != CKR_OK) return crv;
   662     return CKR_OK;
   663 }
   665 /*
   666  * check the consistancy and initialize a Certificate Object 
   667  */
   668 static CK_RV
   669 sftk_handleCertObject(SFTKSession *session,SFTKObject *object)
   670 {
   671     CK_CERTIFICATE_TYPE type;
   672     SFTKAttribute *attribute;
   673     CK_RV crv;
   675     /* certificates must have a type */
   676     if ( !sftk_hasAttribute(object,CKA_CERTIFICATE_TYPE) ) {
   677 	return CKR_TEMPLATE_INCOMPLETE;
   678     }
   680     /* we can't store any certs private */
   681     if (sftk_isTrue(object,CKA_PRIVATE)) {
   682 	return CKR_ATTRIBUTE_VALUE_INVALID;
   683     }
   685     /* We only support X.509 Certs for now */
   686     attribute = sftk_FindAttribute(object,CKA_CERTIFICATE_TYPE);
   687     if (attribute == NULL) return CKR_TEMPLATE_INCOMPLETE;
   688     type = *(CK_CERTIFICATE_TYPE *)attribute->attrib.pValue;
   689     sftk_FreeAttribute(attribute);
   691     if (type != CKC_X_509) {
   692 	return CKR_ATTRIBUTE_VALUE_INVALID;
   693     }
   695     /* X.509 Certificate */
   697     /* make sure we have a cert */
   698     if ( !sftk_hasAttribute(object,CKA_VALUE) ) {
   699 	return CKR_TEMPLATE_INCOMPLETE;
   700     }
   702     /* in PKCS #11, Subject is a required field */
   703     if ( !sftk_hasAttribute(object,CKA_SUBJECT) ) {
   704 	return CKR_TEMPLATE_INCOMPLETE;
   705     }
   707     /* in PKCS #11, Issuer is a required field */
   708     if ( !sftk_hasAttribute(object,CKA_ISSUER) ) {
   709 	return CKR_TEMPLATE_INCOMPLETE;
   710     }
   712     /* in PKCS #11, Serial is a required field */
   713     if ( !sftk_hasAttribute(object,CKA_SERIAL_NUMBER) ) {
   714 	return CKR_TEMPLATE_INCOMPLETE;
   715     }
   717     /* add it to the object */
   718     object->objectInfo = NULL;
   719     object->infoFree = (SFTKFree) NULL;
   721     /* now just verify the required date fields */
   722     crv = sftk_defaultAttribute(object, CKA_ID, NULL, 0);
   723     if (crv != CKR_OK) { return crv; }
   725     if (sftk_isTrue(object,CKA_TOKEN)) {
   726 	SFTKSlot *slot = session->slot;
   727 	SFTKDBHandle *certHandle = sftk_getCertDB(slot);
   729 	if (certHandle == NULL) {
   730 	    return CKR_TOKEN_WRITE_PROTECTED;
   731 	}
   733 	crv = sftkdb_write(certHandle, object, &object->handle);
   734 	sftk_freeDB(certHandle);
   735 	return crv;
   736     }
   738     return CKR_OK;
   739 }
   741 /*
   742  * check the consistancy and initialize a Trust Object 
   743  */
   744 static CK_RV
   745 sftk_handleTrustObject(SFTKSession *session,SFTKObject *object)
   746 {
   747     /* we can't store any certs private */
   748     if (sftk_isTrue(object,CKA_PRIVATE)) {
   749 	return CKR_ATTRIBUTE_VALUE_INVALID;
   750     }
   752     /* certificates must have a type */
   753     if ( !sftk_hasAttribute(object,CKA_ISSUER) ) {
   754 	return CKR_TEMPLATE_INCOMPLETE;
   755     }
   756     if ( !sftk_hasAttribute(object,CKA_SERIAL_NUMBER) ) {
   757 	return CKR_TEMPLATE_INCOMPLETE;
   758     }
   759     if ( !sftk_hasAttribute(object,CKA_CERT_SHA1_HASH) ) {
   760 	return CKR_TEMPLATE_INCOMPLETE;
   761     }
   762     if ( !sftk_hasAttribute(object,CKA_CERT_MD5_HASH) ) {
   763 	return CKR_TEMPLATE_INCOMPLETE;
   764     }
   766     if (sftk_isTrue(object,CKA_TOKEN)) {
   767 	SFTKSlot *slot = session->slot;
   768 	SFTKDBHandle *certHandle = sftk_getCertDB(slot);
   769 	CK_RV crv;
   771 	if (certHandle == NULL) {
   772 	    return CKR_TOKEN_WRITE_PROTECTED;
   773 	}
   775 	crv = sftkdb_write(certHandle, object, &object->handle);
   776 	sftk_freeDB(certHandle);
   777 	return crv;
   778     }
   780     return CKR_OK;
   781 }
   783 /*
   784  * check the consistancy and initialize a Trust Object 
   785  */
   786 static CK_RV
   787 sftk_handleSMimeObject(SFTKSession *session,SFTKObject *object)
   788 {
   790     /* we can't store any certs private */
   791     if (sftk_isTrue(object,CKA_PRIVATE)) {
   792 	return CKR_ATTRIBUTE_VALUE_INVALID;
   793     }
   795     /* certificates must have a type */
   796     if ( !sftk_hasAttribute(object,CKA_SUBJECT) ) {
   797 	return CKR_TEMPLATE_INCOMPLETE;
   798     }
   799     if ( !sftk_hasAttribute(object,CKA_NETSCAPE_EMAIL) ) {
   800 	return CKR_TEMPLATE_INCOMPLETE;
   801     }
   803     if (sftk_isTrue(object,CKA_TOKEN)) {
   804 	SFTKSlot *slot = session->slot;
   805 	SFTKDBHandle *certHandle;
   806 	CK_RV crv;
   808 	PORT_Assert(slot);
   809 	if (slot == NULL) {
   810 	    return CKR_SESSION_HANDLE_INVALID;
   811 	}
   813 	certHandle = sftk_getCertDB(slot);
   814 	if (certHandle == NULL) {
   815 	    return CKR_TOKEN_WRITE_PROTECTED;
   816 	}
   818 	crv = sftkdb_write(certHandle, object, &object->handle);
   819 	sftk_freeDB(certHandle);
   820 	return crv;
   821     }
   823     return CKR_OK;
   824 }
   826 /*
   827  * check the consistancy and initialize a Trust Object 
   828  */
   829 static CK_RV
   830 sftk_handleCrlObject(SFTKSession *session,SFTKObject *object)
   831 {
   833     /* we can't store any certs private */
   834     if (sftk_isTrue(object,CKA_PRIVATE)) {
   835 	return CKR_ATTRIBUTE_VALUE_INVALID;
   836     }
   838     /* certificates must have a type */
   839     if ( !sftk_hasAttribute(object,CKA_SUBJECT) ) {
   840 	return CKR_TEMPLATE_INCOMPLETE;
   841     }
   842     if ( !sftk_hasAttribute(object,CKA_VALUE) ) {
   843 	return CKR_TEMPLATE_INCOMPLETE;
   844     }
   846     if (sftk_isTrue(object,CKA_TOKEN)) {
   847 	SFTKSlot *slot = session->slot;
   848 	SFTKDBHandle *certHandle = sftk_getCertDB(slot);
   849 	CK_RV crv;
   851 	if (certHandle == NULL) {
   852 	    return CKR_TOKEN_WRITE_PROTECTED;
   853 	}
   855 	crv = sftkdb_write(certHandle, object, &object->handle);
   856 	sftk_freeDB(certHandle);
   857 	return crv;
   858     }
   860     return CKR_OK;
   861 }
   863 /*
   864  * check the consistancy and initialize a Public Key Object 
   865  */
   866 static CK_RV
   867 sftk_handlePublicKeyObject(SFTKSession *session, SFTKObject *object,
   868 							 CK_KEY_TYPE key_type)
   869 {
   870     CK_BBOOL encrypt = CK_TRUE;
   871     CK_BBOOL recover = CK_TRUE;
   872     CK_BBOOL wrap = CK_TRUE;
   873     CK_BBOOL derive = CK_FALSE;
   874     CK_BBOOL verify = CK_TRUE;
   875     CK_RV crv;
   877     switch (key_type) {
   878     case CKK_RSA:
   879 	crv = sftk_ConstrainAttribute(object, CKA_MODULUS,
   880 						 RSA_MIN_MODULUS_BITS, 0, 0);
   881 	if (crv != CKR_OK) {
   882 	    return crv;
   883 	}
   884 	crv = sftk_ConstrainAttribute(object, CKA_PUBLIC_EXPONENT, 2, 0, 0);
   885 	if (crv != CKR_OK) {
   886 	    return crv;
   887 	}
   888 	break;
   889     case CKK_DSA:
   890 	crv = sftk_ConstrainAttribute(object, CKA_SUBPRIME, 
   891 					DSA_MIN_Q_BITS, DSA_MAX_Q_BITS, 0);
   892 	if (crv != CKR_OK) {
   893 	    return crv;
   894 	}
   895 	crv = sftk_ConstrainAttribute(object, CKA_PRIME, 
   896 					DSA_MIN_P_BITS, DSA_MAX_P_BITS, 64);
   897 	if (crv != CKR_OK) {
   898 	    return crv;
   899 	}
   900 	crv = sftk_ConstrainAttribute(object, CKA_BASE, 2, DSA_MAX_P_BITS, 0);
   901 	if (crv != CKR_OK) {
   902 	    return crv;
   903 	}
   904 	crv = sftk_ConstrainAttribute(object, CKA_VALUE, 2, DSA_MAX_P_BITS, 0);
   905 	if (crv != CKR_OK) {
   906 	    return crv;
   907 	}
   908 	encrypt = CK_FALSE;
   909 	recover = CK_FALSE;
   910 	wrap = CK_FALSE;
   911 	break;
   912     case CKK_DH:
   913 	crv = sftk_ConstrainAttribute(object, CKA_PRIME, 
   914 					DH_MIN_P_BITS, DH_MAX_P_BITS, 0);
   915 	if (crv != CKR_OK) {
   916 	    return crv;
   917 	}
   918 	crv = sftk_ConstrainAttribute(object, CKA_BASE, 2, DH_MAX_P_BITS, 0);
   919 	if (crv != CKR_OK) {
   920 	    return crv;
   921 	}
   922 	crv = sftk_ConstrainAttribute(object, CKA_VALUE, 2, DH_MAX_P_BITS, 0);
   923 	if (crv != CKR_OK) {
   924 	    return crv;
   925 	}
   926 	verify = CK_FALSE;
   927 	derive = CK_TRUE;
   928 	encrypt = CK_FALSE;
   929 	recover = CK_FALSE;
   930 	wrap = CK_FALSE;
   931 	break;
   932 #ifndef NSS_DISABLE_ECC
   933     case CKK_EC:
   934 	if ( !sftk_hasAttribute(object, CKA_EC_PARAMS)) {
   935 	    return CKR_TEMPLATE_INCOMPLETE;
   936 	}
   937 	if ( !sftk_hasAttribute(object, CKA_EC_POINT)) {
   938 	    return CKR_TEMPLATE_INCOMPLETE;
   939 	}
   940 	derive = CK_TRUE;    /* for ECDH */
   941 	verify = CK_TRUE;    /* for ECDSA */
   942 	encrypt = CK_FALSE;
   943 	recover = CK_FALSE;
   944 	wrap = CK_FALSE;
   945 	break;
   946 #endif /* NSS_DISABLE_ECC */
   947     default:
   948 	return CKR_ATTRIBUTE_VALUE_INVALID;
   949     }
   951     /* make sure the required fields exist */
   952     crv = sftk_defaultAttribute(object,CKA_SUBJECT,NULL,0);
   953     if (crv != CKR_OK)  return crv; 
   954     crv = sftk_defaultAttribute(object,CKA_ENCRYPT,&encrypt,sizeof(CK_BBOOL));
   955     if (crv != CKR_OK)  return crv; 
   956     crv = sftk_defaultAttribute(object,CKA_VERIFY,&verify,sizeof(CK_BBOOL));
   957     if (crv != CKR_OK)  return crv; 
   958     crv = sftk_defaultAttribute(object,CKA_VERIFY_RECOVER,
   959 						&recover,sizeof(CK_BBOOL));
   960     if (crv != CKR_OK)  return crv; 
   961     crv = sftk_defaultAttribute(object,CKA_WRAP,&wrap,sizeof(CK_BBOOL));
   962     if (crv != CKR_OK)  return crv; 
   963     crv = sftk_defaultAttribute(object,CKA_DERIVE,&derive,sizeof(CK_BBOOL));
   964     if (crv != CKR_OK)  return crv; 
   966     object->objectInfo = sftk_GetPubKey(object,key_type, &crv);
   967     if (object->objectInfo == NULL) {
   968 	return crv;
   969     }
   970     object->infoFree = (SFTKFree) nsslowkey_DestroyPublicKey;
   972     /* Check that an imported EC key is valid */
   973     if (key_type == CKK_EC) {
   974       NSSLOWKEYPublicKey *pubKey = (NSSLOWKEYPublicKey*) object->objectInfo;
   975       SECStatus rv = EC_ValidatePublicKey(&pubKey->u.ec.ecParams,
   976                                           &pubKey->u.ec.publicValue);
   978       if (rv != SECSuccess) {
   979         return CKR_TEMPLATE_INCONSISTENT;
   980       }
   981     }
   983     if (sftk_isTrue(object,CKA_TOKEN)) {
   984 	SFTKSlot *slot = session->slot;
   985 	SFTKDBHandle *certHandle = sftk_getCertDB(slot);
   987 	if (certHandle == NULL) {
   988 	    return CKR_TOKEN_WRITE_PROTECTED;
   989 	}
   991 	crv = sftkdb_write(certHandle, object, &object->handle);
   992 	sftk_freeDB(certHandle);
   993 	return crv;
   994     }
   996     return CKR_OK;
   997 }
   999 static NSSLOWKEYPrivateKey * 
  1000 sftk_mkPrivKey(SFTKObject *object,CK_KEY_TYPE key, CK_RV *rvp);
  1002 static SECStatus
  1003 sftk_verifyRSAPrivateKey(SFTKObject *object, PRBool fillIfNeeded);
  1005 /*
  1006  * check the consistancy and initialize a Private Key Object 
  1007  */
  1008 static CK_RV
  1009 sftk_handlePrivateKeyObject(SFTKSession *session,SFTKObject *object,CK_KEY_TYPE key_type)
  1011     CK_BBOOL cktrue = CK_TRUE;
  1012     CK_BBOOL encrypt = CK_TRUE;
  1013     CK_BBOOL sign = CK_FALSE;
  1014     CK_BBOOL recover = CK_TRUE;
  1015     CK_BBOOL wrap = CK_TRUE;
  1016     CK_BBOOL derive = CK_TRUE;
  1017     CK_BBOOL ckfalse = CK_FALSE;
  1018     PRBool createObjectInfo = PR_TRUE;
  1019     PRBool fillPrivateKey = PR_FALSE;
  1020     int missing_rsa_mod_component = 0;
  1021     int missing_rsa_exp_component = 0;
  1022     int missing_rsa_crt_component = 0;
  1024     SECItem mod;
  1025     CK_RV crv;
  1026     SECStatus rv;
  1028     switch (key_type) {
  1029     case CKK_RSA:
  1030 	if ( !sftk_hasAttribute(object, CKA_MODULUS)) {
  1031 	    missing_rsa_mod_component++;
  1033 	if ( !sftk_hasAttribute(object, CKA_PUBLIC_EXPONENT)) {
  1034 	    missing_rsa_exp_component++;
  1036 	if ( !sftk_hasAttribute(object, CKA_PRIVATE_EXPONENT)) {
  1037 	    missing_rsa_exp_component++;
  1039 	if ( !sftk_hasAttribute(object, CKA_PRIME_1)) {
  1040 	    missing_rsa_mod_component++;
  1042 	if ( !sftk_hasAttribute(object, CKA_PRIME_2)) {
  1043 	    missing_rsa_mod_component++;
  1045 	if ( !sftk_hasAttribute(object, CKA_EXPONENT_1)) {
  1046 	    missing_rsa_crt_component++;
  1048 	if ( !sftk_hasAttribute(object, CKA_EXPONENT_2)) {
  1049 	    missing_rsa_crt_component++;
  1051 	if ( !sftk_hasAttribute(object, CKA_COEFFICIENT)) {
  1052 	    missing_rsa_crt_component++;
  1054 	if (missing_rsa_mod_component || missing_rsa_exp_component || 
  1055 					 missing_rsa_crt_component) {
  1056 	    /* we are missing a component, see if we have enough to rebuild
  1057 	     * the rest */
  1058 	    int have_exp = 2- missing_rsa_exp_component;
  1059 	    int have_component = 5- 
  1060 		(missing_rsa_exp_component+missing_rsa_mod_component);
  1062 	    if ((have_exp == 0) || (have_component < 3)) {
  1063 		/* nope, not enough to reconstruct the private key */
  1064 		return CKR_TEMPLATE_INCOMPLETE;
  1066 	    fillPrivateKey = PR_TRUE;
  1068 	/*verify the parameters for consistency*/
  1069 	rv = sftk_verifyRSAPrivateKey(object, fillPrivateKey);
  1070 	if (rv != SECSuccess) {
  1071 		return CKR_TEMPLATE_INCOMPLETE;
  1074 	/* make sure Netscape DB attribute is set correctly */
  1075 	crv = sftk_Attribute2SSecItem(NULL, &mod, object, CKA_MODULUS);
  1076 	if (crv != CKR_OK) return crv;
  1077 	crv = sftk_forceAttribute(object, CKA_NETSCAPE_DB, 
  1078 						sftk_item_expand(&mod));
  1079 	if (mod.data) PORT_Free(mod.data);
  1080 	if (crv != CKR_OK) return crv;
  1082 	sign = CK_TRUE;
  1083 	derive = CK_FALSE;
  1084 	break;
  1085     case CKK_DSA:
  1086 	if ( !sftk_hasAttribute(object, CKA_SUBPRIME)) {
  1087 	    return CKR_TEMPLATE_INCOMPLETE;
  1089 	sign = CK_TRUE;
  1090 	derive = CK_FALSE;
  1091 	/* fall through */
  1092     case CKK_DH:
  1093 	if ( !sftk_hasAttribute(object, CKA_PRIME)) {
  1094 	    return CKR_TEMPLATE_INCOMPLETE;
  1096 	if ( !sftk_hasAttribute(object, CKA_BASE)) {
  1097 	    return CKR_TEMPLATE_INCOMPLETE;
  1099 	if ( !sftk_hasAttribute(object, CKA_VALUE)) {
  1100 	    return CKR_TEMPLATE_INCOMPLETE;
  1102 	encrypt = CK_FALSE;
  1103 	recover = CK_FALSE;
  1104 	wrap = CK_FALSE;
  1105 	break;
  1106 #ifndef NSS_DISABLE_ECC
  1107     case CKK_EC:
  1108 	if ( !sftk_hasAttribute(object, CKA_EC_PARAMS)) {
  1109 	    return CKR_TEMPLATE_INCOMPLETE;
  1111 	if ( !sftk_hasAttribute(object, CKA_VALUE)) {
  1112 	    return CKR_TEMPLATE_INCOMPLETE;
  1114 	encrypt = CK_FALSE;
  1115 	sign = CK_TRUE;
  1116 	recover = CK_FALSE;
  1117 	wrap = CK_FALSE;
  1118 	break;
  1119 #endif /* NSS_DISABLE_ECC */
  1120     case CKK_NSS_JPAKE_ROUND1:
  1121         if (!sftk_hasAttribute(object, CKA_PRIME) ||
  1122             !sftk_hasAttribute(object, CKA_SUBPRIME) ||
  1123             !sftk_hasAttribute(object, CKA_BASE)) {
  1124             return CKR_TEMPLATE_INCOMPLETE;
  1126         /* fall through */
  1127     case CKK_NSS_JPAKE_ROUND2:
  1128         /* CKA_NSS_JPAKE_SIGNERID and CKA_NSS_JPAKE_PEERID are checked in
  1129            the J-PAKE code. */
  1130         encrypt = sign = recover = wrap = CK_FALSE;
  1131         derive = CK_TRUE;
  1132         createObjectInfo = PR_FALSE;
  1133         break;
  1134     default:
  1135 	return CKR_ATTRIBUTE_VALUE_INVALID;
  1137     crv = sftk_defaultAttribute(object,CKA_SUBJECT,NULL,0);
  1138     if (crv != CKR_OK)  return crv; 
  1139     crv = sftk_defaultAttribute(object,CKA_SENSITIVE,&cktrue,sizeof(CK_BBOOL));
  1140     if (crv != CKR_OK)  return crv; 
  1141     crv = sftk_defaultAttribute(object,CKA_EXTRACTABLE,&cktrue,sizeof(CK_BBOOL));
  1142     if (crv != CKR_OK)  return crv; 
  1143     crv = sftk_defaultAttribute(object,CKA_DECRYPT,&encrypt,sizeof(CK_BBOOL));
  1144     if (crv != CKR_OK)  return crv; 
  1145     crv = sftk_defaultAttribute(object,CKA_SIGN,&sign,sizeof(CK_BBOOL));
  1146     if (crv != CKR_OK)  return crv; 
  1147     crv = sftk_defaultAttribute(object,CKA_SIGN_RECOVER,&recover,
  1148 							     sizeof(CK_BBOOL));
  1149     if (crv != CKR_OK)  return crv; 
  1150     crv = sftk_defaultAttribute(object,CKA_UNWRAP,&wrap,sizeof(CK_BBOOL));
  1151     if (crv != CKR_OK)  return crv; 
  1152     crv = sftk_defaultAttribute(object,CKA_DERIVE,&derive,sizeof(CK_BBOOL));
  1153     if (crv != CKR_OK)  return crv; 
  1154     /* the next two bits get modified only in the key gen and token cases */
  1155     crv = sftk_forceAttribute(object,CKA_ALWAYS_SENSITIVE,
  1156 						&ckfalse,sizeof(CK_BBOOL));
  1157     if (crv != CKR_OK)  return crv; 
  1158     crv = sftk_forceAttribute(object,CKA_NEVER_EXTRACTABLE,
  1159 						&ckfalse,sizeof(CK_BBOOL));
  1160     if (crv != CKR_OK)  return crv; 
  1162     /* should we check the non-token RSA private keys? */
  1164     if (sftk_isTrue(object,CKA_TOKEN)) {
  1165 	SFTKSlot *slot = session->slot;
  1166 	SFTKDBHandle *keyHandle = sftk_getKeyDB(slot);
  1168 	if (keyHandle == NULL) {
  1169 	    return CKR_TOKEN_WRITE_PROTECTED;
  1172 	crv = sftkdb_write(keyHandle, object, &object->handle);
  1173 	sftk_freeDB(keyHandle);
  1174 	return crv;
  1175     } else if (createObjectInfo) {
  1176 	object->objectInfo = sftk_mkPrivKey(object,key_type,&crv);
  1177 	if (object->objectInfo == NULL) return crv;
  1178 	object->infoFree = (SFTKFree) nsslowkey_DestroyPrivateKey;
  1180     return CKR_OK;
  1183 /* forward declare the DES formating function for handleSecretKey */
  1184 void sftk_FormatDESKey(unsigned char *key, int length);
  1186 /* Validate secret key data, and set defaults */
  1187 static CK_RV
  1188 validateSecretKey(SFTKSession *session, SFTKObject *object, 
  1189 					CK_KEY_TYPE key_type, PRBool isFIPS)
  1191     CK_RV crv;
  1192     CK_BBOOL cktrue = CK_TRUE;
  1193     CK_BBOOL ckfalse = CK_FALSE;
  1194     SFTKAttribute *attribute = NULL;
  1195     unsigned long requiredLen;
  1197     crv = sftk_defaultAttribute(object,CKA_SENSITIVE,
  1198 				isFIPS?&cktrue:&ckfalse,sizeof(CK_BBOOL));
  1199     if (crv != CKR_OK)  return crv; 
  1200     crv = sftk_defaultAttribute(object,CKA_EXTRACTABLE,
  1201 						&cktrue,sizeof(CK_BBOOL));
  1202     if (crv != CKR_OK)  return crv; 
  1203     crv = sftk_defaultAttribute(object,CKA_ENCRYPT,&cktrue,sizeof(CK_BBOOL));
  1204     if (crv != CKR_OK)  return crv; 
  1205     crv = sftk_defaultAttribute(object,CKA_DECRYPT,&cktrue,sizeof(CK_BBOOL));
  1206     if (crv != CKR_OK)  return crv; 
  1207     crv = sftk_defaultAttribute(object,CKA_SIGN,&ckfalse,sizeof(CK_BBOOL));
  1208     if (crv != CKR_OK)  return crv; 
  1209     crv = sftk_defaultAttribute(object,CKA_VERIFY,&ckfalse,sizeof(CK_BBOOL));
  1210     if (crv != CKR_OK)  return crv; 
  1211     crv = sftk_defaultAttribute(object,CKA_WRAP,&cktrue,sizeof(CK_BBOOL));
  1212     if (crv != CKR_OK)  return crv; 
  1213     crv = sftk_defaultAttribute(object,CKA_UNWRAP,&cktrue,sizeof(CK_BBOOL));
  1214     if (crv != CKR_OK)  return crv; 
  1216     if ( !sftk_hasAttribute(object, CKA_VALUE)) {
  1217 	return CKR_TEMPLATE_INCOMPLETE;
  1219     /* the next two bits get modified only in the key gen and token cases */
  1220     crv = sftk_forceAttribute(object,CKA_ALWAYS_SENSITIVE,
  1221 						&ckfalse,sizeof(CK_BBOOL));
  1222     if (crv != CKR_OK)  return crv; 
  1223     crv = sftk_forceAttribute(object,CKA_NEVER_EXTRACTABLE,
  1224 						&ckfalse,sizeof(CK_BBOOL));
  1225     if (crv != CKR_OK)  return crv; 
  1227     /* some types of keys have a value length */
  1228     crv = CKR_OK;
  1229     switch (key_type) {
  1230     /* force CKA_VALUE_LEN to be set */
  1231     case CKK_GENERIC_SECRET:
  1232     case CKK_RC2:
  1233     case CKK_RC4:
  1234 #if NSS_SOFTOKEN_DOES_RC5
  1235     case CKK_RC5:
  1236 #endif
  1237 #ifdef NSS_SOFTOKEN_DOES_CAST
  1238     case CKK_CAST:
  1239     case CKK_CAST3:
  1240     case CKK_CAST5:
  1241 #endif
  1242 #if NSS_SOFTOKEN_DOES_IDEA
  1243     case CKK_IDEA:
  1244 #endif
  1245 	attribute = sftk_FindAttribute(object,CKA_VALUE);
  1246 	/* shouldn't happen */
  1247 	if (attribute == NULL) return CKR_TEMPLATE_INCOMPLETE;
  1248 	crv = sftk_forceAttribute(object, CKA_VALUE_LEN, 
  1249 			&attribute->attrib.ulValueLen, sizeof(CK_ULONG));
  1250 	sftk_FreeAttribute(attribute);
  1251 	break;
  1252     /* force the value to have the correct parity */
  1253     case CKK_DES:
  1254     case CKK_DES2:
  1255     case CKK_DES3:
  1256     case CKK_CDMF:
  1257 	attribute = sftk_FindAttribute(object,CKA_VALUE);
  1258 	/* shouldn't happen */
  1259 	if (attribute == NULL) 
  1260 	    return CKR_TEMPLATE_INCOMPLETE;
  1261 	requiredLen = sftk_MapKeySize(key_type);
  1262 	if (attribute->attrib.ulValueLen != requiredLen) {
  1263 	    sftk_FreeAttribute(attribute);
  1264 	    return CKR_KEY_SIZE_RANGE;
  1266 	sftk_FormatDESKey((unsigned char*)attribute->attrib.pValue,
  1267 						 attribute->attrib.ulValueLen);
  1268 	sftk_FreeAttribute(attribute);
  1269 	break;
  1270     case CKK_AES:
  1271 	attribute = sftk_FindAttribute(object,CKA_VALUE);
  1272 	/* shouldn't happen */
  1273 	if (attribute == NULL) 
  1274 	    return CKR_TEMPLATE_INCOMPLETE;
  1275 	if (attribute->attrib.ulValueLen != 16 &&
  1276 	    attribute->attrib.ulValueLen != 24 &&
  1277 	    attribute->attrib.ulValueLen != 32) {
  1278 	    sftk_FreeAttribute(attribute);
  1279 	    return CKR_KEY_SIZE_RANGE;
  1281 	crv = sftk_forceAttribute(object, CKA_VALUE_LEN, 
  1282 			&attribute->attrib.ulValueLen, sizeof(CK_ULONG));
  1283 	sftk_FreeAttribute(attribute);
  1284 	break;
  1285     default:
  1286 	break;
  1289     return crv;
  1292 /*
  1293  * check the consistancy and initialize a Secret Key Object 
  1294  */
  1295 static CK_RV
  1296 sftk_handleSecretKeyObject(SFTKSession *session,SFTKObject *object,
  1297 					CK_KEY_TYPE key_type, PRBool isFIPS)
  1299     CK_RV crv;
  1301     /* First validate and set defaults */
  1302     crv = validateSecretKey(session, object, key_type, isFIPS);
  1303     if (crv != CKR_OK) goto loser;
  1305     /* If the object is a TOKEN object, store in the database */
  1306     if (sftk_isTrue(object,CKA_TOKEN)) {
  1307 	SFTKSlot *slot = session->slot;
  1308 	SFTKDBHandle *keyHandle = sftk_getKeyDB(slot);
  1309 	CK_RV crv;
  1311 	if (keyHandle == NULL) {
  1312 	    return CKR_TOKEN_WRITE_PROTECTED;
  1315 	crv = sftkdb_write(keyHandle, object, &object->handle);
  1316 	sftk_freeDB(keyHandle);
  1317 	return crv;
  1320 loser:
  1322     return crv;
  1325 /*
  1326  * check the consistancy and initialize a Key Object 
  1327  */
  1328 static CK_RV
  1329 sftk_handleKeyObject(SFTKSession *session, SFTKObject *object)
  1331     SFTKAttribute *attribute;
  1332     CK_KEY_TYPE key_type;
  1333     CK_BBOOL ckfalse = CK_FALSE;
  1334     CK_RV crv;
  1336     /* verify the required fields */
  1337     if ( !sftk_hasAttribute(object,CKA_KEY_TYPE) ) {
  1338 	return CKR_TEMPLATE_INCOMPLETE;
  1341     /* now verify the common fields */
  1342     crv = sftk_defaultAttribute(object,CKA_ID,NULL,0);
  1343     if (crv != CKR_OK)  return crv; 
  1344     crv = sftk_defaultAttribute(object,CKA_START_DATE,NULL,0);
  1345     if (crv != CKR_OK)  return crv; 
  1346     crv = sftk_defaultAttribute(object,CKA_END_DATE,NULL,0);
  1347     if (crv != CKR_OK)  return crv; 
  1348     /* CKA_DERIVE is common to all keys, but it's default value is
  1349      * key dependent */
  1350     crv = sftk_defaultAttribute(object,CKA_LOCAL,&ckfalse,sizeof(CK_BBOOL));
  1351     if (crv != CKR_OK)  return crv; 
  1353     /* get the key type */
  1354     attribute = sftk_FindAttribute(object,CKA_KEY_TYPE);
  1355     if (!attribute) {
  1356         return CKR_ATTRIBUTE_VALUE_INVALID;
  1358     key_type = *(CK_KEY_TYPE *)attribute->attrib.pValue;
  1359     sftk_FreeAttribute(attribute);
  1361     switch (object->objclass) {
  1362     case CKO_PUBLIC_KEY:
  1363 	return sftk_handlePublicKeyObject(session,object,key_type);
  1364     case CKO_PRIVATE_KEY:
  1365 	return sftk_handlePrivateKeyObject(session,object,key_type);
  1366     case CKO_SECRET_KEY:
  1367 	/* make sure the required fields exist */
  1368 	return sftk_handleSecretKeyObject(session,object,key_type,
  1369 			     (PRBool)(session->slot->slotID == FIPS_SLOT_ID));
  1370     default:
  1371 	break;
  1373     return CKR_ATTRIBUTE_VALUE_INVALID;
  1376 /*
  1377  * check the consistancy and Verify a DSA Parameter Object 
  1378  */
  1379 static CK_RV
  1380 sftk_handleDSAParameterObject(SFTKSession *session, SFTKObject *object)
  1382     SFTKAttribute *primeAttr = NULL;
  1383     SFTKAttribute *subPrimeAttr = NULL;
  1384     SFTKAttribute *baseAttr = NULL;
  1385     SFTKAttribute *seedAttr = NULL;
  1386     SFTKAttribute *hAttr = NULL;
  1387     SFTKAttribute *attribute;
  1388     CK_RV crv = CKR_TEMPLATE_INCOMPLETE;
  1389     PQGParams params;
  1390     PQGVerify vfy, *verify = NULL;
  1391     SECStatus result,rv;
  1392     /* This bool keeps track of whether or not we need verify parameters.
  1393      * If a P, Q and G or supplied, we dont' need verify parameters, as we
  1394      * have PQ and G. 
  1395      *   - If G is not supplied, the presumption is that we want to
  1396      * verify P and Q only.
  1397      *   - If counter is supplied, it is presumed we want to verify PQ because
  1398      * the counter is only used in verification.
  1399      *   - If H is supplied, is is presumed we want to verify G because H is
  1400      * only used to verify G.
  1401      *   - Any verification step must have the SEED (counter or H could be 
  1402      * missing depending on exactly what we want to verify). If SEED is supplied,
  1403      * the code just goes ahead and runs verify (other errors are parameter
  1404      * errors are detected by the PQG_VerifyParams function). If SEED is not
  1405      * supplied, but we determined that we are trying to verify (because needVfy
  1406      * is set, go ahead and return CKR_TEMPLATE_INCOMPLETE.
  1407      */
  1408     PRBool needVfy = PR_FALSE;      
  1410     primeAttr = sftk_FindAttribute(object,CKA_PRIME);
  1411     if (primeAttr == NULL) goto loser;
  1412     params.prime.data = primeAttr->attrib.pValue;
  1413     params.prime.len = primeAttr->attrib.ulValueLen;
  1415     subPrimeAttr = sftk_FindAttribute(object,CKA_SUBPRIME);
  1416     if (subPrimeAttr == NULL) goto loser;
  1417     params.subPrime.data = subPrimeAttr->attrib.pValue;
  1418     params.subPrime.len = subPrimeAttr->attrib.ulValueLen;
  1420     baseAttr = sftk_FindAttribute(object,CKA_BASE);
  1421     if (baseAttr != NULL) {
  1422 	params.base.data = baseAttr->attrib.pValue;
  1423 	params.base.len = baseAttr->attrib.ulValueLen;
  1424     } else {
  1425 	params.base.data = NULL;
  1426 	params.base.len = 0;
  1427 	needVfy = PR_TRUE; /* presumably only including PQ so we can verify
  1428 			    * them. */
  1431     attribute = sftk_FindAttribute(object, CKA_NETSCAPE_PQG_COUNTER);
  1432     if (attribute != NULL) {
  1433 	vfy.counter = *(CK_ULONG *) attribute->attrib.pValue;
  1434 	sftk_FreeAttribute(attribute);
  1435 	needVfy = PR_TRUE; /* included a count so we can verify PQ */
  1436     } else {
  1437 	vfy.counter = -1;
  1440     hAttr = sftk_FindAttribute(object, CKA_NETSCAPE_PQG_H);
  1441     if (hAttr != NULL) {
  1442 	vfy.h.data = hAttr->attrib.pValue;
  1443 	vfy.h.len = hAttr->attrib.ulValueLen;
  1444 	needVfy = PR_TRUE; /* included H so we can verify G */
  1445     } else {
  1446 	vfy.h.data = NULL;
  1447 	vfy.h.len = 0;
  1449     seedAttr = sftk_FindAttribute(object, CKA_NETSCAPE_PQG_SEED);
  1450     if (seedAttr != NULL) {
  1451 	vfy.seed.data = seedAttr->attrib.pValue;
  1452 	vfy.seed.len = seedAttr->attrib.ulValueLen;
  1454 	verify = &vfy;
  1455     } else if (needVfy) {
  1456 	goto loser; /* Verify always needs seed, if we need verify and not seed
  1457 		     * then fail */
  1460     crv = CKR_FUNCTION_FAILED;
  1461     rv = PQG_VerifyParams(&params,verify,&result);
  1462     if (rv == SECSuccess) {
  1463 	crv = (result== SECSuccess) ? CKR_OK : CKR_ATTRIBUTE_VALUE_INVALID;
  1466 loser:
  1467     if (hAttr) sftk_FreeAttribute(hAttr);
  1468     if (seedAttr) sftk_FreeAttribute(seedAttr);
  1469     if (baseAttr) sftk_FreeAttribute(baseAttr);
  1470     if (subPrimeAttr) sftk_FreeAttribute(subPrimeAttr);
  1471     if (primeAttr) sftk_FreeAttribute(primeAttr);
  1473     return crv;
  1476 /*
  1477  * check the consistancy and initialize a Key Parameter Object 
  1478  */
  1479 static CK_RV
  1480 sftk_handleKeyParameterObject(SFTKSession *session, SFTKObject *object)
  1482     SFTKAttribute *attribute;
  1483     CK_KEY_TYPE key_type;
  1484     CK_BBOOL ckfalse = CK_FALSE;
  1485     CK_RV crv;
  1487     /* verify the required fields */
  1488     if ( !sftk_hasAttribute(object,CKA_KEY_TYPE) ) {
  1489 	return CKR_TEMPLATE_INCOMPLETE;
  1492     /* now verify the common fields */
  1493     crv = sftk_defaultAttribute(object,CKA_LOCAL,&ckfalse,sizeof(CK_BBOOL));
  1494     if (crv != CKR_OK)  return crv; 
  1496     /* get the key type */
  1497     attribute = sftk_FindAttribute(object,CKA_KEY_TYPE);
  1498     if (!attribute) {
  1499         return CKR_ATTRIBUTE_VALUE_INVALID;
  1501     key_type = *(CK_KEY_TYPE *)attribute->attrib.pValue;
  1502     sftk_FreeAttribute(attribute);
  1504     switch (key_type) {
  1505     case CKK_DSA:
  1506 	return sftk_handleDSAParameterObject(session,object);
  1508     default:
  1509 	break;
  1511     return CKR_KEY_TYPE_INCONSISTENT;
  1514 /* 
  1515  * Handle Object does all the object consistancy checks, automatic attribute
  1516  * generation, attribute defaulting, etc. If handleObject succeeds, the object
  1517  * will be assigned an object handle, and the object installed in the session
  1518  * or stored in the DB.
  1519  */
  1520 CK_RV
  1521 sftk_handleObject(SFTKObject *object, SFTKSession *session)
  1523     SFTKSlot *slot = session->slot;
  1524     SFTKAttribute *attribute;
  1525     SFTKObject *duplicateObject = NULL;
  1526     CK_OBJECT_HANDLE handle;
  1527     CK_BBOOL ckfalse = CK_FALSE;
  1528     CK_BBOOL cktrue = CK_TRUE;
  1529     CK_RV crv;
  1531     /* make sure all the base object types are defined. If not set the
  1532      * defaults */
  1533     crv = sftk_defaultAttribute(object,CKA_TOKEN,&ckfalse,sizeof(CK_BBOOL));
  1534     if (crv != CKR_OK) return crv;
  1535     crv = sftk_defaultAttribute(object,CKA_PRIVATE,&ckfalse,sizeof(CK_BBOOL));
  1536     if (crv != CKR_OK) return crv;
  1537     crv = sftk_defaultAttribute(object,CKA_LABEL,NULL,0);
  1538     if (crv != CKR_OK) return crv;
  1539     crv = sftk_defaultAttribute(object,CKA_MODIFIABLE,&cktrue,sizeof(CK_BBOOL));
  1540     if (crv != CKR_OK) return crv;
  1542     /* don't create a private object if we aren't logged in */
  1543     if ((!slot->isLoggedIn) && (slot->needLogin) &&
  1544 				(sftk_isTrue(object,CKA_PRIVATE))) {
  1545 	return CKR_USER_NOT_LOGGED_IN;
  1549     if (((session->info.flags & CKF_RW_SESSION) == 0) &&
  1550 				(sftk_isTrue(object,CKA_TOKEN))) {
  1551 	return CKR_SESSION_READ_ONLY;
  1554     /* Assign a unique SESSION object handle to every new object,
  1555      * whether it is a session object or a token object.  
  1556      * At this point, all new objects are structured as session objects.
  1557      * Objects with the CKA_TOKEN attribute true will be turned into 
  1558      * token objects and will have a token object handle assigned to 
  1559      * them by a call to sftk_mkHandle in the handler for each object 
  1560      * class, invoked below.
  1562      * It may be helpful to note/remember that 
  1563      * sftk_narrowToXxxObject uses sftk_isToken,
  1564      * sftk_isToken examines the sign bit of the object's handle, but
  1565      * sftk_isTrue(...,CKA_TOKEN) examines the CKA_TOKEN attribute.
  1566      */
  1567     do {
  1568 	PRUint32 wrappedAround;
  1570 	duplicateObject = NULL;
  1571 	PZ_Lock(slot->objectLock);
  1572 	wrappedAround = slot->sessionObjectHandleCount &  SFTK_TOKEN_MASK;
  1573 	handle        = slot->sessionObjectHandleCount & ~SFTK_TOKEN_MASK;
  1574 	if (!handle) /* don't allow zero handle */
  1575 	    handle = minSessionObjectHandle;  
  1576 	slot->sessionObjectHandleCount = (handle + 1U) | wrappedAround;
  1577 	/* Is there already a session object with this handle? */
  1578 	if (wrappedAround) {
  1579 	    sftkqueue_find(duplicateObject, handle, slot->sessObjHashTable, \
  1580 	                   slot->sessObjHashSize);
  1582 	PZ_Unlock(slot->objectLock);
  1583     } while (duplicateObject != NULL);
  1584     object->handle = handle;
  1586     /* get the object class */
  1587     attribute = sftk_FindAttribute(object,CKA_CLASS);
  1588     if (attribute == NULL) {
  1589 	return CKR_TEMPLATE_INCOMPLETE;
  1591     object->objclass = *(CK_OBJECT_CLASS *)attribute->attrib.pValue;
  1592     sftk_FreeAttribute(attribute);
  1594     /* Now handle the specific object class. 
  1595      * At this point, all objects are session objects, and the session
  1596      * number must be passed to the object class handlers.
  1597      */
  1598     switch (object->objclass) {
  1599     case CKO_DATA:
  1600 	crv = sftk_handleDataObject(session,object);
  1601 	break;
  1602     case CKO_CERTIFICATE:
  1603 	crv = sftk_handleCertObject(session,object);
  1604 	break;
  1605     case CKO_NETSCAPE_TRUST:
  1606 	crv = sftk_handleTrustObject(session,object);
  1607 	break;
  1608     case CKO_NETSCAPE_CRL:
  1609 	crv = sftk_handleCrlObject(session,object);
  1610 	break;
  1611     case CKO_NETSCAPE_SMIME:
  1612 	crv = sftk_handleSMimeObject(session,object);
  1613 	break;
  1614     case CKO_PRIVATE_KEY:
  1615     case CKO_PUBLIC_KEY:
  1616     case CKO_SECRET_KEY:
  1617 	crv = sftk_handleKeyObject(session,object);
  1618 	break;
  1619     case CKO_KG_PARAMETERS:
  1620 	crv = sftk_handleKeyParameterObject(session,object);
  1621 	break;
  1622     default:
  1623 	crv = CKR_ATTRIBUTE_VALUE_INVALID;
  1624 	break;
  1627     /* can't fail from here on out unless the pk_handlXXX functions have
  1628      * failed the request */
  1629     if (crv != CKR_OK) {
  1630 	return crv;
  1633     /* Now link the object into the slot and session structures.
  1634      * If the object has a true CKA_TOKEN attribute, the above object
  1635      * class handlers will have set the sign bit in the object handle,
  1636      * causing the following test to be true.
  1637      */
  1638     if (sftk_isToken(object->handle)) {
  1639 	sftk_convertSessionToToken(object);
  1640     } else {
  1641 	object->slot = slot;
  1642 	sftk_AddObject(session,object);
  1645     return CKR_OK;
  1648 /*
  1649  * ******************** Public Key Utilities ***************************
  1650  */
  1651 /* Generate a low public key structure from an object */
  1652 NSSLOWKEYPublicKey *sftk_GetPubKey(SFTKObject *object,CK_KEY_TYPE key_type, 
  1653 								CK_RV *crvp)
  1655     NSSLOWKEYPublicKey *pubKey;
  1656     PLArenaPool *arena;
  1657     CK_RV crv;
  1659     if (object->objclass != CKO_PUBLIC_KEY) {
  1660 	*crvp = CKR_KEY_TYPE_INCONSISTENT;
  1661 	return NULL;
  1664     if (sftk_isToken(object->handle)) {
  1665 /* ferret out the token object handle */
  1668     /* If we already have a key, use it */
  1669     if (object->objectInfo) {
  1670 	*crvp = CKR_OK;
  1671 	return (NSSLOWKEYPublicKey *)object->objectInfo;
  1674     /* allocate the structure */
  1675     arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
  1676     if (arena == NULL) {
  1677 	*crvp = CKR_HOST_MEMORY;
  1678 	return NULL;
  1681     pubKey = (NSSLOWKEYPublicKey *)
  1682 			PORT_ArenaAlloc(arena,sizeof(NSSLOWKEYPublicKey));
  1683     if (pubKey == NULL) {
  1684     	PORT_FreeArena(arena,PR_FALSE);
  1685 	*crvp = CKR_HOST_MEMORY;
  1686 	return NULL;
  1689     /* fill in the structure */
  1690     pubKey->arena = arena;
  1691     switch (key_type) {
  1692     case CKK_RSA:
  1693 	pubKey->keyType = NSSLOWKEYRSAKey;
  1694 	crv = sftk_Attribute2SSecItem(arena,&pubKey->u.rsa.modulus,
  1695 							object,CKA_MODULUS);
  1696     	if (crv != CKR_OK) break;
  1697     	crv = sftk_Attribute2SSecItem(arena,&pubKey->u.rsa.publicExponent,
  1698 						object,CKA_PUBLIC_EXPONENT);
  1699 	break;
  1700     case CKK_DSA:
  1701 	pubKey->keyType = NSSLOWKEYDSAKey;
  1702 	crv = sftk_Attribute2SSecItem(arena,&pubKey->u.dsa.params.prime,
  1703 							object,CKA_PRIME);
  1704     	if (crv != CKR_OK) break;
  1705 	crv = sftk_Attribute2SSecItem(arena,&pubKey->u.dsa.params.subPrime,
  1706 							object,CKA_SUBPRIME);
  1707     	if (crv != CKR_OK) break;
  1708 	crv = sftk_Attribute2SSecItem(arena,&pubKey->u.dsa.params.base,
  1709 							object,CKA_BASE);
  1710     	if (crv != CKR_OK) break;
  1711     	crv = sftk_Attribute2SSecItem(arena,&pubKey->u.dsa.publicValue,
  1712 							object,CKA_VALUE);
  1713 	break;
  1714     case CKK_DH:
  1715 	pubKey->keyType = NSSLOWKEYDHKey;
  1716 	crv = sftk_Attribute2SSecItem(arena,&pubKey->u.dh.prime,
  1717 							object,CKA_PRIME);
  1718     	if (crv != CKR_OK) break;
  1719 	crv = sftk_Attribute2SSecItem(arena,&pubKey->u.dh.base,
  1720 							object,CKA_BASE);
  1721     	if (crv != CKR_OK) break;
  1722     	crv = sftk_Attribute2SSecItem(arena,&pubKey->u.dh.publicValue,
  1723 							object,CKA_VALUE);
  1724 	break;
  1725 #ifndef NSS_DISABLE_ECC
  1726     case CKK_EC:
  1727 	pubKey->keyType = NSSLOWKEYECKey;
  1728 	crv = sftk_Attribute2SSecItem(arena,
  1729 	                              &pubKey->u.ec.ecParams.DEREncoding,
  1730 	                              object,CKA_EC_PARAMS);
  1731 	if (crv != CKR_OK) break;
  1733 	/* Fill out the rest of the ecParams structure 
  1734 	 * based on the encoded params
  1735 	 */
  1736 	if (EC_FillParams(arena, &pubKey->u.ec.ecParams.DEREncoding,
  1737 		    &pubKey->u.ec.ecParams) != SECSuccess) {
  1738 	    crv = CKR_DOMAIN_PARAMS_INVALID;
  1739 	    break;
  1742 	crv = sftk_Attribute2SSecItem(arena,&pubKey->u.ec.publicValue,
  1743 	                              object,CKA_EC_POINT);
  1744 	if (crv == CKR_OK) {
  1745 	    int keyLen,curveLen;
  1747 	    curveLen = (pubKey->u.ec.ecParams.fieldID.size +7)/8;
  1748 	    keyLen = (2*curveLen)+1;
  1750 	    /* special note: We can't just use the first byte to determine
  1751 	     * between these 2 cases because both EC_POINT_FORM_UNCOMPRESSED 
  1752 	     * and SEC_ASN1_OCTET_STRING are 0x04 */
  1754 	    /* handle the non-DER encoded case (UNCOMPRESSED only) */	
  1755 	    if (pubKey->u.ec.publicValue.data[0] == EC_POINT_FORM_UNCOMPRESSED
  1756 		&& pubKey->u.ec.publicValue.len == keyLen) {
  1757 		break; /* key was not DER encoded, no need to unwrap */
  1760 	    /* if we ever support compressed, handle it here */
  1762 	    /* handle the encoded case */
  1763 	    if ((pubKey->u.ec.publicValue.data[0] == SEC_ASN1_OCTET_STRING) 
  1764 		&& pubKey->u.ec.publicValue.len > keyLen) {
  1765 		SECItem publicValue;
  1766 		SECStatus rv;
  1768 		rv = SEC_QuickDERDecodeItem(arena, &publicValue, 
  1769 					 SEC_ASN1_GET(SEC_OctetStringTemplate), 
  1770 					 &pubKey->u.ec.publicValue);
  1771 		/* nope, didn't decode correctly */
  1772 		if ((rv != SECSuccess)
  1773 		    || (publicValue.data[0] != EC_POINT_FORM_UNCOMPRESSED)
  1774 		    || (publicValue.len != keyLen)) {
  1775 	   	    crv = CKR_ATTRIBUTE_VALUE_INVALID;
  1776 		    break;
  1778 		/* replace our previous with the decoded key */
  1779 		pubKey->u.ec.publicValue = publicValue;
  1780 		break;
  1782 	   crv = CKR_ATTRIBUTE_VALUE_INVALID;
  1784 	break;
  1785 #endif /* NSS_DISABLE_ECC */
  1786     default:
  1787 	crv = CKR_KEY_TYPE_INCONSISTENT;
  1788 	break;
  1790     *crvp = crv;
  1791     if (crv != CKR_OK) {
  1792     	PORT_FreeArena(arena,PR_FALSE);
  1793 	return NULL;
  1796     object->objectInfo = pubKey;
  1797     object->infoFree = (SFTKFree) nsslowkey_DestroyPublicKey;
  1798     return pubKey;
  1801 /* make a private key from a verified object */
  1802 static NSSLOWKEYPrivateKey *
  1803 sftk_mkPrivKey(SFTKObject *object, CK_KEY_TYPE key_type, CK_RV *crvp)
  1805     NSSLOWKEYPrivateKey *privKey;
  1806     SFTKItemTemplate itemTemplate[SFTK_MAX_ITEM_TEMPLATE];
  1807     int itemTemplateCount = 0;
  1808     PLArenaPool *arena;
  1809     CK_RV crv = CKR_OK;
  1810     SECStatus rv;
  1812     arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
  1813     if (arena == NULL) {
  1814 	*crvp = CKR_HOST_MEMORY;
  1815 	return NULL;
  1818     privKey = (NSSLOWKEYPrivateKey *)
  1819 			PORT_ArenaZAlloc(arena,sizeof(NSSLOWKEYPrivateKey));
  1820     if (privKey == NULL)  {
  1821 	PORT_FreeArena(arena,PR_FALSE);
  1822 	*crvp = CKR_HOST_MEMORY;
  1823 	return NULL;
  1826     /* in future this would be a switch on key_type */
  1827     privKey->arena = arena;
  1828     switch (key_type) {
  1829     case CKK_RSA:
  1830 	privKey->keyType = NSSLOWKEYRSAKey;
  1832 	SFTK_SET_ITEM_TEMPLATE(itemTemplate, itemTemplateCount,
  1833 		&privKey->u.rsa.modulus,CKA_MODULUS);
  1834 	itemTemplateCount++;
  1835 	SFTK_SET_ITEM_TEMPLATE(itemTemplate, itemTemplateCount,
  1836 		&privKey->u.rsa.publicExponent, CKA_PUBLIC_EXPONENT);
  1837 	itemTemplateCount++;
  1838 	SFTK_SET_ITEM_TEMPLATE(itemTemplate, itemTemplateCount,
  1839 		&privKey->u.rsa.privateExponent, CKA_PRIVATE_EXPONENT);
  1840 	itemTemplateCount++;
  1841 	SFTK_SET_ITEM_TEMPLATE(itemTemplate, itemTemplateCount,
  1842 		&privKey->u.rsa.prime1, CKA_PRIME_1);
  1843 	itemTemplateCount++;
  1844 	SFTK_SET_ITEM_TEMPLATE(itemTemplate, itemTemplateCount,
  1845 		&privKey->u.rsa.prime2, CKA_PRIME_2);
  1846 	itemTemplateCount++;
  1847 	SFTK_SET_ITEM_TEMPLATE(itemTemplate, itemTemplateCount,
  1848 		&privKey->u.rsa.exponent1, CKA_EXPONENT_1);
  1849 	itemTemplateCount++;
  1850 	SFTK_SET_ITEM_TEMPLATE(itemTemplate, itemTemplateCount,
  1851 		&privKey->u.rsa.exponent2, CKA_EXPONENT_2);
  1852 	itemTemplateCount++;
  1853 	SFTK_SET_ITEM_TEMPLATE(itemTemplate, itemTemplateCount,
  1854 		&privKey->u.rsa.coefficient, CKA_COEFFICIENT);
  1855 	itemTemplateCount++;
  1856         rv = DER_SetUInteger(privKey->arena, &privKey->u.rsa.version,
  1857                           NSSLOWKEY_PRIVATE_KEY_INFO_VERSION);
  1858 	if (rv != SECSuccess) crv = CKR_HOST_MEMORY;
  1859 	break;
  1861     case CKK_DSA:
  1862 	privKey->keyType = NSSLOWKEYDSAKey;
  1863 	SFTK_SET_ITEM_TEMPLATE(itemTemplate, itemTemplateCount,
  1864 		&privKey->u.dsa.params.prime, CKA_PRIME);
  1865 	itemTemplateCount++;
  1866 	SFTK_SET_ITEM_TEMPLATE(itemTemplate, itemTemplateCount,
  1867 		&privKey->u.dsa.params.subPrime, CKA_SUBPRIME);
  1868 	itemTemplateCount++;
  1869 	SFTK_SET_ITEM_TEMPLATE(itemTemplate, itemTemplateCount,
  1870 		&privKey->u.dsa.params.base, CKA_BASE);
  1871 	itemTemplateCount++;
  1872 	SFTK_SET_ITEM_TEMPLATE(itemTemplate, itemTemplateCount,
  1873 		&privKey->u.dsa.privateValue, CKA_VALUE);
  1874 	itemTemplateCount++;
  1875 	/* privKey was zero'd so public value is already set to NULL, 0
  1876 	 * if we don't set it explicitly */
  1877 	break;
  1879     case CKK_DH:
  1880 	privKey->keyType = NSSLOWKEYDHKey;
  1881 	SFTK_SET_ITEM_TEMPLATE(itemTemplate, itemTemplateCount,
  1882 		&privKey->u.dh.prime, CKA_PRIME);
  1883 	itemTemplateCount++;
  1884 	SFTK_SET_ITEM_TEMPLATE(itemTemplate, itemTemplateCount,
  1885 		&privKey->u.dh.base, CKA_BASE);
  1886 	itemTemplateCount++;
  1887 	SFTK_SET_ITEM_TEMPLATE(itemTemplate, itemTemplateCount,
  1888 		&privKey->u.dh.privateValue, CKA_VALUE);
  1889 	itemTemplateCount++;
  1890 	/* privKey was zero'd so public value is already set to NULL, 0
  1891 	 * if we don't set it explicitly */
  1892 	break;
  1894 #ifndef NSS_DISABLE_ECC
  1895     case CKK_EC:
  1896 	privKey->keyType = NSSLOWKEYECKey;
  1897 	crv = sftk_Attribute2SSecItem(arena, 
  1898 				      &privKey->u.ec.ecParams.DEREncoding,
  1899 				      object,CKA_EC_PARAMS);
  1900     	if (crv != CKR_OK) break;
  1902 	/* Fill out the rest of the ecParams structure
  1903 	 * based on the encoded params
  1904 	 */
  1905 	if (EC_FillParams(arena, &privKey->u.ec.ecParams.DEREncoding,
  1906 		    &privKey->u.ec.ecParams) != SECSuccess) {
  1907 	    crv = CKR_DOMAIN_PARAMS_INVALID;
  1908 	    break;
  1910 	crv = sftk_Attribute2SSecItem(arena,&privKey->u.ec.privateValue,
  1911 							object,CKA_VALUE);
  1912 	if (crv != CKR_OK) break;
  1914 	if (sftk_hasAttribute(object, CKA_NETSCAPE_DB)) {
  1915 	    crv = sftk_Attribute2SSecItem(arena, &privKey->u.ec.publicValue,
  1916  				object, CKA_NETSCAPE_DB);
  1917 	    if (crv != CKR_OK) break;
  1918 	    /* privKey was zero'd so public value is already set to NULL, 0
  1919 	     * if we don't set it explicitly */
  1921         rv = DER_SetUInteger(privKey->arena, &privKey->u.ec.version,
  1922                           NSSLOWKEY_EC_PRIVATE_KEY_VERSION);
  1923 	if (rv != SECSuccess) {
  1924 	    crv = CKR_HOST_MEMORY;
  1925 	    /* The following ifdef is needed for Linux arm distros and
  1926 	     * Android as gcc 4.6 has a bug when targeting arm (but not
  1927 	     * thumb). The bug has been fixed in gcc 4.7.
  1928 	     * http://gcc.gnu.org/bugzilla/show_bug.cgi?id=56561
  1929 	     */
  1930 #if defined (__arm__) && !defined(__thumb__) && defined (__GNUC__)
  1931 	    *crvp = CKR_HOST_MEMORY;
  1932 	    break;
  1933 #endif
  1935 	break;
  1936 #endif /* NSS_DISABLE_ECC */
  1938     default:
  1939 	crv = CKR_KEY_TYPE_INCONSISTENT;
  1940 	break;
  1942     if (crv == CKR_OK && itemTemplateCount != 0) {
  1943 	PORT_Assert(itemTemplateCount > 0);
  1944 	PORT_Assert(itemTemplateCount <= SFTK_MAX_ITEM_TEMPLATE);
  1945 	crv = sftk_MultipleAttribute2SecItem(arena, object, itemTemplate, 
  1946 						itemTemplateCount);
  1948     *crvp = crv;
  1949     if (crv != CKR_OK) {
  1950 	PORT_FreeArena(arena,PR_FALSE);
  1951 	return NULL;
  1953     return privKey;
  1956 /*
  1957  * If a partial RSA private key is present, fill in the rest if necessary,
  1958  * and then verify the parameters are well-formed
  1959  */
  1960 static SECStatus
  1961 sftk_verifyRSAPrivateKey(SFTKObject *object, PRBool fillIfNeeded)
  1963     RSAPrivateKey tmpKey = { 0 };
  1964     SFTKAttribute *modulus = NULL;
  1965     SFTKAttribute *prime1 = NULL;
  1966     SFTKAttribute *prime2 = NULL;
  1967     SFTKAttribute *privateExponent = NULL;
  1968     SFTKAttribute *publicExponent = NULL;
  1969     SFTKAttribute *exponent1 = NULL;
  1970     SFTKAttribute *exponent2 = NULL;
  1971     SFTKAttribute *coefficient = NULL;
  1972     SECStatus rv;
  1973     CK_RV crv;
  1975     /* first fill in the components that we have. Populate only uses
  1976      * the non-crt components, so only fill those in  */
  1977     tmpKey.arena = NULL;
  1978     modulus = sftk_FindAttribute(object, CKA_MODULUS);
  1979     if (modulus) {
  1980 	tmpKey.modulus.data = modulus->attrib.pValue;
  1981 	tmpKey.modulus.len  = modulus->attrib.ulValueLen;
  1983     prime1 = sftk_FindAttribute(object, CKA_PRIME_1);
  1984     if (prime1) {
  1985 	tmpKey.prime1.data = prime1->attrib.pValue;
  1986 	tmpKey.prime1.len  = prime1->attrib.ulValueLen;
  1988     prime2 = sftk_FindAttribute(object, CKA_PRIME_2);
  1989     if (prime2) {
  1990 	tmpKey.prime2.data = prime2->attrib.pValue;
  1991 	tmpKey.prime2.len  = prime2->attrib.ulValueLen;
  1993     privateExponent = sftk_FindAttribute(object, CKA_PRIVATE_EXPONENT);
  1994     if (privateExponent) {
  1995 	tmpKey.privateExponent.data = privateExponent->attrib.pValue;
  1996 	tmpKey.privateExponent.len  = privateExponent->attrib.ulValueLen;
  1998     publicExponent = sftk_FindAttribute(object, CKA_PUBLIC_EXPONENT);
  1999     if (publicExponent) {
  2000 	tmpKey.publicExponent.data = publicExponent->attrib.pValue;
  2001 	tmpKey.publicExponent.len  = publicExponent->attrib.ulValueLen;
  2003     exponent1 = sftk_FindAttribute(object, CKA_EXPONENT_1);
  2004     if (exponent1) {
  2005 	tmpKey.exponent1.data = exponent1->attrib.pValue;
  2006 	tmpKey.exponent1.len  = exponent1->attrib.ulValueLen;
  2008     exponent2 = sftk_FindAttribute(object, CKA_EXPONENT_2);
  2009     if (exponent2) {
  2010 	tmpKey.exponent2.data = exponent2->attrib.pValue;
  2011 	tmpKey.exponent2.len  = exponent2->attrib.ulValueLen;
  2013     coefficient = sftk_FindAttribute(object, CKA_COEFFICIENT);
  2014     if (coefficient) {
  2015 	tmpKey.coefficient.data = coefficient->attrib.pValue;
  2016 	tmpKey.coefficient.len  = coefficient->attrib.ulValueLen;
  2019     if (fillIfNeeded) {
  2020 	/*
  2021 	* populate requires one exponent plus 2 other components to work.
  2022 	* we expected our caller to check that first. If that didn't happen,
  2023 	* populate will simply return an error here.
  2024 	*/
  2025 	rv = RSA_PopulatePrivateKey(&tmpKey);
  2026 	if (rv != SECSuccess) {
  2027 		goto loser;
  2030     rv = RSA_PrivateKeyCheck(&tmpKey);
  2031     if (rv != SECSuccess) {
  2032 	goto loser;
  2034     /* now that we have a fully populated key, set all our attribute values */
  2035     rv = SECFailure;
  2036     if (!modulus || modulus->attrib.pValue != tmpKey.modulus.data) {
  2037         crv = sftk_forceAttribute(object,CKA_MODULUS,
  2038                                   sftk_item_expand(&tmpKey.modulus));
  2039         if (crv != CKR_OK) goto loser;
  2041     if (!publicExponent ||
  2042         publicExponent->attrib.pValue != tmpKey.publicExponent.data) {
  2043         crv = sftk_forceAttribute(object, CKA_PUBLIC_EXPONENT,
  2044                                   sftk_item_expand(&tmpKey.publicExponent));
  2045         if (crv != CKR_OK) goto loser;
  2047     if (!privateExponent ||
  2048         privateExponent->attrib.pValue != tmpKey.privateExponent.data) {
  2049         crv = sftk_forceAttribute(object, CKA_PRIVATE_EXPONENT,
  2050                                   sftk_item_expand(&tmpKey.privateExponent));
  2051         if (crv != CKR_OK) goto loser;
  2053     if (!prime1 || prime1->attrib.pValue != tmpKey.prime1.data) {
  2054         crv = sftk_forceAttribute(object, CKA_PRIME_1,
  2055                                   sftk_item_expand(&tmpKey.prime1));
  2056         if (crv != CKR_OK) goto loser;
  2058     if (!prime2 || prime2->attrib.pValue != tmpKey.prime2.data) {
  2059         crv = sftk_forceAttribute(object, CKA_PRIME_2,
  2060                                   sftk_item_expand(&tmpKey.prime2));
  2061         if (crv != CKR_OK) goto loser;
  2063     if (!exponent1 || exponent1->attrib.pValue != tmpKey.exponent1.data) {
  2064         crv = sftk_forceAttribute(object, CKA_EXPONENT_1,
  2065                                  sftk_item_expand(&tmpKey.exponent1));
  2066         if (crv != CKR_OK) goto loser;
  2068     if (!exponent2 || exponent2->attrib.pValue != tmpKey.exponent2.data) {
  2069         crv = sftk_forceAttribute(object, CKA_EXPONENT_2,
  2070                                   sftk_item_expand(&tmpKey.exponent2));
  2071         if (crv != CKR_OK) goto loser;
  2073     if (!coefficient || coefficient->attrib.pValue != tmpKey.coefficient.data) {
  2074         crv = sftk_forceAttribute(object, CKA_COEFFICIENT,
  2075                                   sftk_item_expand(&tmpKey.coefficient));
  2076         if (crv != CKR_OK) goto loser;
  2078     rv = SECSuccess;
  2080     /* we're done (one way or the other), clean up all our stuff */
  2081 loser:
  2082     if (tmpKey.arena) {
  2083 	PORT_FreeArena(tmpKey.arena,PR_TRUE);
  2085     if (modulus) {
  2086 	sftk_FreeAttribute(modulus);
  2088     if (prime1) {
  2089 	sftk_FreeAttribute(prime1);
  2091     if (prime2) {
  2092 	sftk_FreeAttribute(prime2);
  2094     if (privateExponent) {
  2095 	sftk_FreeAttribute(privateExponent);
  2097     if (publicExponent) {
  2098 	sftk_FreeAttribute(publicExponent);
  2100     if (exponent1) {
  2101 	sftk_FreeAttribute(exponent1);
  2103     if (exponent2) {
  2104 	sftk_FreeAttribute(exponent2);
  2106     if (coefficient) {
  2107 	sftk_FreeAttribute(coefficient);
  2109     return rv;
  2112 /* Generate a low private key structure from an object */
  2113 NSSLOWKEYPrivateKey *
  2114 sftk_GetPrivKey(SFTKObject *object,CK_KEY_TYPE key_type, CK_RV *crvp)
  2116     NSSLOWKEYPrivateKey *priv = NULL;
  2118     if (object->objclass != CKO_PRIVATE_KEY) {
  2119 	*crvp = CKR_KEY_TYPE_INCONSISTENT;
  2120 	return NULL;
  2122     if (object->objectInfo) {
  2123 	*crvp = CKR_OK;
  2124 	return (NSSLOWKEYPrivateKey *)object->objectInfo;
  2127     priv = sftk_mkPrivKey(object, key_type, crvp);
  2128     object->objectInfo = priv;
  2129     object->infoFree = (SFTKFree) nsslowkey_DestroyPrivateKey;
  2130     return priv;
  2133 /*
  2134  **************************** Symetric Key utils ************************
  2135  */
  2136 /*
  2137  * set the DES key with parity bits correctly
  2138  */
  2139 void
  2140 sftk_FormatDESKey(unsigned char *key, int length)
  2142     int i;
  2144     /* format the des key */
  2145     for (i=0; i < length; i++) {
  2146 	key[i] = parityTable[key[i]>>1];
  2150 /*
  2151  * check a des key (des2 or des3 subkey) for weak keys.
  2152  */
  2153 PRBool
  2154 sftk_CheckDESKey(unsigned char *key)
  2156     int i;
  2158     /* format the des key with parity  */
  2159     sftk_FormatDESKey(key, 8);
  2161     for (i=0; i < sftk_desWeakTableSize; i++) {
  2162 	if (PORT_Memcmp(key,sftk_desWeakTable[i],8) == 0) {
  2163 	    return PR_TRUE;
  2166     return PR_FALSE;
  2169 /*
  2170  * check if a des or triple des key is weak.
  2171  */
  2172 PRBool
  2173 sftk_IsWeakKey(unsigned char *key,CK_KEY_TYPE key_type)
  2176     switch(key_type) {
  2177     case CKK_DES:
  2178 	return sftk_CheckDESKey(key);
  2179     case CKM_DES2_KEY_GEN:
  2180 	if (sftk_CheckDESKey(key)) return PR_TRUE;
  2181 	return sftk_CheckDESKey(&key[8]);
  2182     case CKM_DES3_KEY_GEN:
  2183 	if (sftk_CheckDESKey(key)) return PR_TRUE;
  2184 	if (sftk_CheckDESKey(&key[8])) return PR_TRUE;
  2185 	return sftk_CheckDESKey(&key[16]);
  2186     default:
  2187 	break;
  2189     return PR_FALSE;
  2193 /**********************************************************************
  2195  *     Start of PKCS 11 functions 
  2197  **********************************************************************/
  2200 /* return the function list */
  2201 CK_RV NSC_GetFunctionList(CK_FUNCTION_LIST_PTR *pFunctionList)
  2203     CHECK_FORK();
  2205     *pFunctionList = (CK_FUNCTION_LIST_PTR) &sftk_funcList;
  2206     return CKR_OK;
  2209 /* return the function list */
  2210 CK_RV C_GetFunctionList(CK_FUNCTION_LIST_PTR *pFunctionList)
  2212     CHECK_FORK();
  2214     return NSC_GetFunctionList(pFunctionList);
  2217 static PLHashNumber
  2218 sftk_HashNumber(const void *key)
  2220     return (PLHashNumber) key;
  2223 /*
  2224  * eventually I'd like to expunge all occurances of XXX_SLOT_ID and
  2225  * just go with the info in the slot. This is one place, however,
  2226  * where it might be a little difficult.
  2227  */
  2228 const char *
  2229 sftk_getDefTokName(CK_SLOT_ID slotID)
  2231     static char buf[33];
  2233     switch (slotID) {
  2234     case NETSCAPE_SLOT_ID:
  2235 	return "NSS Generic Crypto Services     ";
  2236     case PRIVATE_KEY_SLOT_ID:
  2237 	return "NSS Certificate DB              ";
  2238     case FIPS_SLOT_ID:
  2239         return "NSS FIPS 140-2 Certificate DB   ";
  2240     default:
  2241 	break;
  2243     sprintf(buf,"NSS Application Token %08x  ",(unsigned int) slotID);
  2244     return buf;
  2247 const char *
  2248 sftk_getDefSlotName(CK_SLOT_ID slotID)
  2250     static char buf[65];
  2252     switch (slotID) {
  2253     case NETSCAPE_SLOT_ID:
  2254 	return 
  2255 	 "NSS Internal Cryptographic Services                             ";
  2256     case PRIVATE_KEY_SLOT_ID:
  2257 	return 
  2258 	 "NSS User Private Key and Certificate Services                   ";
  2259     case FIPS_SLOT_ID:
  2260         return 
  2261          "NSS FIPS 140-2 User Private Key Services                        ";
  2262     default:
  2263 	break;
  2265     sprintf(buf,
  2266      "NSS Application Slot %08x                                   ",
  2267 							(unsigned int) slotID);
  2268     return buf;
  2271 static CK_ULONG nscSlotCount[2] = {0 , 0};
  2272 static CK_SLOT_ID_PTR nscSlotList[2] = {NULL, NULL};
  2273 static CK_ULONG nscSlotListSize[2] = {0, 0};
  2274 static PLHashTable *nscSlotHashTable[2] = {NULL, NULL};
  2276 static int
  2277 sftk_GetModuleIndex(CK_SLOT_ID slotID)
  2279     if ((slotID == FIPS_SLOT_ID) || (slotID >= SFTK_MIN_FIPS_USER_SLOT_ID)) {
  2280 	return NSC_FIPS_MODULE;
  2282     return NSC_NON_FIPS_MODULE;
  2285 /* look up a slot structure from the ID (used to be a macro when we only
  2286  * had two slots) */
  2287 /* if all is true, return the slot even if it has been 'unloaded' */
  2288 /* if all is false, only return the slots which are present */
  2289 SFTKSlot *
  2290 sftk_SlotFromID(CK_SLOT_ID slotID, PRBool all)
  2292     SFTKSlot *slot;
  2293     int index = sftk_GetModuleIndex(slotID);
  2295     if (nscSlotHashTable[index] == NULL) return NULL;
  2296     slot = (SFTKSlot *)PL_HashTableLookupConst(nscSlotHashTable[index], 
  2297 							(void *)slotID);
  2298     /* cleared slots shouldn't 'show up' */
  2299     if (slot && !all && !slot->present) slot = NULL;
  2300     return slot;
  2303 SFTKSlot *
  2304 sftk_SlotFromSessionHandle(CK_SESSION_HANDLE handle)
  2306     CK_ULONG slotIDIndex = (handle >> 24) & 0x7f;
  2307     CK_ULONG moduleIndex = (handle >> 31) & 1;
  2309     if (slotIDIndex >= nscSlotCount[moduleIndex]) {
  2310 	return NULL;
  2313     return sftk_SlotFromID(nscSlotList[moduleIndex][slotIDIndex], PR_FALSE);
  2316 static CK_RV
  2317 sftk_RegisterSlot(SFTKSlot *slot, int moduleIndex)
  2319     PLHashEntry *entry;
  2320     int index;
  2322     index = sftk_GetModuleIndex(slot->slotID);
  2324     /* make sure the slotID for this module is valid */
  2325     if (moduleIndex != index) {
  2326 	return CKR_SLOT_ID_INVALID;
  2329     if (nscSlotList[index] == NULL) {
  2330 	nscSlotListSize[index] = NSC_SLOT_LIST_BLOCK_SIZE;
  2331 	nscSlotList[index] = (CK_SLOT_ID *)
  2332 		PORT_ZAlloc(nscSlotListSize[index]*sizeof(CK_SLOT_ID));
  2333 	if (nscSlotList[index] == NULL) {
  2334 	    return CKR_HOST_MEMORY;
  2337     if (nscSlotCount[index] >= nscSlotListSize[index]) {
  2338 	CK_SLOT_ID* oldNscSlotList = nscSlotList[index];
  2339 	CK_ULONG oldNscSlotListSize = nscSlotListSize[index];
  2340 	nscSlotListSize[index] += NSC_SLOT_LIST_BLOCK_SIZE;
  2341 	nscSlotList[index] = (CK_SLOT_ID *) PORT_Realloc(oldNscSlotList,
  2342 				nscSlotListSize[index]*sizeof(CK_SLOT_ID));
  2343 	if (nscSlotList[index] == NULL) {
  2344             nscSlotList[index] = oldNscSlotList;
  2345             nscSlotListSize[index] = oldNscSlotListSize;
  2346             return CKR_HOST_MEMORY;
  2350     if (nscSlotHashTable[index] == NULL) {
  2351 	nscSlotHashTable[index] = PL_NewHashTable(64,sftk_HashNumber,
  2352 				PL_CompareValues, PL_CompareValues, NULL, 0);
  2353 	if (nscSlotHashTable[index] == NULL) {
  2354 	    return CKR_HOST_MEMORY;
  2358     entry = PL_HashTableAdd(nscSlotHashTable[index],(void *)slot->slotID,slot);
  2359     if (entry == NULL) {
  2360 	return CKR_HOST_MEMORY;
  2362     slot->index = (nscSlotCount[index] & 0x7f) | ((index << 7) & 0x80);
  2363     nscSlotList[index][nscSlotCount[index]++] = slot->slotID;
  2365     return CKR_OK;
  2369 /*
  2370  * ths function has all the common initialization that happens whenever we
  2371  * create a new slot or repurpose an old slot (only valid for slotID's 4 
  2372  * and greater).
  2374  * things that are not reinitialized are:
  2375  *   slotID (can't change)
  2376  *   slotDescription (can't change once defined) 
  2377  *   the locks and hash tables (difficult to change in running code, and
  2378  *     unnecessary. hash tables and list are cleared on shutdown, but they
  2379  *     are cleared in a 'friendly' way).
  2380  *   session and object ID counters -- so any old sessions and objects in the
  2381  *     application will get properly notified that the world has changed.
  2383  * things that are reinitialized:
  2384  *   database (otherwise what would the point be;).
  2385  *   state variables related to databases.
  2386  *   session count stat info.
  2387  *   tokenDescription.
  2389  * NOTE: slotID's 4 and greater show up as removable devices.
  2391  */
  2392 CK_RV
  2393 SFTK_SlotReInit(SFTKSlot *slot, char *configdir, char *updatedir, 
  2394 	char *updateID, sftk_token_parameters *params, int moduleIndex)
  2396     PRBool needLogin = !params->noKeyDB;
  2397     CK_RV crv;
  2399     slot->hasTokens = PR_FALSE;
  2400     slot->sessionIDConflict = 0;
  2401     slot->sessionCount = 0;
  2402     slot->rwSessionCount = 0;
  2403     slot->needLogin = PR_FALSE;
  2404     slot->isLoggedIn = PR_FALSE;
  2405     slot->ssoLoggedIn = PR_FALSE;
  2406     slot->DB_loaded = PR_FALSE;
  2407     slot->certDB = NULL;
  2408     slot->keyDB = NULL;
  2409     slot->minimumPinLen = 0;
  2410     slot->readOnly = params->readOnly;
  2411     sftk_setStringName(params->tokdes ? params->tokdes : 
  2412 	sftk_getDefTokName(slot->slotID), slot->tokDescription, 
  2413 					sizeof(slot->tokDescription),PR_TRUE);
  2414     sftk_setStringName(params->updtokdes ? params->updtokdes : " ", 
  2415 				slot->updateTokDescription, 
  2416 				sizeof(slot->updateTokDescription),PR_TRUE);
  2418     if ((!params->noCertDB) || (!params->noKeyDB)) {
  2419 	SFTKDBHandle * certHandle = NULL;
  2420 	SFTKDBHandle *keyHandle = NULL;
  2421 	crv = sftk_DBInit(params->configdir ? params->configdir : configdir,
  2422 		params->certPrefix, params->keyPrefix, 
  2423 		params->updatedir ? params->updatedir : updatedir,
  2424 		params->updCertPrefix, params->updKeyPrefix,
  2425 		params->updateID  ? params->updateID : updateID, 
  2426 		params->readOnly, params->noCertDB, params->noKeyDB,
  2427 		params->forceOpen, 
  2428 		moduleIndex == NSC_FIPS_MODULE,
  2429 		&certHandle, &keyHandle);
  2430 	if (crv != CKR_OK) {
  2431 	    goto loser;
  2434 	slot->certDB = certHandle;
  2435 	slot->keyDB = keyHandle;
  2437     if (needLogin) {
  2438 	/* if the data base is initialized with a null password,remember that */
  2439 	slot->needLogin = 
  2440 		(PRBool)!sftk_hasNullPassword(slot, slot->keyDB);
  2441 	if ((params->minPW >= 0) && (params->minPW <= SFTK_MAX_PIN)) {
  2442 	    slot->minimumPinLen = params->minPW;
  2444 	if ((slot->minimumPinLen == 0) && (params->pwRequired)) {
  2445 	    slot->minimumPinLen = 1;
  2447 	if ((moduleIndex == NSC_FIPS_MODULE) &&
  2448 		(slot->minimumPinLen < FIPS_MIN_PIN)) {
  2449 	    slot->minimumPinLen = FIPS_MIN_PIN;
  2453     slot->present = PR_TRUE;
  2454     return CKR_OK;
  2456 loser:
  2457     SFTK_ShutdownSlot(slot);
  2458     return crv;
  2461 /*
  2462  * initialize one of the slot structures. figure out which by the ID
  2463  */
  2464 CK_RV
  2465 SFTK_SlotInit(char *configdir, char *updatedir, char *updateID,
  2466 		sftk_token_parameters *params, int moduleIndex)
  2468     unsigned int i;
  2469     CK_SLOT_ID slotID = params->slotID;
  2470     SFTKSlot *slot;
  2471     CK_RV crv = CKR_HOST_MEMORY;
  2473     /*
  2474      * first we initialize everything that is 'permanent' with this slot.
  2475      * that is everything we aren't going to shutdown if we close this slot
  2476      * and open it up again with different databases */
  2478     slot = PORT_ZNew(SFTKSlot);
  2480     if (slot == NULL) {
  2481 	return CKR_HOST_MEMORY;
  2484     slot->optimizeSpace = params->optimizeSpace;
  2485     if (slot->optimizeSpace) {
  2486 	slot->sessObjHashSize = SPACE_SESSION_OBJECT_HASH_SIZE;
  2487 	slot->sessHashSize = SPACE_SESSION_HASH_SIZE;
  2488 	slot->numSessionLocks = 1;
  2489     } else {
  2490 	slot->sessObjHashSize = TIME_SESSION_OBJECT_HASH_SIZE;
  2491 	slot->sessHashSize = TIME_SESSION_HASH_SIZE;
  2492 	slot->numSessionLocks = slot->sessHashSize/BUCKETS_PER_SESSION_LOCK;
  2494     slot->sessionLockMask = slot->numSessionLocks-1;
  2496     slot->slotLock = PZ_NewLock(nssILockSession);
  2497     if (slot->slotLock == NULL)
  2498 	goto mem_loser;
  2499     slot->sessionLock = PORT_ZNewArray(PZLock *, slot->numSessionLocks);
  2500     if (slot->sessionLock == NULL)
  2501 	goto mem_loser;
  2502     for (i=0; i < slot->numSessionLocks; i++) {
  2503         slot->sessionLock[i] = PZ_NewLock(nssILockSession);
  2504         if (slot->sessionLock[i] == NULL) 
  2505 	    goto mem_loser;
  2507     slot->objectLock = PZ_NewLock(nssILockObject);
  2508     if (slot->objectLock == NULL) 
  2509     	goto mem_loser;
  2510     slot->pwCheckLock = PR_NewLock();
  2511     if (slot->pwCheckLock == NULL) 
  2512     	goto mem_loser;
  2513     slot->head = PORT_ZNewArray(SFTKSession *, slot->sessHashSize);
  2514     if (slot->head == NULL) 
  2515 	goto mem_loser;
  2516     slot->sessObjHashTable = PORT_ZNewArray(SFTKObject *, slot->sessObjHashSize);
  2517     if (slot->sessObjHashTable == NULL) 
  2518 	goto mem_loser;
  2519     slot->tokObjHashTable = PL_NewHashTable(64,sftk_HashNumber,PL_CompareValues,
  2520 					SECITEM_HashCompare, NULL, 0);
  2521     if (slot->tokObjHashTable == NULL) 
  2522 	goto mem_loser;
  2524     slot->sessionIDCount = 0;
  2525     slot->sessionObjectHandleCount = minSessionObjectHandle;
  2526     slot->slotID = slotID;
  2527     sftk_setStringName(params->slotdes ? params->slotdes : 
  2528 	      sftk_getDefSlotName(slotID), slot->slotDescription, 
  2529 					sizeof(slot->slotDescription), PR_TRUE);
  2531     /* call the reinit code to set everything that changes between token
  2532      * init calls */
  2533     crv = SFTK_SlotReInit(slot, configdir, updatedir, updateID,
  2534 			   params, moduleIndex);
  2535     if (crv != CKR_OK) {
  2536 	goto loser;
  2538     crv = sftk_RegisterSlot(slot, moduleIndex);
  2539     if (crv != CKR_OK) {
  2540 	goto loser;
  2542     return CKR_OK;
  2544 mem_loser:
  2545     crv = CKR_HOST_MEMORY;
  2546 loser:
  2547    SFTK_DestroySlotData(slot);
  2548     return crv;
  2552 CK_RV sftk_CloseAllSessions(SFTKSlot *slot, PRBool logout)
  2554     SFTKSession *session;
  2555     unsigned int i;
  2556     SFTKDBHandle *handle;
  2558     /* first log out the card */
  2559     /* special case - if we are in a middle of upgrade, we want to close the
  2560      * sessions to fake a token removal to tell the upper level code we have
  2561      * switched from one database to another, but we don't want to 
  2562      * explicity logout in case we can continue the upgrade with the 
  2563       * existing password if possible.
  2564      */
  2565     if (logout) {
  2566 	handle = sftk_getKeyDB(slot);
  2567 	SKIP_AFTER_FORK(PZ_Lock(slot->slotLock));
  2568 	slot->isLoggedIn = PR_FALSE;
  2569 	if (slot->needLogin && handle) {
  2570 	    sftkdb_ClearPassword(handle);
  2572 	SKIP_AFTER_FORK(PZ_Unlock(slot->slotLock));
  2573 	if (handle) {
  2574             sftk_freeDB(handle);
  2578     /* now close all the current sessions */
  2579     /* NOTE: If you try to open new sessions before NSC_CloseAllSessions
  2580      * completes, some of those new sessions may or may not be closed by
  2581      * NSC_CloseAllSessions... but any session running when this code starts
  2582      * will guarrenteed be close, and no session will be partially closed */
  2583     for (i=0; i < slot->sessHashSize; i++) {
  2584 	PZLock *lock = SFTK_SESSION_LOCK(slot,i);
  2585 	do {
  2586 	    SKIP_AFTER_FORK(PZ_Lock(lock));
  2587 	    session = slot->head[i];
  2588 	    /* hand deque */
  2589 	    /* this duplicates function of NSC_close session functions, but 
  2590 	     * because we know that we are freeing all the sessions, we can
  2591 	     * do more efficient processing */
  2592 	    if (session) {
  2593 		slot->head[i] = session->next;
  2594 		if (session->next) session->next->prev = NULL;
  2595 		session->next = session->prev = NULL;
  2596 		SKIP_AFTER_FORK(PZ_Unlock(lock));
  2597 		SKIP_AFTER_FORK(PZ_Lock(slot->slotLock));
  2598 		--slot->sessionCount;
  2599 		SKIP_AFTER_FORK(PZ_Unlock(slot->slotLock));
  2600 		if (session->info.flags & CKF_RW_SESSION) {
  2601 		    PR_ATOMIC_DECREMENT(&slot->rwSessionCount);
  2603 	    } else {
  2604 		SKIP_AFTER_FORK(PZ_Unlock(lock));
  2606 	    if (session) sftk_FreeSession(session);
  2607 	} while (session != NULL);
  2609     return CKR_OK;
  2612 /*
  2613  * shut down the databases.
  2614  * we get the slot lock (which also protects slot->certDB and slot->keyDB)
  2615  * and clear the values so the new users will not find the databases.
  2616  * once things are clear, we can release our references to the databases.
  2617  * The databases will close when the last reference is released.
  2619  * We use reference counts so that we don't crash if someone shuts down
  2620  * a token that another thread is actively using.
  2621  */
  2622 static void
  2623 sftk_DBShutdown(SFTKSlot *slot)
  2625     SFTKDBHandle *certHandle;
  2626     SFTKDBHandle      *keyHandle;
  2627     SKIP_AFTER_FORK(PZ_Lock(slot->slotLock));
  2628     certHandle = slot->certDB;
  2629     slot->certDB = NULL;
  2630     keyHandle = slot->keyDB;
  2631     slot->keyDB = NULL;
  2632     SKIP_AFTER_FORK(PZ_Unlock(slot->slotLock));
  2633     if (certHandle) {
  2634 	sftk_freeDB(certHandle);
  2636     if (keyHandle) {
  2637 	sftk_freeDB(keyHandle);
  2641 CK_RV
  2642 SFTK_ShutdownSlot(SFTKSlot *slot)
  2644     /* make sure no new PK11 calls work except C_GetSlotInfo */
  2645     slot->present = PR_FALSE;
  2647     /* close all outstanding sessions
  2648      * the sessHashSize variable guarentees we have all the session
  2649      * mechanism set up */
  2650     if (slot->head) {
  2651 	sftk_CloseAllSessions(slot, PR_TRUE);
  2654     /* clear all objects.. session objects are cleared as a result of
  2655      * closing all the sessions. We just need to clear the token object
  2656      * cache. slot->tokObjHashTable guarentees we have the token 
  2657      * infrastructure set up. */
  2658     if (slot->tokObjHashTable) {
  2659 	SFTK_ClearTokenKeyHashTable(slot);
  2662     /* clear the slot description for the next guy */
  2663     PORT_Memset(slot->tokDescription, 0, sizeof(slot->tokDescription));
  2665     /* now shut down the databases. */
  2666     sftk_DBShutdown(slot);
  2667     return CKR_OK;
  2670 /*
  2671  * initialize one of the slot structures. figure out which by the ID
  2672  */
  2673 CK_RV
  2674 SFTK_DestroySlotData(SFTKSlot *slot)
  2676     unsigned int i;
  2678     SFTK_ShutdownSlot(slot);
  2680     if (slot->tokObjHashTable) {
  2681 	PL_HashTableDestroy(slot->tokObjHashTable);
  2682 	slot->tokObjHashTable = NULL;
  2685     if (slot->sessObjHashTable) {
  2686 	PORT_Free(slot->sessObjHashTable);
  2687 	slot->sessObjHashTable = NULL;
  2689     slot->sessObjHashSize = 0;
  2691     if (slot->head) {
  2692 	PORT_Free(slot->head);
  2693 	slot->head = NULL;
  2695     slot->sessHashSize = 0;
  2697     /* OK everything has been disassembled, now we can finally get rid
  2698      * of the locks */
  2699     SKIP_AFTER_FORK(PZ_DestroyLock(slot->slotLock));
  2700     slot->slotLock = NULL;
  2701     if (slot->sessionLock) {
  2702 	for (i=0; i < slot->numSessionLocks; i++) {
  2703 	    if (slot->sessionLock[i]) {
  2704 		SKIP_AFTER_FORK(PZ_DestroyLock(slot->sessionLock[i]));
  2705 		slot->sessionLock[i] = NULL;
  2708 	PORT_Free(slot->sessionLock);
  2709 	slot->sessionLock = NULL;
  2711     if (slot->objectLock) {
  2712 	SKIP_AFTER_FORK(PZ_DestroyLock(slot->objectLock));
  2713 	slot->objectLock = NULL;
  2715     if (slot->pwCheckLock) {
  2716 	SKIP_AFTER_FORK(PR_DestroyLock(slot->pwCheckLock));
  2717 	slot->pwCheckLock = NULL;
  2719     PORT_Free(slot);
  2720     return CKR_OK;
  2723 /*
  2724  * handle the SECMOD.db
  2725  */
  2726 char **
  2727 NSC_ModuleDBFunc(unsigned long function,char *parameters, void *args)
  2729     char *secmod = NULL;
  2730     char *appName = NULL;
  2731     char *filename = NULL;
  2732     NSSDBType dbType = NSS_DB_TYPE_NONE;
  2733     PRBool rw;
  2734     static char *success="Success";
  2735     char **rvstr = NULL;
  2737     rvstr = NSSUTIL_DoModuleDBFunction(function, parameters, args);
  2738     if (rvstr != NULL) {
  2739 	return rvstr;
  2742     if (PORT_GetError() != SEC_ERROR_LEGACY_DATABASE) {
  2743 	return NULL;
  2746    /* The legacy database uses the old dbm, which is only linked with the 
  2747     * legacy DB handler, which is only callable from softoken */
  2749     secmod = _NSSUTIL_GetSecmodName(parameters, &dbType, &appName,
  2750 				    &filename, &rw);
  2752     switch (function) {
  2753     case SECMOD_MODULE_DB_FUNCTION_FIND:
  2754 	if (secmod == NULL) {
  2755 	    PORT_SetError(SEC_ERROR_INVALID_ARGS);
  2756 	    return NULL;
  2758 	if (rw && (dbType != NSS_DB_TYPE_LEGACY) && 
  2759 	    (dbType != NSS_DB_TYPE_MULTIACCESS)) {
  2760 	    /* if we get here, we are trying to update the local database */
  2761 	    /* force data from the legacy DB */
  2762 	    char *oldSecmod = NULL;
  2763 	    char *oldAppName = NULL;
  2764 	    char *oldFilename = NULL;
  2765 	    PRBool oldrw;
  2766 	    char **strings = NULL;
  2767 	    int i;
  2769 	    dbType = NSS_DB_TYPE_LEGACY;
  2770 	    oldSecmod = _NSSUTIL_GetSecmodName(parameters,&dbType, &oldAppName,
  2771 					    &oldFilename, &oldrw);
  2772 	    strings = sftkdbCall_ReadSecmodDB(appName, oldFilename, oldSecmod,
  2773 					(char *)parameters, oldrw);
  2774 	    if (strings) {
  2775 		/* write out the strings */
  2776 		for (i=0; strings[i]; i++) {
  2777 		    NSSUTIL_DoModuleDBFunction(SECMOD_MODULE_DB_FUNCTION_ADD,
  2778 				parameters, strings[i]);
  2780 		sftkdbCall_ReleaseSecmodDBData(oldAppName,oldFilename,oldSecmod,
  2781 			(char **)strings,oldrw);
  2782 	    } else {
  2783 		/* write out a dummy record */
  2784 		NSSUTIL_DoModuleDBFunction(SECMOD_MODULE_DB_FUNCTION_ADD,
  2785 				parameters, " ");
  2787 	    if (oldSecmod) { PR_smprintf_free(oldSecmod); }
  2788 	    if (oldAppName) { PORT_Free(oldAppName); }
  2789 	    if (oldFilename) { PORT_Free(oldFilename); }
  2790 	    rvstr = NSSUTIL_DoModuleDBFunction(function, parameters, args);
  2791 	    break;
  2793 	rvstr = sftkdbCall_ReadSecmodDB(appName,filename,secmod,
  2794 					(char *)parameters,rw);
  2795 	break;
  2796     case SECMOD_MODULE_DB_FUNCTION_ADD:
  2797 	if (secmod == NULL) {
  2798 	    PORT_SetError(SEC_ERROR_INVALID_ARGS);
  2799 	    return NULL;
  2801 	rvstr = (sftkdbCall_AddSecmodDB(appName,filename,secmod,
  2802 			(char *)args,rw) == SECSuccess) ? &success: NULL;
  2803 	break;
  2804     case SECMOD_MODULE_DB_FUNCTION_DEL:
  2805 	if (secmod == NULL) {
  2806 	    PORT_SetError(SEC_ERROR_INVALID_ARGS);
  2807 	    return NULL;
  2809 	rvstr = (sftkdbCall_DeleteSecmodDB(appName,filename,secmod,
  2810 			(char *)args,rw) == SECSuccess) ? &success: NULL;
  2811 	break;
  2812     case SECMOD_MODULE_DB_FUNCTION_RELEASE:
  2813 	rvstr = (sftkdbCall_ReleaseSecmodDBData(appName,filename,secmod,
  2814 			(char **)args,rw) == SECSuccess) ? &success: NULL;
  2815 	break;
  2817     if (secmod) PR_smprintf_free(secmod);
  2818     if (appName) PORT_Free(appName);
  2819     if (filename) PORT_Free(filename);
  2820     return rvstr;
  2823 static void nscFreeAllSlots(int moduleIndex)
  2825     /* free all the slots */
  2826     SFTKSlot *slot = NULL;
  2827     CK_SLOT_ID slotID;
  2828     int i;
  2830     if (nscSlotList[moduleIndex]) {
  2831 	CK_ULONG tmpSlotCount = nscSlotCount[moduleIndex];
  2832 	CK_SLOT_ID_PTR tmpSlotList = nscSlotList[moduleIndex];
  2833 	PLHashTable *tmpSlotHashTable = nscSlotHashTable[moduleIndex];
  2835 	/* first close all the session */
  2836 	for (i=0; i < (int) tmpSlotCount; i++) {
  2837 	    slotID = tmpSlotList[i];
  2838 	    (void) NSC_CloseAllSessions(slotID);
  2841 	/* now clear out the statics */
  2842 	nscSlotList[moduleIndex] = NULL;
  2843 	nscSlotCount[moduleIndex] = 0;
  2844 	nscSlotHashTable[moduleIndex] = NULL;
  2845 	nscSlotListSize[moduleIndex] = 0;
  2847 	for (i=0; i < (int) tmpSlotCount; i++) {
  2848 	    slotID = tmpSlotList[i];
  2849 	    slot = (SFTKSlot *)
  2850 			PL_HashTableLookup(tmpSlotHashTable, (void *)slotID);
  2851 	    PORT_Assert(slot);
  2852 	    if (!slot) continue;
  2853 	    SFTK_DestroySlotData(slot);
  2854 	    PL_HashTableRemove(tmpSlotHashTable, (void *)slotID);
  2856 	PORT_Free(tmpSlotList);
  2857 	PL_HashTableDestroy(tmpSlotHashTable);
  2861 static void
  2862 sftk_closePeer(PRBool isFIPS)
  2864     CK_SLOT_ID slotID = isFIPS ? PRIVATE_KEY_SLOT_ID: FIPS_SLOT_ID;
  2865     SFTKSlot *slot;
  2866     int moduleIndex = isFIPS? NSC_NON_FIPS_MODULE : NSC_FIPS_MODULE;
  2867     PLHashTable *tmpSlotHashTable = nscSlotHashTable[moduleIndex];
  2869     slot = (SFTKSlot *) PL_HashTableLookup(tmpSlotHashTable, (void *)slotID);
  2870     if (slot == NULL) {
  2871 	return;
  2873     sftk_DBShutdown(slot);
  2874     return;
  2877 /* NSC_Initialize initializes the Cryptoki library. */
  2878 CK_RV nsc_CommonInitialize(CK_VOID_PTR pReserved, PRBool isFIPS)
  2880     CK_RV crv = CKR_OK;
  2881     SECStatus rv;
  2882     CK_C_INITIALIZE_ARGS *init_args = (CK_C_INITIALIZE_ARGS *) pReserved;
  2883     int i;
  2884     int moduleIndex = isFIPS? NSC_FIPS_MODULE : NSC_NON_FIPS_MODULE;
  2886     if (isFIPS) {
  2887 	loginWaitTime = PR_SecondsToInterval(1);
  2890     ENABLE_FORK_CHECK();
  2892     rv = SECOID_Init();
  2893     if (rv != SECSuccess) {
  2894 	crv = CKR_DEVICE_ERROR;
  2895 	return crv;
  2898     rv = RNG_RNGInit();         /* initialize random number generator */
  2899     if (rv != SECSuccess) {
  2900 	crv = CKR_DEVICE_ERROR;
  2901 	return crv;
  2903     rv = BL_Init();             /* initialize freebl engine */
  2904     if (rv != SECSuccess) {
  2905 	crv = CKR_DEVICE_ERROR;
  2906 	return crv;
  2909     /* NOTE:
  2910      * we should be getting out mutexes from this list, not statically binding
  2911      * them from NSPR. This should happen before we allow the internal to split
  2912      * off from the rest on NSS.
  2913      */
  2915    /* initialize the key and cert db's */
  2916     if (init_args && (!(init_args->flags & CKF_OS_LOCKING_OK))) {
  2917         if (init_args->CreateMutex && init_args->DestroyMutex &&
  2918             init_args->LockMutex && init_args->UnlockMutex) {
  2919             /* softoken always uses NSPR (ie. OS locking), and doesn't know how
  2920              * to use the lock functions provided by the application.
  2921              */
  2922             crv = CKR_CANT_LOCK;
  2923             return crv;
  2925         if (init_args->CreateMutex || init_args->DestroyMutex ||
  2926             init_args->LockMutex || init_args->UnlockMutex) {
  2927             /* only some of the lock functions were provided by the
  2928              * application. This is invalid per PKCS#11 spec.
  2929              */
  2930             crv = CKR_ARGUMENTS_BAD;
  2931             return crv;
  2934     crv = CKR_ARGUMENTS_BAD;
  2935     if ((init_args && init_args->LibraryParameters)) {
  2936 	sftk_parameters paramStrings;
  2938 	crv = sftk_parseParameters
  2939 		((char *)init_args->LibraryParameters, &paramStrings, isFIPS);
  2940 	if (crv != CKR_OK) {
  2941 	    return crv;
  2943 	crv = sftk_configure(paramStrings.man, paramStrings.libdes);
  2944         if (crv != CKR_OK) {
  2945 	    goto loser;
  2948 	/* if we have a peer already open, have him close his DB's so we
  2949 	 * don't clobber each other. */
  2950 	if ((isFIPS && nsc_init) || (!isFIPS && nsf_init)) {
  2951 	    sftk_closePeer(isFIPS);
  2952 	    if (sftk_audit_enabled) {
  2953 		if (isFIPS && nsc_init) {
  2954 		    sftk_LogAuditMessage(NSS_AUDIT_INFO, NSS_AUDIT_FIPS_STATE, 
  2955 				"enabled FIPS mode");
  2956 		} else {
  2957 		    sftk_LogAuditMessage(NSS_AUDIT_INFO, NSS_AUDIT_FIPS_STATE, 
  2958 				"disabled FIPS mode");
  2963 	for (i=0; i < paramStrings.token_count; i++) {
  2964 	    crv = SFTK_SlotInit(paramStrings.configdir, 
  2965 			paramStrings.updatedir, paramStrings.updateID,
  2966 			&paramStrings.tokens[i], moduleIndex);
  2967 	    if (crv != CKR_OK) {
  2968                 nscFreeAllSlots(moduleIndex);
  2969                 break;
  2972 loser:
  2973 	sftk_freeParams(&paramStrings);
  2975     if (CKR_OK == crv) {
  2976         sftk_InitFreeLists();
  2979 #ifndef NO_FORK_CHECK
  2980     if (CKR_OK == crv) {
  2981 #if defined(CHECK_FORK_MIXED)
  2982         /* Before Solaris 10, fork handlers are not unregistered at dlclose()
  2983          * time. So, we only use pthread_atfork on Solaris 10 and later. For
  2984          * earlier versions, we use PID checks.
  2985          */
  2986         char buf[200];
  2987         int major = 0, minor = 0;
  2989         long rv = sysinfo(SI_RELEASE, buf, sizeof(buf));
  2990         if (rv > 0 && rv < sizeof(buf)) {
  2991             if (2 == sscanf(buf, "%d.%d", &major, &minor)) {
  2992                 /* Are we on Solaris 10 or greater ? */
  2993                 if (major >5 || (5 == major && minor >= 10)) {
  2994                     /* we are safe to use pthread_atfork */
  2995                     usePthread_atfork = PR_TRUE;
  2999         if (usePthread_atfork) {
  3000             pthread_atfork(NULL, NULL, ForkedChild);
  3001         } else {
  3002             myPid = getpid();
  3005 #elif defined(CHECK_FORK_PTHREAD)
  3006         pthread_atfork(NULL, NULL, ForkedChild);
  3007 #elif defined(CHECK_FORK_GETPID)
  3008         myPid = getpid();
  3009 #else
  3010 #error Incorrect fork check method.
  3011 #endif
  3013 #endif
  3014     return crv;
  3017 CK_RV NSC_Initialize(CK_VOID_PTR pReserved)
  3019     CK_RV crv;
  3021     sftk_ForkReset(pReserved, &crv);
  3023     if (nsc_init) {
  3024 	return CKR_CRYPTOKI_ALREADY_INITIALIZED;
  3026     crv = nsc_CommonInitialize(pReserved,PR_FALSE);
  3027     nsc_init = (PRBool) (crv == CKR_OK);
  3028     return crv;
  3032 /* NSC_Finalize indicates that an application is done with the 
  3033  * Cryptoki library.*/
  3034 CK_RV nsc_CommonFinalize (CK_VOID_PTR pReserved, PRBool isFIPS)
  3036     /* propagate the fork status to freebl and util */
  3037     BL_SetForkState(parentForkedAfterC_Initialize);
  3038     UTIL_SetForkState(parentForkedAfterC_Initialize);
  3040     nscFreeAllSlots(isFIPS ? NSC_FIPS_MODULE : NSC_NON_FIPS_MODULE);
  3042     /* don't muck with the globals if our peer is still initialized */
  3043     if (isFIPS && nsc_init) {
  3044 	return CKR_OK;
  3046     if (!isFIPS && nsf_init) {
  3047 	return CKR_OK;
  3050     sftk_CleanupFreeLists();
  3051     sftkdb_Shutdown();
  3053     /* This function does not discard all our previously aquired entropy. */
  3054     RNG_RNGShutdown();
  3056     /* tell freeBL to clean up after itself */
  3057     BL_Cleanup();
  3059     /* reset fork status in freebl. We must do this before BL_Unload so that
  3060      * this call doesn't force freebl to be reloaded. */
  3061     BL_SetForkState(PR_FALSE);
  3063     /* unload freeBL shared library from memory. This may only decrement the
  3064      * OS refcount if it's been loaded multiple times, eg. by libssl */
  3065     BL_Unload();
  3067     /* clean up the default OID table */
  3068     SECOID_Shutdown();
  3070     /* reset fork status in util */
  3071     UTIL_SetForkState(PR_FALSE);
  3073     nsc_init = PR_FALSE;
  3075 #ifdef CHECK_FORK_MIXED
  3076     if (!usePthread_atfork) {
  3077         myPid = 0; /* allow CHECK_FORK in the next softoken initialization to
  3078                     * succeed */
  3079     } else {
  3080         forked = PR_FALSE; /* allow reinitialization */
  3082 #elif defined(CHECK_FORK_GETPID)
  3083     myPid = 0; /* allow reinitialization */
  3084 #elif defined (CHECK_FORK_PTHREAD)
  3085     forked = PR_FALSE; /* allow reinitialization */
  3086 #endif
  3087     return CKR_OK;
  3090 /* Hard-reset the entire softoken PKCS#11 module if the parent process forked
  3091  * while it was initialized. */
  3092 PRBool sftk_ForkReset(CK_VOID_PTR pReserved, CK_RV* crv)
  3094 #ifndef NO_FORK_CHECK
  3095     if (PARENT_FORKED()) {
  3096         parentForkedAfterC_Initialize = PR_TRUE;
  3097         if (nsc_init) {
  3098             /* finalize non-FIPS token */
  3099             *crv = nsc_CommonFinalize(pReserved, PR_FALSE);
  3100             PORT_Assert(CKR_OK == *crv);
  3101             nsc_init = (PRBool) !(*crv == CKR_OK);
  3103         if (nsf_init) {
  3104             /* finalize FIPS token */
  3105             *crv = nsc_CommonFinalize(pReserved, PR_TRUE);
  3106             PORT_Assert(CKR_OK == *crv);
  3107             nsf_init = (PRBool) !(*crv == CKR_OK);
  3109         parentForkedAfterC_Initialize = PR_FALSE;
  3110         return PR_TRUE;
  3112 #endif
  3113     return PR_FALSE;
  3116 /* NSC_Finalize indicates that an application is done with the 
  3117  * Cryptoki library.*/
  3118 CK_RV NSC_Finalize (CK_VOID_PTR pReserved)
  3120     CK_RV crv;
  3122     /* reset entire PKCS#11 module upon fork */
  3123     if (sftk_ForkReset(pReserved, &crv)) {
  3124         return crv;
  3127     if (!nsc_init) {
  3128         return CKR_OK;
  3131     crv = nsc_CommonFinalize (pReserved, PR_FALSE);
  3133     nsc_init = (PRBool) !(crv == CKR_OK);
  3135     return crv;
  3138 extern const char __nss_softokn_rcsid[];
  3139 extern const char __nss_softokn_sccsid[];
  3141 /* NSC_GetInfo returns general information about Cryptoki. */
  3142 CK_RV  NSC_GetInfo(CK_INFO_PTR pInfo)
  3144     volatile char c; /* force a reference that won't get optimized away */
  3146     CHECK_FORK();
  3148     c = __nss_softokn_rcsid[0] + __nss_softokn_sccsid[0]; 
  3149     pInfo->cryptokiVersion.major = 2;
  3150     pInfo->cryptokiVersion.minor = 20;
  3151     PORT_Memcpy(pInfo->manufacturerID,manufacturerID,32);
  3152     pInfo->libraryVersion.major = SOFTOKEN_VMAJOR;
  3153     pInfo->libraryVersion.minor = SOFTOKEN_VMINOR;
  3154     PORT_Memcpy(pInfo->libraryDescription,libraryDescription,32);
  3155     pInfo->flags = 0;
  3156     return CKR_OK;
  3160 /* NSC_GetSlotList obtains a list of slots in the system. */
  3161 CK_RV nsc_CommonGetSlotList(CK_BBOOL tokenPresent, 
  3162 	CK_SLOT_ID_PTR	pSlotList, CK_ULONG_PTR pulCount, int moduleIndex)
  3164     *pulCount = nscSlotCount[moduleIndex];
  3165     if (pSlotList != NULL) {
  3166 	PORT_Memcpy(pSlotList,nscSlotList[moduleIndex],
  3167 				nscSlotCount[moduleIndex]*sizeof(CK_SLOT_ID));
  3169     return CKR_OK;
  3172 /* NSC_GetSlotList obtains a list of slots in the system. */
  3173 CK_RV NSC_GetSlotList(CK_BBOOL tokenPresent,
  3174 	 		CK_SLOT_ID_PTR	pSlotList, CK_ULONG_PTR pulCount)
  3176     CHECK_FORK();
  3177     return nsc_CommonGetSlotList(tokenPresent, pSlotList, pulCount, 
  3178 							NSC_NON_FIPS_MODULE);
  3181 /* NSC_GetSlotInfo obtains information about a particular slot in the system. */
  3182 CK_RV NSC_GetSlotInfo(CK_SLOT_ID slotID, CK_SLOT_INFO_PTR pInfo)
  3184     SFTKSlot *slot = sftk_SlotFromID(slotID, PR_TRUE);
  3186     CHECK_FORK();
  3188     if (slot == NULL) return CKR_SLOT_ID_INVALID;
  3190     PORT_Memcpy(pInfo->manufacturerID,manufacturerID,
  3191 		sizeof(pInfo->manufacturerID));
  3192     PORT_Memcpy(pInfo->slotDescription,slot->slotDescription,
  3193 		sizeof(pInfo->slotDescription));
  3194     pInfo->flags = (slot->present) ? CKF_TOKEN_PRESENT : 0;
  3196     /* all user defined slots are defined as removable */
  3197     if (slotID >= SFTK_MIN_USER_SLOT_ID) {
  3198 	pInfo->flags |= CKF_REMOVABLE_DEVICE;
  3199     } else {
  3200 	/* In the case where we are doing a merge update, we need
  3201 	 * the DB slot to be removable so the token name can change
  3202 	 * appropriately. */
  3203 	SFTKDBHandle *handle = sftk_getKeyDB(slot);
  3204 	if (handle) { 
  3205 	    if (sftkdb_InUpdateMerge(handle)) {
  3206 		pInfo->flags |= CKF_REMOVABLE_DEVICE;
  3208             sftk_freeDB(handle);
  3212     /* ok we really should read it out of the keydb file. */
  3213     /* pInfo->hardwareVersion.major = NSSLOWKEY_DB_FILE_VERSION; */
  3214     pInfo->hardwareVersion.major = SOFTOKEN_VMAJOR;
  3215     pInfo->hardwareVersion.minor = SOFTOKEN_VMINOR;
  3216     pInfo->firmwareVersion.major = SOFTOKEN_VPATCH;
  3217     pInfo->firmwareVersion.minor = SOFTOKEN_VBUILD;
  3218     return CKR_OK;
  3221 /*
  3222  * check the current state of the 'needLogin' flag in case the database has
  3223  * been changed underneath us.
  3224  */
  3225 static PRBool
  3226 sftk_checkNeedLogin(SFTKSlot *slot, SFTKDBHandle *keyHandle)
  3228     if (sftkdb_PWCached(keyHandle) == SECSuccess) {
  3229 	return slot->needLogin;
  3231     slot->needLogin = (PRBool)!sftk_hasNullPassword(slot, keyHandle);
  3232     return (slot->needLogin);
  3235 static PRBool
  3236 sftk_isBlank(const char *s, int len)
  3238     int i;
  3239     for (i=0; i < len; i++) {
  3240 	if (s[i] != ' ') {
  3241 	    return PR_FALSE;
  3244     return PR_TRUE;
  3247 /* NSC_GetTokenInfo obtains information about a particular token in 
  3248  * the system. */
  3249 CK_RV NSC_GetTokenInfo(CK_SLOT_ID slotID,CK_TOKEN_INFO_PTR pInfo)
  3251     SFTKSlot *slot;
  3252     SFTKDBHandle *handle;
  3254     CHECK_FORK();
  3256     if (!nsc_init && !nsf_init) return CKR_CRYPTOKI_NOT_INITIALIZED;
  3257     slot = sftk_SlotFromID(slotID, PR_FALSE);
  3258     if (slot == NULL) return CKR_SLOT_ID_INVALID;
  3260     PORT_Memcpy(pInfo->manufacturerID,manufacturerID,32);
  3261     PORT_Memcpy(pInfo->model,"NSS 3           ",16);
  3262     PORT_Memcpy(pInfo->serialNumber,"0000000000000000",16);
  3263     PORT_Memcpy(pInfo->utcTime,"0000000000000000",16);
  3264     pInfo->ulMaxSessionCount = 0; /* arbitrarily large */
  3265     pInfo->ulSessionCount = slot->sessionCount;
  3266     pInfo->ulMaxRwSessionCount = 0; /* arbitarily large */
  3267     pInfo->ulRwSessionCount = slot->rwSessionCount;
  3268     pInfo->firmwareVersion.major = 0;
  3269     pInfo->firmwareVersion.minor = 0;
  3270     PORT_Memcpy(pInfo->label,slot->tokDescription,sizeof(pInfo->label));
  3271     handle = sftk_getKeyDB(slot);
  3272     pInfo->flags = CKF_RNG | CKF_DUAL_CRYPTO_OPERATIONS;
  3273     if (handle == NULL) {
  3274 	pInfo->flags |= CKF_WRITE_PROTECTED;
  3275 	pInfo->ulMaxPinLen = 0;
  3276 	pInfo->ulMinPinLen = 0;
  3277 	pInfo->ulTotalPublicMemory = 0;
  3278 	pInfo->ulFreePublicMemory = 0;
  3279 	pInfo->ulTotalPrivateMemory = 0;
  3280 	pInfo->ulFreePrivateMemory = 0;
  3281 	pInfo->hardwareVersion.major = 4;
  3282 	pInfo->hardwareVersion.minor = 0;
  3283     } else {
  3284 	/*
  3285 	 * we have three possible states which we may be in:
  3286 	 *   (1) No DB password has been initialized. This also means we
  3287 	 *   have no keys in the key db.
  3288 	 *   (2) Password initialized to NULL. This means we have keys, but
  3289 	 *   the user has chosen not use a password.
  3290 	 *   (3) Finally we have an initialized password whicn is not NULL, and
  3291 	 *   we will need to prompt for it.
  3292 	 */
  3293 	if (sftkdb_HasPasswordSet(handle) == SECFailure) {
  3294 	    pInfo->flags |= CKF_LOGIN_REQUIRED;
  3295 	} else if (!sftk_checkNeedLogin(slot,handle)) {
  3296 	    pInfo->flags |= CKF_USER_PIN_INITIALIZED;
  3297 	} else {
  3298 	    pInfo->flags |= CKF_LOGIN_REQUIRED | CKF_USER_PIN_INITIALIZED;
  3299 	/* 
  3300          * if we are doing a merge style update, and we need to get the password
  3301 	 * of our source database (the database we are updating from), make sure we
  3302          * return a token name that will match the database we are prompting for.
  3303 	 */
  3304 	if (sftkdb_NeedUpdateDBPassword(handle)) {
  3305 	    /* if we have an update tok description, use it. otherwise
  3306              * use the updateID for this database */
  3307 	    if (!sftk_isBlank(slot->updateTokDescription,
  3308 						sizeof(pInfo->label))) {
  3309 		PORT_Memcpy(pInfo->label,slot->updateTokDescription,
  3310 				sizeof(pInfo->label));
  3311 	    } else {
  3312 		/* build from updateID */
  3313 		const char *updateID = sftkdb_GetUpdateID(handle);
  3314 		if (updateID) {
  3315 		    sftk_setStringName(updateID, (char *)pInfo->label,
  3316 				 sizeof(pInfo->label), PR_FALSE);
  3321 	pInfo->ulMaxPinLen = SFTK_MAX_PIN;
  3322 	pInfo->ulMinPinLen = (CK_ULONG)slot->minimumPinLen;
  3323 	pInfo->ulTotalPublicMemory = 1;
  3324 	pInfo->ulFreePublicMemory = 1;
  3325 	pInfo->ulTotalPrivateMemory = 1;
  3326 	pInfo->ulFreePrivateMemory = 1;
  3327 #ifdef SHDB_FIXME
  3328 	pInfo->hardwareVersion.major = CERT_DB_FILE_VERSION;
  3329 	pInfo->hardwareVersion.minor = handle->version;
  3330 #else
  3331 	pInfo->hardwareVersion.major = 0;
  3332 	pInfo->hardwareVersion.minor = 0;
  3333 #endif
  3334         sftk_freeDB(handle);
  3336     /*
  3337      * CKF_LOGIN_REQUIRED CKF_USER_PIN_INITIALIZED  how CKF_TOKEN_INITIALIZED
  3338      *                                              should be set
  3339      *         0                   0                           1
  3340      *         1                   0                           0
  3341      *         0                   1                           1
  3342      *         1                   1                           1
  3343      */
  3344     if (!(pInfo->flags & CKF_LOGIN_REQUIRED) ||
  3345 	(pInfo->flags & CKF_USER_PIN_INITIALIZED)) {
  3346 	pInfo->flags |= CKF_TOKEN_INITIALIZED;
  3348     return CKR_OK;
  3351 /* NSC_GetMechanismList obtains a list of mechanism types 
  3352  * supported by a token. */
  3353 CK_RV NSC_GetMechanismList(CK_SLOT_ID slotID,
  3354 	CK_MECHANISM_TYPE_PTR pMechanismList, CK_ULONG_PTR pulCount)
  3356     CK_ULONG i;
  3358     CHECK_FORK();
  3360     switch (slotID) {
  3361     /* default: */
  3362     case NETSCAPE_SLOT_ID:
  3363 	*pulCount = mechanismCount;
  3364 	if (pMechanismList != NULL) {
  3365 	    for (i=0; i < mechanismCount; i++) {
  3366 		pMechanismList[i] = mechanisms[i].type;
  3369 	break;
  3370      default:
  3371 	*pulCount = 0;
  3372 	for (i=0; i < mechanismCount; i++) {
  3373 	    if (mechanisms[i].privkey) {
  3374 		(*pulCount)++;
  3375 		if (pMechanismList != NULL) {
  3376 		    *pMechanismList++ = mechanisms[i].type;
  3380 	break;
  3382     return CKR_OK;
  3386 /* NSC_GetMechanismInfo obtains information about a particular mechanism 
  3387  * possibly supported by a token. */
  3388 CK_RV NSC_GetMechanismInfo(CK_SLOT_ID slotID, CK_MECHANISM_TYPE type,
  3389     					CK_MECHANISM_INFO_PTR pInfo)
  3391     PRBool isPrivateKey;
  3392     CK_ULONG i;
  3394     CHECK_FORK();
  3396     switch (slotID) {
  3397     case NETSCAPE_SLOT_ID:
  3398 	isPrivateKey = PR_FALSE;
  3399 	break;
  3400     default:
  3401 	isPrivateKey = PR_TRUE;
  3402 	break;
  3404     for (i=0; i < mechanismCount; i++) {
  3405         if (type == mechanisms[i].type) {
  3406 	    if (isPrivateKey && !mechanisms[i].privkey) {
  3407     		return CKR_MECHANISM_INVALID;
  3409 	    PORT_Memcpy(pInfo,&mechanisms[i].info, sizeof(CK_MECHANISM_INFO));
  3410 	    return CKR_OK;
  3413     return CKR_MECHANISM_INVALID;
  3416 CK_RV sftk_MechAllowsOperation(CK_MECHANISM_TYPE type, CK_ATTRIBUTE_TYPE op)
  3418     CK_ULONG i;
  3419     CK_FLAGS flags;
  3421     switch (op) {
  3422     case CKA_ENCRYPT:         flags = CKF_ENCRYPT;         break;
  3423     case CKA_DECRYPT:         flags = CKF_DECRYPT;         break;
  3424     case CKA_WRAP:            flags = CKF_WRAP;            break;
  3425     case CKA_UNWRAP:          flags = CKF_UNWRAP;          break;
  3426     case CKA_SIGN:            flags = CKF_SIGN;            break;
  3427     case CKA_SIGN_RECOVER:    flags = CKF_SIGN_RECOVER;    break;
  3428     case CKA_VERIFY:          flags = CKF_VERIFY;          break;
  3429     case CKA_VERIFY_RECOVER:  flags = CKF_VERIFY_RECOVER;  break;
  3430     case CKA_DERIVE:          flags = CKF_DERIVE;          break;
  3431     default:
  3432     	return CKR_ARGUMENTS_BAD;
  3434     for (i=0; i < mechanismCount; i++) {
  3435         if (type == mechanisms[i].type) {
  3436 	    return (flags & mechanisms[i].info.flags) ? CKR_OK 
  3437 	                                              : CKR_MECHANISM_INVALID;
  3440     return CKR_MECHANISM_INVALID;
  3443 /* NSC_InitToken initializes a token. */
  3444 CK_RV NSC_InitToken(CK_SLOT_ID slotID,CK_CHAR_PTR pPin,
  3445  				CK_ULONG ulPinLen,CK_CHAR_PTR pLabel) {
  3446     SFTKSlot *slot = sftk_SlotFromID(slotID, PR_FALSE);
  3447     SFTKDBHandle *handle;
  3448     SFTKDBHandle *certHandle;
  3449     SECStatus rv;
  3450     unsigned int i;
  3451     SFTKObject *object;
  3453     CHECK_FORK();
  3455     if (slot == NULL) return CKR_SLOT_ID_INVALID;
  3457     /* don't initialize the database if we aren't talking to a token
  3458      * that uses the key database.
  3459      */
  3460     if (slotID == NETSCAPE_SLOT_ID) {
  3461 	return CKR_TOKEN_WRITE_PROTECTED;
  3464     /* first, delete all our loaded key and cert objects from our 
  3465      * internal list. */
  3466     PZ_Lock(slot->objectLock);
  3467     for (i=0; i < slot->sessObjHashSize; i++) {
  3468 	do {
  3469 	    object = slot->sessObjHashTable[i];
  3470 	    /* hand deque */
  3471 	    /* this duplicates function of NSC_close session functions, but 
  3472 	     * because we know that we are freeing all the sessions, we can
  3473 	     * do more efficient processing */
  3474 	    if (object) {
  3475 		slot->sessObjHashTable[i] = object->next;
  3477 		if (object->next) object->next->prev = NULL;
  3478 		object->next = object->prev = NULL;
  3480 	    if (object) sftk_FreeObject(object);
  3481 	} while (object != NULL);
  3483     slot->DB_loaded = PR_FALSE;
  3484     PZ_Unlock(slot->objectLock);
  3486     /* then clear out the key database */
  3487     handle = sftk_getKeyDB(slot);
  3488     if (handle == NULL) {
  3489 	return CKR_TOKEN_WRITE_PROTECTED;
  3492     rv = sftkdb_ResetKeyDB(handle);
  3493     sftk_freeDB(handle);
  3494     if (rv != SECSuccess) {
  3495 	return CKR_DEVICE_ERROR;
  3498     /* finally  mark all the user certs as non-user certs */
  3499     certHandle = sftk_getCertDB(slot);
  3500     if (certHandle == NULL) return CKR_OK;
  3502     sftk_freeDB(certHandle);
  3504     return CKR_OK; /*is this the right function for not implemented*/
  3508 /* NSC_InitPIN initializes the normal user's PIN. */
  3509 CK_RV NSC_InitPIN(CK_SESSION_HANDLE hSession,
  3510     					CK_CHAR_PTR pPin, CK_ULONG ulPinLen)
  3512     SFTKSession *sp = NULL;
  3513     SFTKSlot *slot;
  3514     SFTKDBHandle *handle = NULL;
  3515     char newPinStr[SFTK_MAX_PIN+1];
  3516     SECStatus rv;
  3517     CK_RV crv = CKR_SESSION_HANDLE_INVALID;
  3518     PRBool tokenRemoved = PR_FALSE;
  3520     CHECK_FORK();
  3522     sp = sftk_SessionFromHandle(hSession);
  3523     if (sp == NULL) {
  3524 	goto loser;
  3527     slot = sftk_SlotFromSession(sp);
  3528     if (slot == NULL) {
  3529 	goto loser;
  3532     handle = sftk_getKeyDB(slot);
  3533     if (handle == NULL) {
  3534 	crv = CKR_PIN_LEN_RANGE;
  3535 	goto loser;
  3539     if (sp->info.state != CKS_RW_SO_FUNCTIONS) {
  3540 	crv = CKR_USER_NOT_LOGGED_IN;
  3541 	goto loser;
  3544     sftk_FreeSession(sp);
  3545     sp = NULL;
  3547     /* make sure the pins aren't too long */
  3548     if (ulPinLen > SFTK_MAX_PIN) {
  3549 	crv = CKR_PIN_LEN_RANGE;
  3550 	goto loser;
  3552     if (ulPinLen < (CK_ULONG)slot->minimumPinLen) {
  3553 	crv = CKR_PIN_LEN_RANGE;
  3554 	goto loser;
  3557     if (sftkdb_HasPasswordSet(handle) != SECFailure) {
  3558 	crv = CKR_DEVICE_ERROR;
  3559 	goto loser;
  3562     /* convert to null terminated string */
  3563     PORT_Memcpy(newPinStr, pPin, ulPinLen);
  3564     newPinStr[ulPinLen] = 0; 
  3566     /* build the hashed pins which we pass around */
  3568     /* change the data base */
  3569     rv = sftkdb_ChangePassword(handle, NULL, newPinStr, &tokenRemoved);
  3570     if (tokenRemoved) {
  3571 	sftk_CloseAllSessions(slot, PR_FALSE);
  3573     sftk_freeDB(handle);
  3574     handle = NULL;
  3576     /* Now update our local copy of the pin */
  3577     if (rv == SECSuccess) {
  3578 	if (ulPinLen == 0) slot->needLogin = PR_FALSE;
  3579 	return CKR_OK;
  3581     crv = CKR_PIN_INCORRECT;
  3583 loser:
  3584     if (sp) {
  3585 	sftk_FreeSession(sp);
  3587     if (handle) {
  3588 	sftk_freeDB(handle);
  3590     return crv;
  3594 /* NSC_SetPIN modifies the PIN of user that is currently logged in. */
  3595 /* NOTE: This is only valid for the PRIVATE_KEY_SLOT */
  3596 CK_RV NSC_SetPIN(CK_SESSION_HANDLE hSession, CK_CHAR_PTR pOldPin,
  3597     CK_ULONG ulOldLen, CK_CHAR_PTR pNewPin, CK_ULONG ulNewLen)
  3599     SFTKSession *sp = NULL;
  3600     SFTKSlot *slot;
  3601     SFTKDBHandle *handle = NULL;
  3602     char newPinStr[SFTK_MAX_PIN+1],oldPinStr[SFTK_MAX_PIN+1];
  3603     SECStatus rv;
  3604     CK_RV crv = CKR_SESSION_HANDLE_INVALID;
  3605     PRBool tokenRemoved = PR_FALSE;
  3607     CHECK_FORK();
  3609     sp = sftk_SessionFromHandle(hSession);
  3610     if (sp == NULL) {
  3611 	goto loser;
  3614     slot = sftk_SlotFromSession(sp);
  3615     if (!slot) {
  3616 	goto loser;
  3619     handle = sftk_getKeyDB(slot);
  3620     if (handle == NULL) {
  3621 	sftk_FreeSession(sp);
  3622 	return CKR_PIN_LEN_RANGE; /* XXX FIXME wrong return value */
  3625     if (slot->needLogin && sp->info.state != CKS_RW_USER_FUNCTIONS) {
  3626 	crv = CKR_USER_NOT_LOGGED_IN;
  3627 	goto loser;
  3630     sftk_FreeSession(sp);
  3631     sp = NULL;
  3633     /* make sure the pins aren't too long */
  3634     if ((ulNewLen > SFTK_MAX_PIN) || (ulOldLen > SFTK_MAX_PIN)) {
  3635 	crv = CKR_PIN_LEN_RANGE;
  3636 	goto loser;
  3638     if (ulNewLen < (CK_ULONG)slot->minimumPinLen) {
  3639 	crv = CKR_PIN_LEN_RANGE;
  3640 	goto loser;
  3644     /* convert to null terminated string */
  3645     PORT_Memcpy(newPinStr,pNewPin,ulNewLen);
  3646     newPinStr[ulNewLen] = 0; 
  3647     PORT_Memcpy(oldPinStr,pOldPin,ulOldLen);
  3648     oldPinStr[ulOldLen] = 0; 
  3650     /* change the data base password */
  3651     PR_Lock(slot->pwCheckLock);
  3652     rv = sftkdb_ChangePassword(handle, oldPinStr, newPinStr, &tokenRemoved);
  3653     if (tokenRemoved) {
  3654 	sftk_CloseAllSessions(slot, PR_FALSE);
  3656     if ((rv != SECSuccess) && (slot->slotID == FIPS_SLOT_ID)) {
  3657 	PR_Sleep(loginWaitTime);
  3659     PR_Unlock(slot->pwCheckLock);
  3661     /* Now update our local copy of the pin */
  3662     if (rv == SECSuccess) {
  3663 	slot->needLogin = (PRBool)(ulNewLen != 0);
  3664         /* Reset login flags. */
  3665         if (ulNewLen == 0) {
  3666             PRBool tokenRemoved = PR_FALSE;
  3667             PZ_Lock(slot->slotLock);
  3668             slot->isLoggedIn = PR_FALSE;
  3669             slot->ssoLoggedIn = PR_FALSE;
  3670             PZ_Unlock(slot->slotLock);
  3672             rv = sftkdb_CheckPassword(handle, "", &tokenRemoved);
  3673             if (tokenRemoved) {
  3674                 sftk_CloseAllSessions(slot, PR_FALSE);
  3677         sftk_update_all_states(slot);
  3678         sftk_freeDB(handle);
  3679 	return CKR_OK;
  3681     crv = CKR_PIN_INCORRECT;
  3682 loser:
  3683     if (sp) {
  3684 	sftk_FreeSession(sp);
  3686     if (handle) {
  3687 	sftk_freeDB(handle);
  3689     return crv;
  3692 /* NSC_OpenSession opens a session between an application and a token. */
  3693 CK_RV NSC_OpenSession(CK_SLOT_ID slotID, CK_FLAGS flags,
  3694    CK_VOID_PTR pApplication,CK_NOTIFY Notify,CK_SESSION_HANDLE_PTR phSession)
  3696     SFTKSlot *slot;
  3697     CK_SESSION_HANDLE sessionID;
  3698     SFTKSession *session;
  3699     SFTKSession *sameID;
  3701     CHECK_FORK();
  3703     slot = sftk_SlotFromID(slotID, PR_FALSE);
  3704     if (slot == NULL) return CKR_SLOT_ID_INVALID;
  3706     /* new session (we only have serial sessions) */
  3707     session = sftk_NewSession(slotID, Notify, pApplication,
  3708 						 flags | CKF_SERIAL_SESSION);
  3709     if (session == NULL) return CKR_HOST_MEMORY;
  3711     if (slot->readOnly && (flags & CKF_RW_SESSION)) {
  3712 	/* NETSCAPE_SLOT_ID is Read ONLY */
  3713 	session->info.flags &= ~CKF_RW_SESSION;
  3715     PZ_Lock(slot->slotLock);
  3716     ++slot->sessionCount;
  3717     PZ_Unlock(slot->slotLock);
  3718     if (session->info.flags & CKF_RW_SESSION) {
  3719 	PR_ATOMIC_INCREMENT(&slot->rwSessionCount);
  3722     do {
  3723         PZLock *lock;
  3724         do {
  3725             sessionID = (PR_ATOMIC_INCREMENT(&slot->sessionIDCount) & 0xffffff)
  3726                         | (slot->index << 24);
  3727         } while (sessionID == CK_INVALID_HANDLE);
  3728         lock = SFTK_SESSION_LOCK(slot,sessionID);
  3729         PZ_Lock(lock);
  3730         sftkqueue_find(sameID, sessionID, slot->head, slot->sessHashSize);
  3731         if (sameID == NULL) {
  3732             session->handle = sessionID;
  3733             sftk_update_state(slot, session);
  3734             sftkqueue_add(session, sessionID, slot->head,slot->sessHashSize);
  3735         } else {
  3736             slot->sessionIDConflict++;  /* for debugging */
  3738         PZ_Unlock(lock);
  3739     } while (sameID != NULL);
  3741     *phSession = sessionID;
  3742     return CKR_OK;
  3746 /* NSC_CloseSession closes a session between an application and a token. */
  3747 CK_RV NSC_CloseSession(CK_SESSION_HANDLE hSession)
  3749     SFTKSlot *slot;
  3750     SFTKSession *session;
  3751     PRBool sessionFound;
  3752     PZLock *lock;
  3754     CHECK_FORK();
  3756     session = sftk_SessionFromHandle(hSession);
  3757     if (session == NULL) return CKR_SESSION_HANDLE_INVALID;
  3758     slot = sftk_SlotFromSession(session);
  3759     sessionFound = PR_FALSE;
  3761     /* lock */
  3762     lock = SFTK_SESSION_LOCK(slot,hSession);
  3763     PZ_Lock(lock);
  3764     if (sftkqueue_is_queued(session,hSession,slot->head,slot->sessHashSize)) {
  3765 	sessionFound = PR_TRUE;
  3766 	sftkqueue_delete(session,hSession,slot->head,slot->sessHashSize);
  3767 	session->refCount--; /* can't go to zero while we hold the reference */
  3768 	PORT_Assert(session->refCount > 0);
  3770     PZ_Unlock(lock);
  3772     if (sessionFound) {
  3773 	SFTKDBHandle *handle;
  3774 	handle = sftk_getKeyDB(slot);
  3775 	PZ_Lock(slot->slotLock);
  3776 	if (--slot->sessionCount == 0) {
  3777 	    slot->isLoggedIn = PR_FALSE;
  3778 	    if (slot->needLogin && handle) {
  3779 		sftkdb_ClearPassword(handle);
  3782 	PZ_Unlock(slot->slotLock);
  3783 	if (handle) {
  3784 	    sftk_freeDB(handle);
  3786 	if (session->info.flags & CKF_RW_SESSION) {
  3787 	    PR_ATOMIC_DECREMENT(&slot->rwSessionCount);
  3791     sftk_FreeSession(session);
  3792     return CKR_OK;
  3796 /* NSC_CloseAllSessions closes all sessions with a token. */
  3797 CK_RV NSC_CloseAllSessions (CK_SLOT_ID slotID)
  3799     SFTKSlot *slot;
  3801 #ifndef NO_FORK_CHECK
  3802     /* skip fork check if we are being called from C_Initialize or C_Finalize */
  3803     if (!parentForkedAfterC_Initialize) {
  3804         CHECK_FORK();
  3806 #endif
  3808     slot = sftk_SlotFromID(slotID, PR_FALSE);
  3809     if (slot == NULL) return CKR_SLOT_ID_INVALID;
  3811     return sftk_CloseAllSessions(slot, PR_TRUE);
  3816 /* NSC_GetSessionInfo obtains information about the session. */
  3817 CK_RV NSC_GetSessionInfo(CK_SESSION_HANDLE hSession,
  3818     						CK_SESSION_INFO_PTR pInfo)
  3820     SFTKSession *session;
  3822     CHECK_FORK();
  3824     session = sftk_SessionFromHandle(hSession);
  3825     if (session == NULL) return CKR_SESSION_HANDLE_INVALID;
  3827     PORT_Memcpy(pInfo,&session->info,sizeof(CK_SESSION_INFO));
  3828     sftk_FreeSession(session);
  3829     return CKR_OK;
  3832 /* NSC_Login logs a user into a token. */
  3833 CK_RV NSC_Login(CK_SESSION_HANDLE hSession, CK_USER_TYPE userType,
  3834 				    CK_CHAR_PTR pPin, CK_ULONG ulPinLen)
  3836     SFTKSlot *slot;
  3837     SFTKSession *session;
  3838     SFTKDBHandle *handle;
  3839     CK_FLAGS sessionFlags;
  3840     SECStatus rv;
  3841     CK_RV crv;
  3842     char pinStr[SFTK_MAX_PIN+1];
  3843     PRBool tokenRemoved = PR_FALSE;
  3845     CHECK_FORK();
  3847     /* get the slot */
  3848     slot = sftk_SlotFromSessionHandle(hSession);
  3849     if (slot == NULL) {
  3850 	return CKR_SESSION_HANDLE_INVALID;
  3853     /* make sure the session is valid */
  3854     session = sftk_SessionFromHandle(hSession);
  3855     if (session == NULL) {
  3856 	return CKR_SESSION_HANDLE_INVALID;
  3858     sessionFlags = session->info.flags;
  3859     sftk_FreeSession(session);
  3860     session = NULL;
  3862     /* can't log into the Netscape Slot */
  3863     if (slot->slotID == NETSCAPE_SLOT_ID) {
  3864 	 return CKR_USER_TYPE_INVALID;
  3867     if (slot->isLoggedIn) return CKR_USER_ALREADY_LOGGED_IN;
  3868     if (!slot->needLogin) {
  3869         return ulPinLen ? CKR_PIN_INCORRECT : CKR_OK;
  3871     slot->ssoLoggedIn = PR_FALSE;
  3873     if (ulPinLen > SFTK_MAX_PIN) return CKR_PIN_LEN_RANGE;
  3875     /* convert to null terminated string */
  3876     PORT_Memcpy(pinStr,pPin,ulPinLen);
  3877     pinStr[ulPinLen] = 0; 
  3879     handle = sftk_getKeyDB(slot);
  3880     if (handle == NULL) {
  3881 	 return CKR_USER_TYPE_INVALID;
  3884     /*
  3885      * Deal with bootstrap. We allow the SSO to login in with a NULL
  3886      * password if and only if we haven't initialized the KEY DB yet.
  3887      * We only allow this on a RW session.
  3888      */
  3889     rv = sftkdb_HasPasswordSet(handle);
  3890     if (rv == SECFailure) {
  3891 	/* allow SSO's to log in only if there is not password on the
  3892 	 * key database */
  3893 	if (((userType == CKU_SO) && (sessionFlags & CKF_RW_SESSION))
  3894 	    /* fips always needs to authenticate, even if there isn't a db */
  3895 					|| (slot->slotID == FIPS_SLOT_ID)) {
  3896 	    /* should this be a fixed password? */
  3897 	    if (ulPinLen == 0) {
  3898 		sftkdb_ClearPassword(handle);
  3899     		PZ_Lock(slot->slotLock);
  3900 		slot->isLoggedIn = PR_TRUE;
  3901 		slot->ssoLoggedIn = (PRBool)(userType == CKU_SO);
  3902 		PZ_Unlock(slot->slotLock);
  3903 		sftk_update_all_states(slot);
  3904 		crv = CKR_OK;
  3905 		goto done;
  3907 	    crv = CKR_PIN_INCORRECT;
  3908 	    goto done;
  3910 	crv = CKR_USER_TYPE_INVALID;
  3911 	goto done;
  3914     /* don't allow the SSO to log in if the user is already initialized */
  3915     if (userType != CKU_USER) { 
  3916 	crv = CKR_USER_TYPE_INVALID; 
  3917 	goto done;
  3921     /* build the hashed pins which we pass around */
  3922     PR_Lock(slot->pwCheckLock);
  3923     rv = sftkdb_CheckPassword(handle,pinStr, &tokenRemoved);
  3924     if (tokenRemoved) {
  3925 	sftk_CloseAllSessions(slot, PR_FALSE);
  3927     if ((rv != SECSuccess) && (slot->slotID == FIPS_SLOT_ID)) {
  3928 	PR_Sleep(loginWaitTime);
  3930     PR_Unlock(slot->pwCheckLock);
  3931     if (rv == SECSuccess) {
  3932 	PZ_Lock(slot->slotLock);
  3933 	/* make sure the login state matches the underlying
  3934 	 * database state */
  3935 	slot->isLoggedIn = sftkdb_PWCached(handle) == SECSuccess ?
  3936 		PR_TRUE : PR_FALSE;
  3937 	PZ_Unlock(slot->slotLock);
  3939  	sftk_freeDB(handle);
  3940 	handle = NULL;
  3942 	/* update all sessions */
  3943 	sftk_update_all_states(slot);
  3944 	return CKR_OK;
  3947     crv = CKR_PIN_INCORRECT;
  3948 done:
  3949     if (handle) {
  3950 	sftk_freeDB(handle);
  3952     return crv;
  3955 /* NSC_Logout logs a user out from a token. */
  3956 CK_RV NSC_Logout(CK_SESSION_HANDLE hSession)
  3958     SFTKSlot *slot = sftk_SlotFromSessionHandle(hSession);
  3959     SFTKSession *session;
  3960     SFTKDBHandle *handle;
  3962     CHECK_FORK();
  3964     if (slot == NULL) {
  3965 	return CKR_SESSION_HANDLE_INVALID;
  3967     session = sftk_SessionFromHandle(hSession);
  3968     if (session == NULL) return CKR_SESSION_HANDLE_INVALID;
  3969     sftk_FreeSession(session);
  3970     session = NULL;
  3972     if (!slot->isLoggedIn) return CKR_USER_NOT_LOGGED_IN;
  3974     handle = sftk_getKeyDB(slot);
  3975     PZ_Lock(slot->slotLock);
  3976     slot->isLoggedIn = PR_FALSE;
  3977     slot->ssoLoggedIn = PR_FALSE;
  3978     if (slot->needLogin && handle) {
  3979 	sftkdb_ClearPassword(handle);
  3981     PZ_Unlock(slot->slotLock);
  3982     if (handle) {
  3983 	sftk_freeDB(handle);
  3986     sftk_update_all_states(slot);
  3987     return CKR_OK;
  3990 /*
  3991  * Create or remove a new slot on the fly.
  3992  * When creating a slot, "slot" is the slot that the request came from. The
  3993  * resulting slot will live in the same module as "slot".
  3994  * When removing a slot, "slot" is the slot to be removed.
  3995  * "object" is the creation object that specifies the module spec for the slot
  3996  * to add or remove.
  3997  */
  3998 static CK_RV sftk_CreateNewSlot(SFTKSlot *slot, CK_OBJECT_CLASS class,
  3999                                 SFTKObject *object)
  4001     PRBool isValidUserSlot = PR_FALSE;
  4002     PRBool isValidFIPSUserSlot = PR_FALSE;
  4003     PRBool isValidSlot = PR_FALSE;
  4004     PRBool isFIPS = PR_FALSE;
  4005     unsigned long moduleIndex;
  4006     SFTKAttribute *attribute;
  4007     sftk_parameters paramStrings;
  4008     char *paramString;
  4009     CK_SLOT_ID slotID = 0;
  4010     SFTKSlot *newSlot = NULL;
  4011     CK_RV crv = CKR_OK;
  4013     if (class != CKO_NETSCAPE_DELSLOT && class != CKO_NETSCAPE_NEWSLOT) {
  4014 	return CKR_ATTRIBUTE_VALUE_INVALID;
  4016     if (class == CKO_NETSCAPE_NEWSLOT && slot->slotID == FIPS_SLOT_ID) {
  4017 	isFIPS = PR_TRUE;
  4019     attribute = sftk_FindAttribute(object, CKA_NETSCAPE_MODULE_SPEC);
  4020     if (attribute == NULL) {
  4021 	return CKR_TEMPLATE_INCOMPLETE;
  4023     paramString = (char *)attribute->attrib.pValue;
  4024     crv = sftk_parseParameters(paramString, &paramStrings, isFIPS);
  4025     if (crv != CKR_OK) {
  4026 	goto loser;
  4029     /* enforce only one at a time */
  4030     if (paramStrings.token_count != 1) {
  4031 	crv = CKR_ATTRIBUTE_VALUE_INVALID;
  4032 	goto loser;
  4035     slotID = paramStrings.tokens[0].slotID;
  4037     /* stay within the valid ID space */
  4038     isValidUserSlot = (slotID >= SFTK_MIN_USER_SLOT_ID &&
  4039                        slotID <= SFTK_MAX_USER_SLOT_ID);
  4040     isValidFIPSUserSlot = (slotID >= SFTK_MIN_FIPS_USER_SLOT_ID &&
  4041                            slotID <= SFTK_MAX_FIPS_USER_SLOT_ID);
  4043     if (class == CKO_NETSCAPE_DELSLOT) {
  4044 	if (slot->slotID == slotID) {
  4045 	    isValidSlot = isValidUserSlot || isValidFIPSUserSlot;
  4047     } else {
  4048 	/* only the crypto or FIPS slots can create new slot objects */
  4049 	if (slot->slotID == NETSCAPE_SLOT_ID) {
  4050 	    isValidSlot = isValidUserSlot;
  4051 	    moduleIndex = NSC_NON_FIPS_MODULE;
  4052 	} else if (slot->slotID == FIPS_SLOT_ID) {
  4053 	    isValidSlot = isValidFIPSUserSlot;
  4054 	    moduleIndex = NSC_FIPS_MODULE;
  4058     if (!isValidSlot) {
  4059 	crv = CKR_ATTRIBUTE_VALUE_INVALID;
  4060 	goto loser;
  4063     /* unload any existing slot at this id */
  4064     newSlot = sftk_SlotFromID(slotID, PR_TRUE);
  4065     if (newSlot && newSlot->present) {
  4066 	crv = SFTK_ShutdownSlot(newSlot);
  4067 	if (crv != CKR_OK) {
  4068 	    goto loser;
  4072     /* if we were just planning on deleting the slot, then do so now */
  4073     if (class == CKO_NETSCAPE_DELSLOT) {
  4074 	/* sort of a unconventional use of this error code, be we are
  4075 	 * overusing CKR_ATTRIBUTE_VALUE_INVALID, and it does apply */
  4076 	crv = newSlot ? CKR_OK : CKR_SLOT_ID_INVALID;
  4077 	goto loser; /* really exit */
  4080     if (newSlot) {
  4081 	crv = SFTK_SlotReInit(newSlot, paramStrings.configdir, 
  4082 			paramStrings.updatedir, paramStrings.updateID,
  4083 			&paramStrings.tokens[0], moduleIndex);
  4084     } else {
  4085 	crv = SFTK_SlotInit(paramStrings.configdir, 
  4086 			paramStrings.updatedir, paramStrings.updateID,
  4087 			&paramStrings.tokens[0], moduleIndex);
  4090 loser:
  4091     sftk_freeParams(&paramStrings);
  4092     sftk_FreeAttribute(attribute);
  4094     return crv;
  4098 /* NSC_CreateObject creates a new object. */
  4099 CK_RV NSC_CreateObject(CK_SESSION_HANDLE hSession,
  4100 		CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount, 
  4101 					CK_OBJECT_HANDLE_PTR phObject)
  4103     SFTKSlot *slot = sftk_SlotFromSessionHandle(hSession);
  4104     SFTKSession *session;
  4105     SFTKObject *object;
  4106     /* make sure class isn't randomly CKO_NETSCAPE_NEWSLOT or
  4107      * CKO_NETSCPE_DELSLOT. */
  4108     CK_OBJECT_CLASS class = CKO_VENDOR_DEFINED;
  4109     CK_RV crv;
  4110     int i;
  4112     CHECK_FORK();
  4114     *phObject = CK_INVALID_HANDLE;
  4116     if (slot == NULL) {
  4117 	return CKR_SESSION_HANDLE_INVALID;
  4119     /*
  4120      * now lets create an object to hang the attributes off of
  4121      */
  4122     object = sftk_NewObject(slot); /* fill in the handle later */
  4123     if (object == NULL) {
  4124 	return CKR_HOST_MEMORY;
  4127     /*
  4128      * load the template values into the object
  4129      */
  4130     for (i=0; i < (int) ulCount; i++) {
  4131 	crv = sftk_AddAttributeType(object,sftk_attr_expand(&pTemplate[i]));
  4132 	if (crv != CKR_OK) {
  4133 	    sftk_FreeObject(object);
  4134 	    return crv;
  4136 	if ((pTemplate[i].type == CKA_CLASS) && pTemplate[i].pValue) {
  4137 	    class = *(CK_OBJECT_CLASS *)pTemplate[i].pValue;
  4141     /* get the session */
  4142     session = sftk_SessionFromHandle(hSession);
  4143     if (session == NULL) {
  4144 	sftk_FreeObject(object);
  4145         return CKR_SESSION_HANDLE_INVALID;
  4148     /*
  4149      * handle pseudo objects (CKO_NEWSLOT)
  4150      */
  4151     if ((class == CKO_NETSCAPE_NEWSLOT)  || (class == CKO_NETSCAPE_DELSLOT)) {
  4152 	crv = sftk_CreateNewSlot(slot, class, object);
  4153 	goto done;
  4156     /*
  4157      * handle the base object stuff
  4158      */
  4159     crv = sftk_handleObject(object,session);
  4160     *phObject = object->handle;
  4161 done:
  4162     sftk_FreeSession(session);
  4163     sftk_FreeObject(object);
  4165     return crv;
  4170 /* NSC_CopyObject copies an object, creating a new object for the copy. */
  4171 CK_RV NSC_CopyObject(CK_SESSION_HANDLE hSession,
  4172        CK_OBJECT_HANDLE hObject, CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount,
  4173 					CK_OBJECT_HANDLE_PTR phNewObject) 
  4175     SFTKObject *destObject,*srcObject;
  4176     SFTKSession *session;
  4177     CK_RV crv = CKR_OK;
  4178     SFTKSlot *slot = sftk_SlotFromSessionHandle(hSession);
  4179     int i;
  4181     CHECK_FORK();
  4183     if (slot == NULL) {
  4184 	return CKR_SESSION_HANDLE_INVALID;
  4186     /* Get srcObject so we can find the class */
  4187     session = sftk_SessionFromHandle(hSession);
  4188     if (session == NULL) {
  4189         return CKR_SESSION_HANDLE_INVALID;
  4191     srcObject = sftk_ObjectFromHandle(hObject,session);
  4192     if (srcObject == NULL) {
  4193 	sftk_FreeSession(session);
  4194 	return CKR_OBJECT_HANDLE_INVALID;
  4196     /*
  4197      * create an object to hang the attributes off of
  4198      */
  4199     destObject = sftk_NewObject(slot); /* fill in the handle later */
  4200     if (destObject == NULL) {
  4201 	sftk_FreeSession(session);
  4202         sftk_FreeObject(srcObject);
  4203 	return CKR_HOST_MEMORY;
  4206     /*
  4207      * load the template values into the object
  4208      */
  4209     for (i=0; i < (int) ulCount; i++) {
  4210 	if (sftk_modifyType(pTemplate[i].type,srcObject->objclass) == SFTK_NEVER) {
  4211 	    crv = CKR_ATTRIBUTE_READ_ONLY;
  4212 	    break;
  4214 	crv = sftk_AddAttributeType(destObject,sftk_attr_expand(&pTemplate[i]));
  4215 	if (crv != CKR_OK) { break; }
  4217     if (crv != CKR_OK) {
  4218 	sftk_FreeSession(session);
  4219         sftk_FreeObject(srcObject);
  4220 	sftk_FreeObject(destObject);
  4221 	return crv;
  4224     /* sensitive can only be changed to CK_TRUE */
  4225     if (sftk_hasAttribute(destObject,CKA_SENSITIVE)) {
  4226 	if (!sftk_isTrue(destObject,CKA_SENSITIVE)) {
  4227 	    sftk_FreeSession(session);
  4228             sftk_FreeObject(srcObject);
  4229 	    sftk_FreeObject(destObject);
  4230 	    return CKR_ATTRIBUTE_READ_ONLY;
  4234     /*
  4235      * now copy the old attributes from the new attributes
  4236      */
  4237     /* don't create a token object if we aren't in a rw session */
  4238     /* we need to hold the lock to copy a consistant version of
  4239      * the object. */
  4240     crv = sftk_CopyObject(destObject,srcObject);
  4242     destObject->objclass = srcObject->objclass;
  4243     sftk_FreeObject(srcObject);
  4244     if (crv != CKR_OK) {
  4245 	sftk_FreeObject(destObject);
  4246 	sftk_FreeSession(session);
  4247         return crv;
  4250     crv = sftk_handleObject(destObject,session);
  4251     *phNewObject = destObject->handle;
  4252     sftk_FreeSession(session);
  4253     sftk_FreeObject(destObject);
  4255     return crv;
  4259 /* NSC_GetObjectSize gets the size of an object in bytes. */
  4260 CK_RV NSC_GetObjectSize(CK_SESSION_HANDLE hSession,
  4261     			CK_OBJECT_HANDLE hObject, CK_ULONG_PTR pulSize)
  4263     CHECK_FORK();
  4265     *pulSize = 0;
  4266     return CKR_OK;
  4270 /* NSC_GetAttributeValue obtains the value of one or more object attributes. */
  4271 CK_RV NSC_GetAttributeValue(CK_SESSION_HANDLE hSession,
  4272     CK_OBJECT_HANDLE hObject,CK_ATTRIBUTE_PTR pTemplate,CK_ULONG ulCount)
  4274     SFTKSlot *slot = sftk_SlotFromSessionHandle(hSession);
  4275     SFTKSession *session;
  4276     SFTKObject *object;
  4277     SFTKAttribute *attribute;
  4278     PRBool sensitive;
  4279     CK_RV crv;
  4280     int i;
  4282     CHECK_FORK();
  4284     if (slot == NULL) {
  4285 	return CKR_SESSION_HANDLE_INVALID;
  4287     /*
  4288      * make sure we're allowed
  4289      */
  4290     session = sftk_SessionFromHandle(hSession);
  4291     if (session == NULL) {
  4292         return CKR_SESSION_HANDLE_INVALID;
  4295     /* short circuit everything for token objects */
  4296     if (sftk_isToken(hObject)) {
  4297 	SFTKSlot *slot = sftk_SlotFromSession(session);
  4298 	SFTKDBHandle *dbHandle = sftk_getDBForTokenObject(slot, hObject);
  4299 	SFTKDBHandle *keydb = NULL;
  4301 	if (dbHandle == NULL) {
  4302 	    sftk_FreeSession(session);
  4303 	    return CKR_OBJECT_HANDLE_INVALID;
  4306 	crv = sftkdb_GetAttributeValue(dbHandle, hObject, pTemplate, ulCount);
  4308 	/* make sure we don't export any sensitive information */
  4309 	keydb = sftk_getKeyDB(slot);
  4310 	if (dbHandle == keydb) {
  4311 	    for (i=0; i < (int) ulCount; i++) {
  4312 		if (sftk_isSensitive(pTemplate[i].type,CKO_PRIVATE_KEY)) {
  4313 		    crv = CKR_ATTRIBUTE_SENSITIVE;
  4314 		    if (pTemplate[i].pValue && (pTemplate[i].ulValueLen!= -1)){
  4315 			PORT_Memset(pTemplate[i].pValue, 0, 
  4316 					pTemplate[i].ulValueLen);
  4318 		    pTemplate[i].ulValueLen = -1;
  4323 	sftk_FreeSession(session);
  4324 	sftk_freeDB(dbHandle);
  4325 	if (keydb) {
  4326 	    sftk_freeDB(keydb);
  4328 	return crv;
  4331     /* handle the session object */
  4332     object = sftk_ObjectFromHandle(hObject,session);
  4333     sftk_FreeSession(session);
  4334     if (object == NULL) {
  4335 	return CKR_OBJECT_HANDLE_INVALID;
  4338     /* don't read a private object if we aren't logged in */
  4339     if ((!slot->isLoggedIn) && (slot->needLogin) &&
  4340 				(sftk_isTrue(object,CKA_PRIVATE))) {
  4341 	sftk_FreeObject(object);
  4342 	return CKR_USER_NOT_LOGGED_IN;
  4345     crv = CKR_OK;
  4346     sensitive = sftk_isTrue(object,CKA_SENSITIVE);
  4347     for (i=0; i < (int) ulCount; i++) {
  4348 	/* Make sure that this attribute is retrievable */
  4349 	if (sensitive && sftk_isSensitive(pTemplate[i].type,object->objclass)) {
  4350 	    crv = CKR_ATTRIBUTE_SENSITIVE;
  4351 	    pTemplate[i].ulValueLen = -1;
  4352 	    continue;
  4354 	attribute = sftk_FindAttribute(object,pTemplate[i].type);
  4355 	if (attribute == NULL) {
  4356 	    crv = CKR_ATTRIBUTE_TYPE_INVALID;
  4357 	    pTemplate[i].ulValueLen = -1;
  4358 	    continue;
  4360 	if (pTemplate[i].pValue != NULL) {
  4361 	    PORT_Memcpy(pTemplate[i].pValue,attribute->attrib.pValue,
  4362 						attribute->attrib.ulValueLen);
  4364 	pTemplate[i].ulValueLen = attribute->attrib.ulValueLen;
  4365 	sftk_FreeAttribute(attribute);
  4368     sftk_FreeObject(object);
  4369     return crv;
  4372 /* NSC_SetAttributeValue modifies the value of one or more object attributes */
  4373 CK_RV NSC_SetAttributeValue (CK_SESSION_HANDLE hSession,
  4374  CK_OBJECT_HANDLE hObject,CK_ATTRIBUTE_PTR pTemplate,CK_ULONG ulCount)
  4376     SFTKSlot *slot = sftk_SlotFromSessionHandle(hSession);
  4377     SFTKSession *session;
  4378     SFTKAttribute *attribute;
  4379     SFTKObject *object;
  4380     PRBool isToken;
  4381     CK_RV crv = CKR_OK;
  4382     CK_BBOOL legal;
  4383     int i;
  4385     CHECK_FORK();
  4387     if (slot == NULL) {
  4388 	return CKR_SESSION_HANDLE_INVALID;
  4390     /*
  4391      * make sure we're allowed
  4392      */
  4393     session = sftk_SessionFromHandle(hSession);
  4394     if (session == NULL) {
  4395         return CKR_SESSION_HANDLE_INVALID;
  4398     object = sftk_ObjectFromHandle(hObject,session);
  4399     if (object == NULL) {
  4400         sftk_FreeSession(session);
  4401 	return CKR_OBJECT_HANDLE_INVALID;
  4404     /* don't modify a private object if we aren't logged in */
  4405     if ((!slot->isLoggedIn) && (slot->needLogin) &&
  4406 				(sftk_isTrue(object,CKA_PRIVATE))) {
  4407 	sftk_FreeSession(session);
  4408 	sftk_FreeObject(object);
  4409 	return CKR_USER_NOT_LOGGED_IN;
  4412     /* don't modify a token object if we aren't in a rw session */
  4413     isToken = sftk_isTrue(object,CKA_TOKEN);
  4414     if (((session->info.flags & CKF_RW_SESSION) == 0) && isToken) {
  4415 	sftk_FreeSession(session);
  4416 	sftk_FreeObject(object);
  4417 	return CKR_SESSION_READ_ONLY;
  4419     sftk_FreeSession(session);
  4421     /* only change modifiable objects */
  4422     if (!sftk_isTrue(object,CKA_MODIFIABLE)) {
  4423 	sftk_FreeObject(object);
  4424 	return CKR_ATTRIBUTE_READ_ONLY;
  4427     for (i=0; i < (int) ulCount; i++) {
  4428 	/* Make sure that this attribute is changeable */
  4429 	switch (sftk_modifyType(pTemplate[i].type,object->objclass)) {
  4430 	case SFTK_NEVER:
  4431 	case SFTK_ONCOPY:
  4432         default:
  4433 	    crv = CKR_ATTRIBUTE_READ_ONLY;
  4434 	    break;
  4436         case SFTK_SENSITIVE:
  4437 	    legal = (pTemplate[i].type == CKA_EXTRACTABLE) ? CK_FALSE : CK_TRUE;
  4438 	    if ((*(CK_BBOOL *)pTemplate[i].pValue) != legal) {
  4439 	        crv = CKR_ATTRIBUTE_READ_ONLY;
  4441 	    break;
  4442         case SFTK_ALWAYS:
  4443 	    break;
  4445 	if (crv != CKR_OK) break;
  4447 	/* find the old attribute */
  4448 	attribute = sftk_FindAttribute(object,pTemplate[i].type);
  4449 	if (attribute == NULL) {
  4450 	    crv =CKR_ATTRIBUTE_TYPE_INVALID;
  4451 	    break;
  4453     	sftk_FreeAttribute(attribute);
  4454 	crv = sftk_forceAttribute(object,sftk_attr_expand(&pTemplate[i]));
  4455 	if (crv != CKR_OK) break;
  4459     sftk_FreeObject(object);
  4460     return crv;
  4463 static CK_RV
  4464 sftk_expandSearchList(SFTKSearchResults *search, int count)
  4466     search->array_size += count;
  4467     search->handles = (CK_OBJECT_HANDLE *)PORT_Realloc(search->handles,
  4468 			sizeof(CK_OBJECT_HANDLE)*search->array_size);
  4469     return search->handles ? CKR_OK : CKR_HOST_MEMORY;
  4474 static CK_RV
  4475 sftk_searchDatabase(SFTKDBHandle *handle, SFTKSearchResults *search,
  4476                         const CK_ATTRIBUTE *pTemplate, CK_ULONG ulCount)
  4478     CK_RV crv;
  4479     int objectListSize = search->array_size-search->size;
  4480     CK_OBJECT_HANDLE *array = &search->handles[search->size];
  4481     SDBFind *find;
  4482     CK_ULONG count;
  4484     crv = sftkdb_FindObjectsInit(handle, pTemplate, ulCount, &find);
  4485     if (crv != CKR_OK)
  4486 	return crv;
  4487     do {
  4488 	crv = sftkdb_FindObjects(handle, find, array, objectListSize, &count);
  4489 	if ((crv != CKR_OK) || (count == 0))
  4490 	    break;
  4491 	search->size += count;
  4492 	objectListSize -= count;
  4493 	if (objectListSize > 0)
  4494 	    break;
  4495 	crv = sftk_expandSearchList(search,NSC_SEARCH_BLOCK_SIZE);
  4496 	objectListSize = NSC_SEARCH_BLOCK_SIZE;
  4497 	array = &search->handles[search->size];
  4498     } while (crv == CKR_OK);
  4499     sftkdb_FindObjectsFinal(handle, find);
  4501     return crv;
  4504 /* softoken used to search the SMimeEntries automatically instead of
  4505  * doing this in pk11wrap. This code should really be up in
  4506  * pk11wrap so that it will work with other tokens other than softoken.
  4507  */
  4508 CK_RV
  4509 sftk_emailhack(SFTKSlot *slot, SFTKDBHandle *handle, 
  4510     SFTKSearchResults *search, CK_ATTRIBUTE *pTemplate, CK_ULONG ulCount)
  4512     PRBool isCert = PR_FALSE;
  4513     int emailIndex = -1;
  4514     int i;
  4515     SFTKSearchResults smime_search;
  4516     CK_ATTRIBUTE smime_template[2];
  4517     CK_OBJECT_CLASS smime_class = CKO_NETSCAPE_SMIME;
  4518     SFTKAttribute *attribute = NULL;
  4519     SFTKObject *object = NULL;
  4520     CK_RV crv = CKR_OK;
  4523     smime_search.handles = NULL; /* paranoia, some one is bound to add a goto
  4524 				  * loser before this gets initialized */
  4526     /* see if we are looking for email certs */
  4527     for (i=0; i < ulCount; i++) {
  4528 	if (pTemplate[i].type == CKA_CLASS) {
  4529 	   if ((pTemplate[i].ulValueLen != sizeof(CK_OBJECT_CLASS) ||
  4530 	       (*(CK_OBJECT_CLASS *)pTemplate[i].pValue) != CKO_CERTIFICATE)) {
  4531 		/* not a cert, skip out */
  4532 		break;
  4534 	   isCert = PR_TRUE;
  4535 	} else if (pTemplate[i].type == CKA_NETSCAPE_EMAIL) {
  4536 	   emailIndex = i;
  4539 	if (isCert && (emailIndex != -1)) break;
  4542     if (!isCert || (emailIndex == -1)) {
  4543 	return CKR_OK;
  4546     /* we are doing a cert and email search, find the SMimeEntry */
  4547     smime_template[0].type = CKA_CLASS;
  4548     smime_template[0].pValue = &smime_class;
  4549     smime_template[0].ulValueLen = sizeof(smime_class);
  4550     smime_template[1] = pTemplate[emailIndex];
  4552     smime_search.handles = (CK_OBJECT_HANDLE *)
  4553 		PORT_Alloc(sizeof(CK_OBJECT_HANDLE) * NSC_SEARCH_BLOCK_SIZE);
  4554     if (smime_search.handles == NULL) {
  4555 	crv = CKR_HOST_MEMORY;
  4556 	goto loser;
  4558     smime_search.index = 0;
  4559     smime_search.size = 0;
  4560     smime_search.array_size = NSC_SEARCH_BLOCK_SIZE;
  4562     crv = sftk_searchDatabase(handle, &smime_search, smime_template, 2);
  4563     if (crv != CKR_OK || smime_search.size == 0) {
  4564 	goto loser;
  4567     /* get the SMime subject */
  4568     object = sftk_NewTokenObject(slot, NULL, smime_search.handles[0]);
  4569     if (object == NULL) {
  4570 	crv = CKR_HOST_MEMORY; /* is there any other reason for this failure? */
  4571 	goto loser;
  4573     attribute = sftk_FindAttribute(object,CKA_SUBJECT);
  4574     if (attribute == NULL) {
  4575 	crv = CKR_ATTRIBUTE_TYPE_INVALID;
  4576 	goto loser;
  4579     /* now find the certs with that subject */
  4580     pTemplate[emailIndex] = attribute->attrib;
  4581     /* now add the appropriate certs to the search list */
  4582     crv = sftk_searchDatabase(handle, search, pTemplate, ulCount);
  4583     pTemplate[emailIndex] = smime_template[1]; /* restore the user's template*/
  4585 loser:
  4586     if (attribute) {
  4587 	sftk_FreeAttribute(attribute);
  4589     if (object) {
  4590 	sftk_FreeObject(object);
  4592     if (smime_search.handles) {
  4593 	PORT_Free(smime_search.handles);
  4596     return crv;
  4599 static void
  4600 sftk_pruneSearch(CK_ATTRIBUTE *pTemplate, CK_ULONG ulCount,
  4601 			PRBool *searchCertDB, PRBool *searchKeyDB) {
  4602     CK_ULONG i;
  4604     *searchCertDB = PR_TRUE;
  4605     *searchKeyDB = PR_TRUE;
  4606     for (i = 0; i < ulCount; i++) {
  4607 	if (pTemplate[i].type == CKA_CLASS && pTemplate[i].pValue != NULL) {
  4608 	    CK_OBJECT_CLASS class = *((CK_OBJECT_CLASS*)pTemplate[i].pValue);
  4609 	    if (class == CKO_PRIVATE_KEY || class == CKO_SECRET_KEY) {
  4610 		*searchCertDB = PR_FALSE;
  4611 	    } else {
  4612 		*searchKeyDB = PR_FALSE;
  4614 	    break;
  4619 static CK_RV
  4620 sftk_searchTokenList(SFTKSlot *slot, SFTKSearchResults *search,
  4621                         CK_ATTRIBUTE *pTemplate, CK_ULONG ulCount,
  4622                         PRBool *tokenOnly, PRBool isLoggedIn)
  4624     CK_RV crv = CKR_OK;
  4625     CK_RV crv2;
  4626     PRBool searchCertDB;
  4627     PRBool searchKeyDB;
  4629     sftk_pruneSearch(pTemplate, ulCount, &searchCertDB, &searchKeyDB);
  4631     if (searchCertDB) {
  4632 	SFTKDBHandle *certHandle = sftk_getCertDB(slot);
  4633 	crv = sftk_searchDatabase(certHandle, search, pTemplate, ulCount);
  4634 	crv2 = sftk_emailhack(slot, certHandle, search, pTemplate, ulCount);
  4635 	if (crv == CKR_OK) crv = crv2;
  4636 	sftk_freeDB(certHandle);
  4639     if (crv == CKR_OK && isLoggedIn && searchKeyDB) {
  4640 	SFTKDBHandle *keyHandle = sftk_getKeyDB(slot);
  4641     	crv = sftk_searchDatabase(keyHandle, search, pTemplate, ulCount);
  4642     	sftk_freeDB(keyHandle);
  4644     return crv;
  4647 /* NSC_FindObjectsInit initializes a search for token and session objects 
  4648  * that match a template. */
  4649 CK_RV NSC_FindObjectsInit(CK_SESSION_HANDLE hSession,
  4650     			CK_ATTRIBUTE_PTR pTemplate,CK_ULONG ulCount)
  4652     SFTKSearchResults *search = NULL, *freeSearch = NULL;
  4653     SFTKSession *session = NULL;
  4654     SFTKSlot *slot = sftk_SlotFromSessionHandle(hSession);
  4655     PRBool tokenOnly = PR_FALSE;
  4656     CK_RV crv = CKR_OK;
  4657     PRBool isLoggedIn;
  4659     CHECK_FORK();
  4661     if (slot == NULL) {
  4662 	return CKR_SESSION_HANDLE_INVALID;
  4664     session = sftk_SessionFromHandle(hSession);
  4665     if (session == NULL) {
  4666 	crv = CKR_SESSION_HANDLE_INVALID;
  4667 	goto loser;
  4670     search = (SFTKSearchResults *)PORT_Alloc(sizeof(SFTKSearchResults));
  4671     if (search == NULL) {
  4672 	crv = CKR_HOST_MEMORY;
  4673 	goto loser;
  4675     search->handles = (CK_OBJECT_HANDLE *)
  4676 		PORT_Alloc(sizeof(CK_OBJECT_HANDLE) * NSC_SEARCH_BLOCK_SIZE);
  4677     if (search->handles == NULL) {
  4678 	crv = CKR_HOST_MEMORY;
  4679 	goto loser;
  4681     search->index = 0;
  4682     search->size = 0;
  4683     search->array_size = NSC_SEARCH_BLOCK_SIZE;
  4684     isLoggedIn = (PRBool)((!slot->needLogin) || slot->isLoggedIn);
  4686     crv = sftk_searchTokenList(slot, search, pTemplate, ulCount, &tokenOnly,
  4687 								isLoggedIn);
  4688     if (crv != CKR_OK) {
  4689 	goto loser;
  4692     /* build list of found objects in the session */
  4693     if (!tokenOnly) {
  4694 	crv = sftk_searchObjectList(search, slot->sessObjHashTable, 
  4695 				slot->sessObjHashSize, slot->objectLock, 
  4696 					pTemplate, ulCount, isLoggedIn);
  4698     if (crv != CKR_OK) {
  4699 	goto loser;
  4702     if ((freeSearch = session->search) != NULL) {
  4703 	session->search = NULL;
  4704 	sftk_FreeSearch(freeSearch);
  4706     session->search = search;
  4707     sftk_FreeSession(session);
  4708     return CKR_OK;
  4710 loser:
  4711     if (search) {
  4712 	sftk_FreeSearch(search);
  4714     if (session) {
  4715 	sftk_FreeSession(session);
  4717     return crv;
  4721 /* NSC_FindObjects continues a search for token and session objects 
  4722  * that match a template, obtaining additional object handles. */
  4723 CK_RV NSC_FindObjects(CK_SESSION_HANDLE hSession,
  4724     CK_OBJECT_HANDLE_PTR phObject,CK_ULONG ulMaxObjectCount,
  4725     					CK_ULONG_PTR pulObjectCount)
  4727     SFTKSession *session;
  4728     SFTKSearchResults *search;
  4729     int	transfer;
  4730     int left;
  4732     CHECK_FORK();
  4734     *pulObjectCount = 0;
  4735     session = sftk_SessionFromHandle(hSession);
  4736     if (session == NULL) return CKR_SESSION_HANDLE_INVALID;
  4737     if (session->search == NULL) {
  4738 	sftk_FreeSession(session);
  4739 	return CKR_OK;
  4741     search = session->search;
  4742     left = session->search->size - session->search->index;
  4743     transfer = ((int)ulMaxObjectCount > left) ? left : ulMaxObjectCount;
  4744     if (transfer > 0) {
  4745 	PORT_Memcpy(phObject,&search->handles[search->index],
  4746                                         transfer*sizeof(CK_OBJECT_HANDLE));
  4747     } else {
  4748        *phObject = CK_INVALID_HANDLE;
  4751     search->index += transfer;
  4752     if (search->index == search->size) {
  4753 	session->search = NULL;
  4754 	sftk_FreeSearch(search);
  4756     *pulObjectCount = transfer;
  4757     sftk_FreeSession(session);
  4758     return CKR_OK;
  4761 /* NSC_FindObjectsFinal finishes a search for token and session objects. */
  4762 CK_RV NSC_FindObjectsFinal(CK_SESSION_HANDLE hSession)
  4764     SFTKSession *session;
  4765     SFTKSearchResults *search;
  4767     CHECK_FORK();
  4769     session = sftk_SessionFromHandle(hSession);
  4770     if (session == NULL) return CKR_SESSION_HANDLE_INVALID;
  4771     search = session->search;
  4772     session->search = NULL;
  4773     sftk_FreeSession(session);
  4774     if (search != NULL) {
  4775 	sftk_FreeSearch(search);
  4777     return CKR_OK;
  4782 CK_RV NSC_WaitForSlotEvent(CK_FLAGS flags, CK_SLOT_ID_PTR pSlot,
  4783 							 CK_VOID_PTR pReserved)
  4785     CHECK_FORK();
  4787     return CKR_FUNCTION_NOT_SUPPORTED;

mercurial