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

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

mercurial