tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

pkcs11.c (207574B)


      1 /* This Source Code Form is subject to the terms of the Mozilla Public
      2 * License, v. 2.0. If a copy of the MPL was not distributed with this
      3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      4 /*
      5 * This file implements PKCS 11 on top of our existing security modules
      6 *
      7 * For more information about PKCS 11 See PKCS 11 Token Inteface Standard.
      8 *   This implementation has two slots:
      9 *      slot 1 is our generic crypto support. It does not require login.
     10 *   It supports Public Key ops, and all they bulk ciphers and hashes.
     11 *   It can also support Private Key ops for imported Private keys. It does
     12 *   not have any token storage.
     13 *      slot 2 is our private key support. It requires a login before use. It
     14 *   can store Private Keys and Certs as token objects. Currently only private
     15 *   keys and their associated Certificates are saved on the token.
     16 *
     17 *   In this implementation, session objects are only visible to the session
     18 *   that created or generated them.
     19 */
     20 #include "seccomon.h"
     21 #include "secitem.h"
     22 /* we need to use the deprecated mechanisms values for backward compatibility */
     23 #include "pkcs11.h"
     24 #include "pkcs11i.h"
     25 #include "softoken.h"
     26 #include "lowkeyi.h"
     27 #include "blapi.h"
     28 #include "secder.h"
     29 #include "secport.h"
     30 #include "secrng.h"
     31 #include "prtypes.h"
     32 #include "nspr.h"
     33 #include "softkver.h"
     34 #include "secoid.h"
     35 #include "sftkdb.h"
     36 #include "utilpars.h"
     37 #include "ec.h"
     38 #include "secasn1.h"
     39 #include "secerr.h"
     40 #include "lgglue.h"
     41 #include "kem.h"
     42 
     43 PRBool parentForkedAfterC_Initialize;
     44 
     45 #ifndef NO_FORK_CHECK
     46 
     47 PRBool sftkForkCheckDisabled;
     48 
     49 #if defined(CHECK_FORK_PTHREAD) || defined(CHECK_FORK_MIXED)
     50 PRBool forked = PR_FALSE;
     51 #endif
     52 
     53 #if defined(CHECK_FORK_GETPID) || defined(CHECK_FORK_MIXED)
     54 #include <unistd.h>
     55 pid_t myPid;
     56 #endif
     57 
     58 #ifdef CHECK_FORK_MIXED
     59 #include <sys/systeminfo.h>
     60 PRBool usePthread_atfork;
     61 #endif
     62 
     63 #endif
     64 
     65 #ifdef XP_UNIX
     66 #define LIB_PARAM_DEFAULT_FILE_LOCATION "/etc/nss/params.config"
     67 #endif
     68 
     69 #define LIB_PARAM_DEFAULT " configdir='' certPrefix='' keyPrefix='' secmod='' flags=noCertDB,noModDB "
     70 /*
     71 * ******************** Static data *******************************
     72 */
     73 
     74 /* The next three strings must be exactly 32 characters long */
     75 static char *manufacturerID = "Mozilla Foundation              ";
     76 static char manufacturerID_space[33];
     77 static char *libraryDescription = "NSS Internal Crypto Services    ";
     78 static char libraryDescription_space[33];
     79 
     80 /*
     81 * In FIPS mode, we disallow login attempts for 1 second after a login
     82 * failure so that there are at most 60 login attempts per minute.
     83 */
     84 static PRIntervalTime loginWaitTime;
     85 
     86 #undef __PASTE
     87 #define __PASTE(x, y) x##y
     88 
     89 /*
     90 * we renamed all our internal functions, get the correct
     91 * definitions for them...
     92 */
     93 #undef CK_PKCS11_FUNCTION_INFO
     94 #undef CK_NEED_ARG_LIST
     95 
     96 #define CK_PKCS11_3_2 1
     97 #define CK_PKCS11_3_0 1
     98 #define CK_EXTERN extern
     99 #define CK_PKCS11_FUNCTION_INFO(func) \
    100    CK_RV __PASTE(NS, func)
    101 #define CK_NEED_ARG_LIST 1
    102 
    103 #include "pkcs11f.h"
    104 
    105 #ifndef NSS_FIPS_DISABLE
    106 /* ------------- forward declare all the FIPS functions ------------- */
    107 #undef CK_NEED_ARG_LIST
    108 #undef CK_PKCS11_FUNCTION_INFO
    109 
    110 #define CK_PKCS11_FUNCTION_INFO(name) CK_RV __PASTE(F, name)
    111 #define CK_NEED_ARG_LIST 1
    112 
    113 #include "pkcs11f.h"
    114 #endif
    115 
    116 /* build the crypto module table */
    117 static CK_FUNCTION_LIST_3_2 sftk_funcList_v32 = {
    118    { 3, 2 },
    119 
    120 #undef CK_PKCS11_FUNCTION_INFO
    121 #undef CK_NEED_ARG_LIST
    122 
    123 #define CK_PKCS11_3_2_ONLY 1
    124 #define CK_PKCS11_FUNCTION_INFO(func) \
    125    __PASTE(NS, func)                 \
    126    ,
    127 #include "pkcs11f.h"
    128 
    129 };
    130 #undef CK_PKCS11_3_2_ONLY
    131 
    132 /* build the crypto module table */
    133 static CK_FUNCTION_LIST_3_0 sftk_funcList_v30 = {
    134    { 3, 0 },
    135 
    136 #undef CK_PKCS11_FUNCTION_INFO
    137 #undef CK_NEED_ARG_LIST
    138 
    139 #define CK_PKCS11_3_0_ONLY 1
    140 #define CK_PKCS11_FUNCTION_INFO(func) \
    141    __PASTE(NS, func)                 \
    142    ,
    143 #include "pkcs11f.h"
    144 
    145 };
    146 #undef CK_PKCS11_3_0_ONLY
    147 
    148 /* need a special version of get info for version 2 which returns the version
    149 * 2.4 version number */
    150 CK_RV NSC_GetInfoV2(CK_INFO_PTR pInfo);
    151 CK_RV NSC_GetMechanismInfoV2(CK_SLOT_ID slotID, CK_MECHANISM_TYPE type,
    152                             CK_MECHANISM_INFO_PTR pInfo);
    153 
    154 /* build the crypto module table */
    155 static CK_FUNCTION_LIST sftk_funcList_v2 = {
    156    { 2, 40 },
    157 
    158 #define CK_PKCS11_2_0_ONLY 1
    159 #undef CK_PKCS11_FUNCTION_INFO
    160 #undef CK_NEED_ARG_LIST
    161 #define C_GetInfo C_GetInfoV2
    162 #define C_GetMechanismInfo C_GetMechanismInfoV2
    163 
    164 #define CK_PKCS11_FUNCTION_INFO(func) \
    165    __PASTE(NS, func)                 \
    166    ,
    167 #include "pkcs11f.h"
    168 
    169 };
    170 
    171 #undef C_GetInfo
    172 #undef C_GetMechanismInfo
    173 #undef CK_PKCS_11_2_0_ONLY
    174 #undef CK_PKCS11_FUNCTION_INFO
    175 #undef CK_NEED_ARG_LIST
    176 
    177 #undef __PASTE
    178 
    179 CK_NSS_MODULE_FUNCTIONS sftk_module_funcList = {
    180    { 1, 0 },
    181    NSC_ModuleDBFunc
    182 };
    183 
    184 static CK_RV
    185 nsc_NSSGetFIPSStatus(CK_SESSION_HANDLE hSession,
    186                     CK_OBJECT_HANDLE hObject,
    187                     CK_ULONG ulOperationType,
    188                     CK_ULONG *pulFIPSStatus);
    189 CK_NSS_FIPS_FUNCTIONS sftk_fips_funcList = {
    190    { 1, 0 },
    191    nsc_NSSGetFIPSStatus
    192 };
    193 
    194 CK_NSS_KEM_FUNCTIONS sftk_kem_funcList = {
    195    { 1, 0 },
    196    NSC_Encapsulate,
    197    NSC_Decapsulate
    198 };
    199 
    200 /*
    201 * Array is orderd by default first
    202 */
    203 static CK_INTERFACE nss_interfaces[] = {
    204    { (CK_UTF8CHAR_PTR) "PKCS 11", &sftk_funcList_v32, NSS_INTERFACE_FLAGS },
    205    { (CK_UTF8CHAR_PTR) "PKCS 11", &sftk_funcList_v30, NSS_INTERFACE_FLAGS },
    206    { (CK_UTF8CHAR_PTR) "PKCS 11", &sftk_funcList_v2, NSS_INTERFACE_FLAGS },
    207    { (CK_UTF8CHAR_PTR) "Vendor NSS Module Interface", &sftk_module_funcList, NSS_INTERFACE_FLAGS },
    208    { (CK_UTF8CHAR_PTR) "Vendor NSS FIPS Interface", &sftk_fips_funcList, NSS_INTERFACE_FLAGS },
    209    { (CK_UTF8CHAR_PTR) "Vendor NSS KEM Interface", &sftk_kem_funcList, NSS_INTERFACE_FLAGS }
    210 };
    211 /* must match the count of interfaces in nss_interfaces above */
    212 #define NSS_INTERFACE_COUNT PR_ARRAY_SIZE(nss_interfaces)
    213 
    214 /* List of DES Weak Keys */
    215 typedef unsigned char desKey[8];
    216 static const desKey sftk_desWeakTable[] = {
    217 #ifdef noParity
    218    /* weak */
    219    { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
    220    { 0x1e, 0x1e, 0x1e, 0x1e, 0x0e, 0x0e, 0x0e, 0x0e },
    221    { 0xe0, 0xe0, 0xe0, 0xe0, 0xf0, 0xf0, 0xf0, 0xf0 },
    222    { 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe },
    223    /* semi-weak */
    224    { 0x00, 0xfe, 0x00, 0xfe, 0x00, 0xfe, 0x00, 0xfe },
    225    { 0xfe, 0x00, 0xfe, 0x00, 0x00, 0xfe, 0x00, 0xfe },
    226 
    227    { 0x1e, 0xe0, 0x1e, 0xe0, 0x0e, 0xf0, 0x0e, 0xf0 },
    228    { 0xe0, 0x1e, 0xe0, 0x1e, 0xf0, 0x0e, 0xf0, 0x0e },
    229 
    230    { 0x00, 0xe0, 0x00, 0xe0, 0x00, 0x0f, 0x00, 0x0f },
    231    { 0xe0, 0x00, 0xe0, 0x00, 0xf0, 0x00, 0xf0, 0x00 },
    232 
    233    { 0x1e, 0xfe, 0x1e, 0xfe, 0x0e, 0xfe, 0x0e, 0xfe },
    234    { 0xfe, 0x1e, 0xfe, 0x1e, 0xfe, 0x0e, 0xfe, 0x0e },
    235 
    236    { 0x00, 0x1e, 0x00, 0x1e, 0x00, 0x0e, 0x00, 0x0e },
    237    { 0x1e, 0x00, 0x1e, 0x00, 0x0e, 0x00, 0x0e, 0x00 },
    238 
    239    { 0xe0, 0xfe, 0xe0, 0xfe, 0xf0, 0xfe, 0xf0, 0xfe },
    240    { 0xfe, 0xe0, 0xfe, 0xe0, 0xfe, 0xf0, 0xfe, 0xf0 },
    241 #else
    242    /* weak */
    243    { 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 },
    244    { 0x1f, 0x1f, 0x1f, 0x1f, 0x0e, 0x0e, 0x0e, 0x0e },
    245    { 0xe0, 0xe0, 0xe0, 0xe0, 0xf1, 0xf1, 0xf1, 0xf1 },
    246    { 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe },
    247 
    248    /* semi-weak */
    249    { 0x01, 0xfe, 0x01, 0xfe, 0x01, 0xfe, 0x01, 0xfe },
    250    { 0xfe, 0x01, 0xfe, 0x01, 0xfe, 0x01, 0xfe, 0x01 },
    251 
    252    { 0x1f, 0xe0, 0x1f, 0xe0, 0x0e, 0xf1, 0x0e, 0xf1 },
    253    { 0xe0, 0x1f, 0xe0, 0x1f, 0xf1, 0x0e, 0xf1, 0x0e },
    254 
    255    { 0x01, 0xe0, 0x01, 0xe0, 0x01, 0xf1, 0x01, 0xf1 },
    256    { 0xe0, 0x01, 0xe0, 0x01, 0xf1, 0x01, 0xf1, 0x01 },
    257 
    258    { 0x1f, 0xfe, 0x1f, 0xfe, 0x0e, 0xfe, 0x0e, 0xfe },
    259    { 0xfe, 0x1f, 0xfe, 0x1f, 0xfe, 0x0e, 0xfe, 0x0e },
    260 
    261    { 0x01, 0x1f, 0x01, 0x1f, 0x01, 0x0e, 0x01, 0x0e },
    262    { 0x1f, 0x01, 0x1f, 0x01, 0x0e, 0x01, 0x0e, 0x01 },
    263 
    264    { 0xe0, 0xfe, 0xe0, 0xfe, 0xf1, 0xfe, 0xf1, 0xfe },
    265    { 0xfe, 0xe0, 0xfe, 0xe0, 0xfe, 0xf1, 0xfe, 0xf1 }
    266 #endif
    267 };
    268 
    269 static const int sftk_desWeakTableSize = sizeof(sftk_desWeakTable) /
    270                                         sizeof(sftk_desWeakTable[0]);
    271 
    272 /* DES KEY Parity conversion table. Takes each byte/2 as an index, returns
    273 * that byte with the proper parity bit set */
    274 static const unsigned char parityTable[256] = {
    275    /* Even...0x00,0x02,0x04,0x06,0x08,0x0a,0x0c,0x0e */
    276    /* E */ 0x01, 0x02, 0x04, 0x07, 0x08, 0x0b, 0x0d, 0x0e,
    277    /* Odd....0x10,0x12,0x14,0x16,0x18,0x1a,0x1c,0x1e */
    278    /* O */ 0x10, 0x13, 0x15, 0x16, 0x19, 0x1a, 0x1c, 0x1f,
    279    /* Odd....0x20,0x22,0x24,0x26,0x28,0x2a,0x2c,0x2e */
    280    /* O */ 0x20, 0x23, 0x25, 0x26, 0x29, 0x2a, 0x2c, 0x2f,
    281    /* Even...0x30,0x32,0x34,0x36,0x38,0x3a,0x3c,0x3e */
    282    /* E */ 0x31, 0x32, 0x34, 0x37, 0x38, 0x3b, 0x3d, 0x3e,
    283    /* Odd....0x40,0x42,0x44,0x46,0x48,0x4a,0x4c,0x4e */
    284    /* O */ 0x40, 0x43, 0x45, 0x46, 0x49, 0x4a, 0x4c, 0x4f,
    285    /* Even...0x50,0x52,0x54,0x56,0x58,0x5a,0x5c,0x5e */
    286    /* E */ 0x51, 0x52, 0x54, 0x57, 0x58, 0x5b, 0x5d, 0x5e,
    287    /* Even...0x60,0x62,0x64,0x66,0x68,0x6a,0x6c,0x6e */
    288    /* E */ 0x61, 0x62, 0x64, 0x67, 0x68, 0x6b, 0x6d, 0x6e,
    289    /* Odd....0x70,0x72,0x74,0x76,0x78,0x7a,0x7c,0x7e */
    290    /* O */ 0x70, 0x73, 0x75, 0x76, 0x79, 0x7a, 0x7c, 0x7f,
    291    /* Odd....0x80,0x82,0x84,0x86,0x88,0x8a,0x8c,0x8e */
    292    /* O */ 0x80, 0x83, 0x85, 0x86, 0x89, 0x8a, 0x8c, 0x8f,
    293    /* Even...0x90,0x92,0x94,0x96,0x98,0x9a,0x9c,0x9e */
    294    /* E */ 0x91, 0x92, 0x94, 0x97, 0x98, 0x9b, 0x9d, 0x9e,
    295    /* Even...0xa0,0xa2,0xa4,0xa6,0xa8,0xaa,0xac,0xae */
    296    /* E */ 0xa1, 0xa2, 0xa4, 0xa7, 0xa8, 0xab, 0xad, 0xae,
    297    /* Odd....0xb0,0xb2,0xb4,0xb6,0xb8,0xba,0xbc,0xbe */
    298    /* O */ 0xb0, 0xb3, 0xb5, 0xb6, 0xb9, 0xba, 0xbc, 0xbf,
    299    /* Even...0xc0,0xc2,0xc4,0xc6,0xc8,0xca,0xcc,0xce */
    300    /* E */ 0xc1, 0xc2, 0xc4, 0xc7, 0xc8, 0xcb, 0xcd, 0xce,
    301    /* Odd....0xd0,0xd2,0xd4,0xd6,0xd8,0xda,0xdc,0xde */
    302    /* O */ 0xd0, 0xd3, 0xd5, 0xd6, 0xd9, 0xda, 0xdc, 0xdf,
    303    /* Odd....0xe0,0xe2,0xe4,0xe6,0xe8,0xea,0xec,0xee */
    304    /* O */ 0xe0, 0xe3, 0xe5, 0xe6, 0xe9, 0xea, 0xec, 0xef,
    305    /* Even...0xf0,0xf2,0xf4,0xf6,0xf8,0xfa,0xfc,0xfe */
    306    /* E */ 0xf1, 0xf2, 0xf4, 0xf7, 0xf8, 0xfb, 0xfd, 0xfe
    307 };
    308 
    309 /* Mechanisms */
    310 struct mechanismList {
    311    CK_MECHANISM_TYPE type;
    312    CK_MECHANISM_INFO info;
    313    PRBool privkey;
    314 };
    315 
    316 /*
    317 * the following table includes a complete list of mechanism defined by
    318 * PKCS #11 version 2.01. Those Mechanisms not supported by this PKCS #11
    319 * module are ifdef'ed out.
    320 */
    321 #define CKF_EN_DE CKF_ENCRYPT | CKF_DECRYPT
    322 #define CKF_WR_UN CKF_WRAP | CKF_UNWRAP
    323 #define CKF_SN_VR CKF_SIGN | CKF_VERIFY
    324 #define CKF_SN_RE CKF_SIGN_RECOVER | CKF_VERIFY_RECOVER
    325 #define CKF_EN_DE_MSG CKF_ENCRYPT | CKF_DECRYPT | CKF_MESSAGE_ENCRYPT | CKF_MESSAGE_DECRYPT
    326 #define CKF_KEM CKF_ENCAPSULATE | CKF_DECAPSULATE
    327 
    328 #define CKF_EN_DE_WR_UN CKF_EN_DE | CKF_WR_UN
    329 #define CKF_SN_VR_RE CKF_SN_VR | CKF_SN_RE
    330 #define CKF_DUZ_IT_ALL CKF_EN_DE_WR_UN | CKF_SN_VR_RE
    331 
    332 #define CKF_EC_PNU CKF_EC_F_P | CKF_EC_NAMEDCURVE | CKF_EC_UNCOMPRESS
    333 
    334 #define CKF_EC_BPNU CKF_EC_F_2M | CKF_EC_PNU
    335 #define CKF_EC_POC CKF_EC_F_P | CKF_EC_OID | CKF_EC_COMPRESS
    336 
    337 #define CK_MAX 0xffffffff
    338 
    339 static const struct mechanismList mechanisms[] = {
    340 
    341    /*
    342     * PKCS #11 Mechanism List.
    343     *
    344     * The first argument is the PKCS #11 Mechanism we support.
    345     * The second argument is Mechanism info structure. It includes:
    346     *    The minimum key size,
    347     *       in bits for RSA, DSA, DH, EC*, KEA, RC2 and RC4 * algs.
    348     *       in bytes for RC5, AES, Camellia, and CAST*
    349     *       ignored for DES*, IDEA and FORTEZZA based
    350     *    The maximum key size,
    351     *       in bits for RSA, DSA, DH, EC*, KEA, RC2 and RC4 * algs.
    352     *       in bytes for RC5, AES, Camellia, and CAST*
    353     *       ignored for DES*, IDEA and FORTEZZA based
    354     *     Flags
    355     *       What operations are supported by this mechanism.
    356     *  The third argument is a bool which tells if this mechanism is
    357     *    supported in the database token.
    358     *
    359     */
    360 
    361    /* ------------------------- RSA Operations ---------------------------*/
    362    { CKM_RSA_PKCS_KEY_PAIR_GEN, { RSA_MIN_MODULUS_BITS, CK_MAX, CKF_GENERATE_KEY_PAIR }, PR_TRUE },
    363    { CKM_RSA_PKCS, { RSA_MIN_MODULUS_BITS, CK_MAX, CKF_DUZ_IT_ALL }, PR_TRUE },
    364    { CKM_RSA_PKCS_PSS, { RSA_MIN_MODULUS_BITS, CK_MAX, CKF_SN_VR }, PR_TRUE },
    365    { CKM_RSA_PKCS_OAEP, { RSA_MIN_MODULUS_BITS, CK_MAX, CKF_EN_DE_WR_UN }, PR_TRUE },
    366 #ifdef SFTK_RSA9796_SUPPORTED
    367    { CKM_RSA_9796, { RSA_MIN_MODULUS_BITS, CK_MAX, CKF_DUZ_IT_ALL }, PR_TRUE },
    368 #endif
    369    { CKM_RSA_X_509, { RSA_MIN_MODULUS_BITS, CK_MAX, CKF_DUZ_IT_ALL }, PR_TRUE },
    370    /* -------------- RSA Multipart Signing Operations -------------------- */
    371    { CKM_MD2_RSA_PKCS, { RSA_MIN_MODULUS_BITS, CK_MAX, CKF_SN_VR }, PR_TRUE },
    372    { CKM_MD5_RSA_PKCS, { RSA_MIN_MODULUS_BITS, CK_MAX, CKF_SN_VR }, PR_TRUE },
    373    { CKM_SHA1_RSA_PKCS, { RSA_MIN_MODULUS_BITS, CK_MAX, CKF_SN_VR }, PR_TRUE },
    374    { CKM_SHA224_RSA_PKCS, { RSA_MIN_MODULUS_BITS, CK_MAX, CKF_SN_VR }, PR_TRUE },
    375    { CKM_SHA256_RSA_PKCS, { RSA_MIN_MODULUS_BITS, CK_MAX, CKF_SN_VR }, PR_TRUE },
    376    { CKM_SHA384_RSA_PKCS, { RSA_MIN_MODULUS_BITS, CK_MAX, CKF_SN_VR }, PR_TRUE },
    377    { CKM_SHA512_RSA_PKCS, { RSA_MIN_MODULUS_BITS, CK_MAX, CKF_SN_VR }, PR_TRUE },
    378    { CKM_SHA1_RSA_PKCS_PSS, { RSA_MIN_MODULUS_BITS, CK_MAX, CKF_SN_VR }, PR_TRUE },
    379    { CKM_SHA224_RSA_PKCS_PSS, { RSA_MIN_MODULUS_BITS, CK_MAX, CKF_SN_VR }, PR_TRUE },
    380    { CKM_SHA256_RSA_PKCS_PSS, { RSA_MIN_MODULUS_BITS, CK_MAX, CKF_SN_VR }, PR_TRUE },
    381    { CKM_SHA384_RSA_PKCS_PSS, { RSA_MIN_MODULUS_BITS, CK_MAX, CKF_SN_VR }, PR_TRUE },
    382    { CKM_SHA512_RSA_PKCS_PSS, { RSA_MIN_MODULUS_BITS, CK_MAX, CKF_SN_VR }, PR_TRUE },
    383 /* ------------------------- DSA Operations --------------------------- */
    384 #ifndef NSS_DISABLE_DSA
    385    { CKM_DSA_KEY_PAIR_GEN, { DSA_MIN_P_BITS, DSA_MAX_P_BITS, CKF_GENERATE_KEY_PAIR }, PR_TRUE },
    386    { CKM_DSA, { DSA_MIN_P_BITS, DSA_MAX_P_BITS, CKF_SN_VR }, PR_TRUE },
    387    { CKM_DSA_PARAMETER_GEN, { DSA_MIN_P_BITS, DSA_MAX_P_BITS, CKF_GENERATE }, PR_TRUE },
    388    { CKM_DSA_SHA1, { DSA_MIN_P_BITS, DSA_MAX_P_BITS, CKF_SN_VR }, PR_TRUE },
    389    { CKM_DSA_SHA224, { DSA_MIN_P_BITS, DSA_MAX_P_BITS, CKF_SN_VR }, PR_TRUE },
    390    { CKM_DSA_SHA256, { DSA_MIN_P_BITS, DSA_MAX_P_BITS, CKF_SN_VR }, PR_TRUE },
    391    { CKM_DSA_SHA384, { DSA_MIN_P_BITS, DSA_MAX_P_BITS, CKF_SN_VR }, PR_TRUE },
    392    { CKM_DSA_SHA512, { DSA_MIN_P_BITS, DSA_MAX_P_BITS, CKF_SN_VR }, PR_TRUE },
    393 #endif
    394    /* -------------------- Diffie Hellman Operations --------------------- */
    395    /* no diffie hellman yet */
    396    { CKM_DH_PKCS_KEY_PAIR_GEN, { DH_MIN_P_BITS, DH_MAX_P_BITS, CKF_GENERATE_KEY_PAIR }, PR_TRUE },
    397    { CKM_DH_PKCS_DERIVE, { DH_MIN_P_BITS, DH_MAX_P_BITS, CKF_DERIVE }, PR_TRUE },
    398    /* -------------------- Elliptic Curve Operations --------------------- */
    399    { CKM_EC_KEY_PAIR_GEN, { EC_MIN_KEY_BITS, EC_MAX_KEY_BITS, CKF_GENERATE_KEY_PAIR | CKF_EC_BPNU }, PR_TRUE },
    400    { CKM_NSS_ECDHE_NO_PAIRWISE_CHECK_KEY_PAIR_GEN, { EC_MIN_KEY_BITS, EC_MAX_KEY_BITS, CKF_GENERATE_KEY_PAIR | CKF_EC_BPNU }, PR_TRUE },
    401    { CKM_ECDH1_DERIVE, { EC_MIN_KEY_BITS, EC_MAX_KEY_BITS, CKF_DERIVE | CKF_EC_BPNU }, PR_TRUE },
    402    { CKM_ECDSA, { EC_MIN_KEY_BITS, EC_MAX_KEY_BITS, CKF_SN_VR | CKF_EC_BPNU }, PR_TRUE },
    403    { CKM_ECDSA_SHA1, { EC_MIN_KEY_BITS, EC_MAX_KEY_BITS, CKF_SN_VR | CKF_EC_BPNU }, PR_TRUE },
    404    { CKM_ECDSA_SHA224, { EC_MIN_KEY_BITS, EC_MAX_KEY_BITS, CKF_SN_VR | CKF_EC_BPNU }, PR_TRUE },
    405    { CKM_ECDSA_SHA256, { EC_MIN_KEY_BITS, EC_MAX_KEY_BITS, CKF_SN_VR | CKF_EC_BPNU }, PR_TRUE },
    406    { CKM_ECDSA_SHA384, { EC_MIN_KEY_BITS, EC_MAX_KEY_BITS, CKF_SN_VR | CKF_EC_BPNU }, PR_TRUE },
    407    { CKM_ECDSA_SHA512, { EC_MIN_KEY_BITS, EC_MAX_KEY_BITS, CKF_SN_VR | CKF_EC_BPNU }, PR_TRUE },
    408    { CKM_EC_EDWARDS_KEY_PAIR_GEN, { ECD_MIN_KEY_BITS, ECD_MAX_KEY_BITS, CKF_GENERATE_KEY_PAIR }, PR_TRUE },
    409    { CKM_EC_MONTGOMERY_KEY_PAIR_GEN, { ECD_MIN_KEY_BITS, ECD_MAX_KEY_BITS, CKF_GENERATE_KEY_PAIR }, PR_TRUE },
    410    { CKM_EDDSA, { ECD_MIN_KEY_BITS, ECD_MAX_KEY_BITS, CKF_SN_VR | CKF_EC_POC }, PR_TRUE },
    411    /* ------------------------- RC2 Operations --------------------------- */
    412    { CKM_RC2_KEY_GEN, { 1, 128, CKF_GENERATE }, PR_TRUE },
    413    { CKM_RC2_ECB, { 1, 128, CKF_EN_DE_WR_UN }, PR_TRUE },
    414    { CKM_RC2_CBC, { 1, 128, CKF_EN_DE_WR_UN }, PR_TRUE },
    415    { CKM_RC2_MAC, { 1, 128, CKF_SN_VR }, PR_TRUE },
    416    { CKM_RC2_MAC_GENERAL, { 1, 128, CKF_SN_VR }, PR_TRUE },
    417    { CKM_RC2_CBC_PAD, { 1, 128, CKF_EN_DE_WR_UN }, PR_TRUE },
    418    /* ------------------------- RC4 Operations --------------------------- */
    419    { CKM_RC4_KEY_GEN, { 1, 256, CKF_GENERATE }, PR_FALSE },
    420    { CKM_RC4, { 1, 256, CKF_EN_DE_WR_UN }, PR_FALSE },
    421    /* ------------------------- DES Operations --------------------------- */
    422    { CKM_DES_KEY_GEN, { 8, 8, CKF_GENERATE }, PR_TRUE },
    423    { CKM_DES_ECB, { 8, 8, CKF_EN_DE_WR_UN }, PR_TRUE },
    424    { CKM_DES_CBC, { 8, 8, CKF_EN_DE_WR_UN }, PR_TRUE },
    425    { CKM_DES_MAC, { 8, 8, CKF_SN_VR }, PR_TRUE },
    426    { CKM_DES_MAC_GENERAL, { 8, 8, CKF_SN_VR }, PR_TRUE },
    427    { CKM_DES_CBC_PAD, { 8, 8, CKF_EN_DE_WR_UN }, PR_TRUE },
    428    { CKM_DES2_KEY_GEN, { 24, 24, CKF_GENERATE }, PR_TRUE },
    429    { CKM_DES3_KEY_GEN, { 24, 24, CKF_GENERATE }, PR_TRUE },
    430    { CKM_DES3_ECB, { 24, 24, CKF_EN_DE_WR_UN }, PR_TRUE },
    431    { CKM_DES3_CBC, { 24, 24, CKF_EN_DE_WR_UN }, PR_TRUE },
    432    { CKM_DES3_MAC, { 24, 24, CKF_SN_VR }, PR_TRUE },
    433    { CKM_DES3_MAC_GENERAL, { 24, 24, CKF_SN_VR }, PR_TRUE },
    434    { CKM_DES3_CBC_PAD, { 24, 24, CKF_EN_DE_WR_UN }, PR_TRUE },
    435    /* ------------------------- CDMF Operations --------------------------- */
    436    { CKM_CDMF_KEY_GEN, { 8, 8, CKF_GENERATE }, PR_TRUE },
    437    { CKM_CDMF_ECB, { 8, 8, CKF_EN_DE_WR_UN }, PR_TRUE },
    438    { CKM_CDMF_CBC, { 8, 8, CKF_EN_DE_WR_UN }, PR_TRUE },
    439    { CKM_CDMF_MAC, { 8, 8, CKF_SN_VR }, PR_TRUE },
    440    { CKM_CDMF_MAC_GENERAL, { 8, 8, CKF_SN_VR }, PR_TRUE },
    441    { CKM_CDMF_CBC_PAD, { 8, 8, CKF_EN_DE_WR_UN }, PR_TRUE },
    442    /* ------------------------- AES Operations --------------------------- */
    443    { CKM_AES_KEY_GEN, { 16, 32, CKF_GENERATE }, PR_TRUE },
    444    { CKM_AES_ECB, { 16, 32, CKF_EN_DE_WR_UN }, PR_TRUE },
    445    { CKM_AES_CBC, { 16, 32, CKF_EN_DE_WR_UN }, PR_TRUE },
    446    { CKM_AES_MAC, { 16, 32, CKF_SN_VR }, PR_TRUE },
    447    { CKM_AES_MAC_GENERAL, { 16, 32, CKF_SN_VR }, PR_TRUE },
    448    { CKM_AES_CMAC, { 16, 32, CKF_SN_VR }, PR_TRUE },
    449    { CKM_AES_CMAC_GENERAL, { 16, 32, CKF_SN_VR }, PR_TRUE },
    450    { CKM_AES_CBC_PAD, { 16, 32, CKF_EN_DE_WR_UN }, PR_TRUE },
    451    { CKM_AES_CTS, { 16, 32, CKF_EN_DE }, PR_TRUE },
    452    { CKM_AES_CTR, { 16, 32, CKF_EN_DE }, PR_TRUE },
    453    { CKM_AES_GCM, { 16, 32, CKF_EN_DE_MSG }, PR_TRUE },
    454    { CKM_AES_XCBC_MAC_96, { 12, 12, CKF_SN_VR }, PR_TRUE },
    455    { CKM_AES_XCBC_MAC, { 16, 16, CKF_SN_VR }, PR_TRUE },
    456    /* ------------------------- Camellia Operations --------------------- */
    457    { CKM_CAMELLIA_KEY_GEN, { 16, 32, CKF_GENERATE }, PR_TRUE },
    458    { CKM_CAMELLIA_ECB, { 16, 32, CKF_EN_DE_WR_UN }, PR_TRUE },
    459    { CKM_CAMELLIA_CBC, { 16, 32, CKF_EN_DE_WR_UN }, PR_TRUE },
    460    { CKM_CAMELLIA_MAC, { 16, 32, CKF_SN_VR }, PR_TRUE },
    461    { CKM_CAMELLIA_MAC_GENERAL, { 16, 32, CKF_SN_VR }, PR_TRUE },
    462    { CKM_CAMELLIA_CBC_PAD, { 16, 32, CKF_EN_DE_WR_UN }, PR_TRUE },
    463 /* ------------------------- SEED Operations --------------------------- */
    464 #ifndef NSS_DISABLE_DEPRECATED_SEED
    465    { CKM_SEED_KEY_GEN, { 16, 16, CKF_GENERATE }, PR_TRUE },
    466    { CKM_SEED_ECB, { 16, 16, CKF_EN_DE_WR_UN }, PR_TRUE },
    467    { CKM_SEED_CBC, { 16, 16, CKF_EN_DE_WR_UN }, PR_TRUE },
    468    { CKM_SEED_MAC, { 16, 16, CKF_SN_VR }, PR_TRUE },
    469    { CKM_SEED_MAC_GENERAL, { 16, 16, CKF_SN_VR }, PR_TRUE },
    470    { CKM_SEED_CBC_PAD, { 16, 16, CKF_EN_DE_WR_UN }, PR_TRUE },
    471 #endif
    472 /* ------------------------- ChaCha20 Operations ---------------------- */
    473 #ifndef NSS_DISABLE_CHACHAPOLY
    474    { CKM_NSS_CHACHA20_KEY_GEN, { 32, 32, CKF_GENERATE }, PR_TRUE },
    475    { CKM_NSS_CHACHA20_POLY1305, { 32, 32, CKF_EN_DE }, PR_TRUE },
    476    { CKM_NSS_CHACHA20_CTR, { 32, 32, CKF_EN_DE }, PR_TRUE },
    477    { CKM_CHACHA20_KEY_GEN, { 32, 32, CKF_GENERATE }, PR_TRUE },
    478    { CKM_CHACHA20, { 32, 32, CKF_EN_DE }, PR_TRUE },
    479    { CKM_CHACHA20_POLY1305, { 32, 32, CKF_EN_DE_MSG }, PR_TRUE },
    480 #endif /* NSS_DISABLE_CHACHAPOLY */
    481    /* ------------------------- Hashing Operations ----------------------- */
    482    { CKM_MD2, { 0, 0, CKF_DIGEST }, PR_FALSE },
    483    { CKM_MD2_HMAC, { 1, 128, CKF_SN_VR }, PR_TRUE },
    484    { CKM_MD2_HMAC_GENERAL, { 1, 128, CKF_SN_VR }, PR_TRUE },
    485    { CKM_MD5, { 0, 0, CKF_DIGEST }, PR_FALSE },
    486    { CKM_MD5_HMAC, { 1, 128, CKF_SN_VR }, PR_TRUE },
    487    { CKM_MD5_HMAC_GENERAL, { 1, 128, CKF_SN_VR }, PR_TRUE },
    488    { CKM_SHA_1, { 0, 0, CKF_DIGEST }, PR_FALSE },
    489    { CKM_SHA_1_HMAC, { 1, 128, CKF_SN_VR }, PR_TRUE },
    490    { CKM_SHA_1_HMAC_GENERAL, { 1, 128, CKF_SN_VR }, PR_TRUE },
    491    { CKM_SHA224, { 0, 0, CKF_DIGEST }, PR_FALSE },
    492    { CKM_SHA224_HMAC, { 1, 128, CKF_SN_VR }, PR_TRUE },
    493    { CKM_SHA224_HMAC_GENERAL, { 1, 128, CKF_SN_VR }, PR_TRUE },
    494    { CKM_SHA256, { 0, 0, CKF_DIGEST }, PR_FALSE },
    495    { CKM_SHA256_HMAC, { 1, 128, CKF_SN_VR }, PR_TRUE },
    496    { CKM_SHA256_HMAC_GENERAL, { 1, 128, CKF_SN_VR }, PR_TRUE },
    497    { CKM_SHA384, { 0, 0, CKF_DIGEST }, PR_FALSE },
    498    { CKM_SHA384_HMAC, { 1, 128, CKF_SN_VR }, PR_TRUE },
    499    { CKM_SHA384_HMAC_GENERAL, { 1, 128, CKF_SN_VR }, PR_TRUE },
    500    { CKM_SHA512, { 0, 0, CKF_DIGEST }, PR_FALSE },
    501    { CKM_SHA512_HMAC, { 1, 128, CKF_SN_VR }, PR_TRUE },
    502    { CKM_SHA512_HMAC_GENERAL, { 1, 128, CKF_SN_VR }, PR_TRUE },
    503    { CKM_SHA3_224, { 0, 0, CKF_DIGEST }, PR_FALSE },
    504    { CKM_SHA3_224_HMAC, { 1, 128, CKF_SN_VR }, PR_TRUE },
    505    { CKM_SHA3_224_HMAC_GENERAL, { 1, 128, CKF_SN_VR }, PR_TRUE },
    506    { CKM_SHA3_256, { 0, 0, CKF_DIGEST }, PR_FALSE },
    507    { CKM_SHA3_256_HMAC, { 1, 128, CKF_SN_VR }, PR_TRUE },
    508    { CKM_SHA3_256_HMAC_GENERAL, { 1, 128, CKF_SN_VR }, PR_TRUE },
    509    { CKM_SHA3_384, { 0, 0, CKF_DIGEST }, PR_FALSE },
    510    { CKM_SHA3_384_HMAC, { 1, 128, CKF_SN_VR }, PR_TRUE },
    511    { CKM_SHA3_384_HMAC_GENERAL, { 1, 128, CKF_SN_VR }, PR_TRUE },
    512    { CKM_SHA3_512, { 0, 0, CKF_DIGEST }, PR_FALSE },
    513    { CKM_SHA3_512_HMAC, { 1, 128, CKF_SN_VR }, PR_TRUE },
    514    { CKM_SHA3_512_HMAC_GENERAL, { 1, 128, CKF_SN_VR }, PR_TRUE },
    515    { CKM_TLS_PRF_GENERAL, { 0, 512, CKF_SN_VR }, PR_FALSE },
    516    { CKM_TLS_MAC, { 0, 512, CKF_SN_VR }, PR_FALSE },
    517    { CKM_NSS_TLS_PRF_GENERAL_SHA256,
    518      { 0, 512, CKF_SN_VR },
    519      PR_FALSE },
    520    /* ------------------------- HKDF Operations -------------------------- */
    521    { CKM_HKDF_DERIVE, { 1, 255 * 64, CKF_DERIVE }, PR_TRUE },
    522    { CKM_HKDF_DATA, { 1, 255 * 64, CKF_DERIVE }, PR_TRUE },
    523    { CKM_HKDF_KEY_GEN, { 20, 64, CKF_GENERATE }, PR_TRUE },
    524    { CKM_NSS_HKDF_SHA1, { 1, 128, CKF_DERIVE }, PR_TRUE },
    525    { CKM_NSS_HKDF_SHA256, { 1, 128, CKF_DERIVE }, PR_TRUE },
    526    { CKM_NSS_HKDF_SHA384, { 1, 128, CKF_DERIVE }, PR_TRUE },
    527    { CKM_NSS_HKDF_SHA512, { 1, 128, CKF_DERIVE }, PR_TRUE },
    528 /* ------------------------- CAST Operations --------------------------- */
    529 #ifdef NSS_SOFTOKEN_DOES_CAST
    530    /* Cast operations are not supported ( yet? ) */
    531    { CKM_CAST_KEY_GEN, { 1, 8, CKF_GENERATE }, PR_TRUE },
    532    { CKM_CAST_ECB, { 1, 8, CKF_EN_DE_WR_UN }, PR_TRUE },
    533    { CKM_CAST_CBC, { 1, 8, CKF_EN_DE_WR_UN }, PR_TRUE },
    534    { CKM_CAST_MAC, { 1, 8, CKF_SN_VR }, PR_TRUE },
    535    { CKM_CAST_MAC_GENERAL, { 1, 8, CKF_SN_VR }, PR_TRUE },
    536    { CKM_CAST_CBC_PAD, { 1, 8, CKF_EN_DE_WR_UN }, PR_TRUE },
    537    { CKM_CAST3_KEY_GEN, { 1, 16, CKF_GENERATE }, PR_TRUE },
    538    { CKM_CAST3_ECB, { 1, 16, CKF_EN_DE_WR_UN }, PR_TRUE },
    539    { CKM_CAST3_CBC, { 1, 16, CKF_EN_DE_WR_UN }, PR_TRUE },
    540    { CKM_CAST3_MAC, { 1, 16, CKF_SN_VR }, PR_TRUE },
    541    { CKM_CAST3_MAC_GENERAL, { 1, 16, CKF_SN_VR }, PR_TRUE },
    542    { CKM_CAST3_CBC_PAD, { 1, 16, CKF_EN_DE_WR_UN }, PR_TRUE },
    543    { CKM_CAST5_KEY_GEN, { 1, 16, CKF_GENERATE }, PR_TRUE },
    544    { CKM_CAST5_ECB, { 1, 16, CKF_EN_DE_WR_UN }, PR_TRUE },
    545    { CKM_CAST5_CBC, { 1, 16, CKF_EN_DE_WR_UN }, PR_TRUE },
    546    { CKM_CAST5_MAC, { 1, 16, CKF_SN_VR }, PR_TRUE },
    547    { CKM_CAST5_MAC_GENERAL, { 1, 16, CKF_SN_VR }, PR_TRUE },
    548    { CKM_CAST5_CBC_PAD, { 1, 16, CKF_EN_DE_WR_UN }, PR_TRUE },
    549 #endif
    550 #if NSS_SOFTOKEN_DOES_RC5
    551    /* ------------------------- RC5 Operations --------------------------- */
    552    { CKM_RC5_KEY_GEN, { 1, 32, CKF_GENERATE }, PR_TRUE },
    553    { CKM_RC5_ECB, { 1, 32, CKF_EN_DE_WR_UN }, PR_TRUE },
    554    { CKM_RC5_CBC, { 1, 32, CKF_EN_DE_WR_UN }, PR_TRUE },
    555    { CKM_RC5_MAC, { 1, 32, CKF_SN_VR }, PR_TRUE },
    556    { CKM_RC5_MAC_GENERAL, { 1, 32, CKF_SN_VR }, PR_TRUE },
    557    { CKM_RC5_CBC_PAD, { 1, 32, CKF_EN_DE_WR_UN }, PR_TRUE },
    558 #endif
    559 #ifdef NSS_SOFTOKEN_DOES_IDEA
    560    /* ------------------------- IDEA Operations -------------------------- */
    561    { CKM_IDEA_KEY_GEN, { 16, 16, CKF_GENERATE }, PR_TRUE },
    562    { CKM_IDEA_ECB, { 16, 16, CKF_EN_DE_WR_UN }, PR_TRUE },
    563    { CKM_IDEA_CBC, { 16, 16, CKF_EN_DE_WR_UN }, PR_TRUE },
    564    { CKM_IDEA_MAC, { 16, 16, CKF_SN_VR }, PR_TRUE },
    565    { CKM_IDEA_MAC_GENERAL, { 16, 16, CKF_SN_VR }, PR_TRUE },
    566    { CKM_IDEA_CBC_PAD, { 16, 16, CKF_EN_DE_WR_UN }, PR_TRUE },
    567 #endif
    568    /* --------------------- Secret Key Operations ------------------------ */
    569    { CKM_GENERIC_SECRET_KEY_GEN, { 1, 32, CKF_GENERATE }, PR_TRUE },
    570    { CKM_CONCATENATE_BASE_AND_KEY, { 1, 32, CKF_DERIVE }, PR_FALSE },
    571    { CKM_CONCATENATE_BASE_AND_DATA, { 1, 32, CKF_DERIVE }, PR_FALSE },
    572    { CKM_CONCATENATE_DATA_AND_BASE, { 1, 32, CKF_DERIVE }, PR_FALSE },
    573    { CKM_XOR_BASE_AND_DATA, { 1, 32, CKF_DERIVE }, PR_FALSE },
    574    { CKM_EXTRACT_KEY_FROM_KEY, { 1, 32, CKF_DERIVE }, PR_FALSE },
    575    { CKM_DES3_ECB_ENCRYPT_DATA, { 1, 32, CKF_DERIVE }, PR_FALSE },
    576    { CKM_DES3_CBC_ENCRYPT_DATA, { 1, 32, CKF_DERIVE }, PR_FALSE },
    577    { CKM_AES_ECB_ENCRYPT_DATA, { 1, 32, CKF_DERIVE }, PR_FALSE },
    578    { CKM_AES_CBC_ENCRYPT_DATA, { 1, 32, CKF_DERIVE }, PR_FALSE },
    579    { CKM_CAMELLIA_ECB_ENCRYPT_DATA, { 1, 32, CKF_DERIVE }, PR_FALSE },
    580    { CKM_CAMELLIA_CBC_ENCRYPT_DATA, { 1, 32, CKF_DERIVE }, PR_FALSE },
    581 #ifndef NSS_DISABLE_DEPRECATED_SEED
    582    { CKM_SEED_ECB_ENCRYPT_DATA, { 1, 32, CKF_DERIVE }, PR_FALSE },
    583    { CKM_SEED_CBC_ENCRYPT_DATA, { 1, 32, CKF_DERIVE }, PR_FALSE },
    584 #endif
    585    /* ---------------------- SSL Key Derivations ------------------------- */
    586    { CKM_SSL3_PRE_MASTER_KEY_GEN, { 48, 48, CKF_GENERATE }, PR_FALSE },
    587    { CKM_SSL3_MASTER_KEY_DERIVE, { 48, 48, CKF_DERIVE }, PR_FALSE },
    588    { CKM_SSL3_MASTER_KEY_DERIVE_DH, { 8, 128, CKF_DERIVE }, PR_FALSE },
    589    { CKM_SSL3_KEY_AND_MAC_DERIVE, { 48, 48, CKF_DERIVE }, PR_FALSE },
    590    { CKM_SSL3_MD5_MAC, { 0, 16, CKF_DERIVE }, PR_FALSE },
    591    { CKM_SSL3_SHA1_MAC, { 0, 20, CKF_DERIVE }, PR_FALSE },
    592    { CKM_MD5_KEY_DERIVATION, { 0, 16, CKF_DERIVE }, PR_FALSE },
    593    { CKM_MD2_KEY_DERIVATION, { 0, 16, CKF_DERIVE }, PR_FALSE },
    594    { CKM_SHA1_KEY_DERIVATION, { 0, 20, CKF_DERIVE }, PR_FALSE },
    595    { CKM_SHA224_KEY_DERIVATION, { 0, 28, CKF_DERIVE }, PR_FALSE },
    596    { CKM_SHA256_KEY_DERIVATION, { 0, 32, CKF_DERIVE }, PR_FALSE },
    597    { CKM_SHA384_KEY_DERIVATION, { 0, 48, CKF_DERIVE }, PR_FALSE },
    598    { CKM_SHA512_KEY_DERIVATION, { 0, 64, CKF_DERIVE }, PR_FALSE },
    599    { CKM_TLS_MASTER_KEY_DERIVE, { 48, 48, CKF_DERIVE }, PR_FALSE },
    600    { CKM_TLS12_MASTER_KEY_DERIVE, { 48, 48, CKF_DERIVE }, PR_FALSE },
    601    { CKM_NSS_TLS_MASTER_KEY_DERIVE_SHA256,
    602      { 48, 48, CKF_DERIVE },
    603      PR_FALSE },
    604    { CKM_TLS_MASTER_KEY_DERIVE_DH, { 8, 128, CKF_DERIVE }, PR_FALSE },
    605    { CKM_TLS12_MASTER_KEY_DERIVE_DH, { 8, 128, CKF_DERIVE }, PR_FALSE },
    606    { CKM_TLS12_EXTENDED_MASTER_KEY_DERIVE, { 48, 128, CKF_DERIVE }, PR_FALSE },
    607    { CKM_TLS12_EXTENDED_MASTER_KEY_DERIVE_DH, { 48, 128, CKF_DERIVE }, PR_FALSE },
    608    { CKM_NSS_TLS_MASTER_KEY_DERIVE_DH_SHA256,
    609      { 8, 128, CKF_DERIVE },
    610      PR_FALSE },
    611    { CKM_TLS_KEY_AND_MAC_DERIVE, { 48, 48, CKF_DERIVE }, PR_FALSE },
    612    { CKM_TLS12_KEY_AND_MAC_DERIVE, { 48, 48, CKF_DERIVE }, PR_FALSE },
    613    { CKM_NSS_TLS_KEY_AND_MAC_DERIVE_SHA256,
    614      { 48, 48, CKF_DERIVE },
    615      PR_FALSE },
    616    { CKM_NSS_TLS_EXTENDED_MASTER_KEY_DERIVE,
    617      { 48, 128, CKF_DERIVE },
    618      PR_FALSE },
    619    { CKM_NSS_TLS_EXTENDED_MASTER_KEY_DERIVE_DH,
    620      { 48, 128, CKF_DERIVE },
    621      PR_FALSE },
    622    /* ---------------------- PBE Key Derivations  ------------------------ */
    623    { CKM_PBE_MD2_DES_CBC, { 8, 8, CKF_DERIVE }, PR_TRUE },
    624    { CKM_PBE_MD5_DES_CBC, { 8, 8, CKF_DERIVE }, PR_TRUE },
    625    /* ------------------ NSS PBE Key Derivations  ------------------- */
    626    { CKM_NSS_PBE_SHA1_DES_CBC, { 8, 8, CKF_GENERATE }, PR_TRUE },
    627    { CKM_NSS_PBE_SHA1_FAULTY_3DES_CBC, { 24, 24, CKF_GENERATE }, PR_TRUE },
    628    { CKM_PBE_SHA1_DES3_EDE_CBC, { 24, 24, CKF_GENERATE }, PR_TRUE },
    629    { CKM_PBE_SHA1_DES2_EDE_CBC, { 24, 24, CKF_GENERATE }, PR_TRUE },
    630    { CKM_PBE_SHA1_RC2_40_CBC, { 40, 40, CKF_GENERATE }, PR_TRUE },
    631    { CKM_PBE_SHA1_RC2_128_CBC, { 128, 128, CKF_GENERATE }, PR_TRUE },
    632    { CKM_PBE_SHA1_RC4_40, { 40, 40, CKF_GENERATE }, PR_TRUE },
    633    { CKM_PBE_SHA1_RC4_128, { 128, 128, CKF_GENERATE }, PR_TRUE },
    634    { CKM_PBA_SHA1_WITH_SHA1_HMAC, { 20, 20, CKF_GENERATE }, PR_TRUE },
    635    { CKM_PKCS5_PBKD2, { 1, 256, CKF_GENERATE }, PR_TRUE },
    636    { CKM_NSS_PBE_SHA1_HMAC_KEY_GEN, { 20, 20, CKF_GENERATE }, PR_TRUE },
    637    { CKM_NSS_PBE_MD5_HMAC_KEY_GEN, { 16, 16, CKF_GENERATE }, PR_TRUE },
    638    { CKM_NSS_PBE_MD2_HMAC_KEY_GEN, { 16, 16, CKF_GENERATE }, PR_TRUE },
    639    { CKM_NSS_PKCS12_PBE_SHA224_HMAC_KEY_GEN, { 28, 28, CKF_GENERATE }, PR_TRUE },
    640    { CKM_NSS_PKCS12_PBE_SHA256_HMAC_KEY_GEN, { 32, 32, CKF_GENERATE }, PR_TRUE },
    641    { CKM_NSS_PKCS12_PBE_SHA384_HMAC_KEY_GEN, { 48, 48, CKF_GENERATE }, PR_TRUE },
    642    { CKM_NSS_PKCS12_PBE_SHA512_HMAC_KEY_GEN, { 64, 64, CKF_GENERATE }, PR_TRUE },
    643    /* ------------------ NIST 800-108 Key Derivations  ------------------- */
    644    { CKM_SP800_108_COUNTER_KDF, { 0, CK_MAX, CKF_DERIVE }, PR_TRUE },
    645    { CKM_SP800_108_FEEDBACK_KDF, { 0, CK_MAX, CKF_DERIVE }, PR_TRUE },
    646    { CKM_SP800_108_DOUBLE_PIPELINE_KDF, { 0, CK_MAX, CKF_DERIVE }, PR_TRUE },
    647    { CKM_NSS_SP800_108_COUNTER_KDF_DERIVE_DATA, { 0, CK_MAX, CKF_DERIVE }, PR_TRUE },
    648    { CKM_NSS_SP800_108_FEEDBACK_KDF_DERIVE_DATA, { 0, CK_MAX, CKF_DERIVE }, PR_TRUE },
    649    { CKM_NSS_SP800_108_DOUBLE_PIPELINE_KDF_DERIVE_DATA, { 0, CK_MAX, CKF_DERIVE }, PR_TRUE },
    650    /* ------------------ AES Key Wrap (also encrypt)  ------------------- */
    651    { CKM_NSS_AES_KEY_WRAP, { 16, 32, CKF_EN_DE_WR_UN }, PR_TRUE },
    652    { CKM_NSS_AES_KEY_WRAP_PAD, { 16, 32, CKF_EN_DE_WR_UN }, PR_TRUE },
    653    { CKM_AES_KEY_WRAP, { 16, 32, CKF_EN_DE_WR_UN }, PR_TRUE },
    654    { CKM_AES_KEY_WRAP_PAD, { 16, 32, CKF_EN_DE_WR_UN }, PR_TRUE },
    655    { CKM_AES_KEY_WRAP_KWP, { 1, 32, CKF_EN_DE_WR_UN }, PR_TRUE },
    656    /* --------------------------- J-PAKE -------------------------------- */
    657    { CKM_NSS_JPAKE_ROUND1_SHA1, { 0, 0, CKF_GENERATE }, PR_TRUE },
    658    { CKM_NSS_JPAKE_ROUND1_SHA256, { 0, 0, CKF_GENERATE }, PR_TRUE },
    659    { CKM_NSS_JPAKE_ROUND1_SHA384, { 0, 0, CKF_GENERATE }, PR_TRUE },
    660    { CKM_NSS_JPAKE_ROUND1_SHA512, { 0, 0, CKF_GENERATE }, PR_TRUE },
    661    { CKM_NSS_JPAKE_ROUND2_SHA1, { 0, 0, CKF_DERIVE }, PR_TRUE },
    662    { CKM_NSS_JPAKE_ROUND2_SHA256, { 0, 0, CKF_DERIVE }, PR_TRUE },
    663    { CKM_NSS_JPAKE_ROUND2_SHA384, { 0, 0, CKF_DERIVE }, PR_TRUE },
    664    { CKM_NSS_JPAKE_ROUND2_SHA512, { 0, 0, CKF_DERIVE }, PR_TRUE },
    665    { CKM_NSS_JPAKE_FINAL_SHA1, { 0, 0, CKF_DERIVE }, PR_TRUE },
    666    { CKM_NSS_JPAKE_FINAL_SHA256, { 0, 0, CKF_DERIVE }, PR_TRUE },
    667    { CKM_NSS_JPAKE_FINAL_SHA384, { 0, 0, CKF_DERIVE }, PR_TRUE },
    668    { CKM_NSS_JPAKE_FINAL_SHA512, { 0, 0, CKF_DERIVE }, PR_TRUE },
    669    /* -------------------- Constant Time TLS MACs ----------------------- */
    670    { CKM_NSS_HMAC_CONSTANT_TIME, { 0, 0, CKF_DIGEST }, PR_TRUE },
    671    { CKM_NSS_SSL3_MAC_CONSTANT_TIME, { 0, 0, CKF_DIGEST }, PR_TRUE },
    672    /* -------------------- IPSEC ----------------------- */
    673    { CKM_IKE2_PRF_PLUS_DERIVE, { 8, 255 * 64, CKF_DERIVE }, PR_TRUE },
    674    { CKM_IKE_PRF_DERIVE, { 8, 64, CKF_DERIVE }, PR_TRUE },
    675    { CKM_IKE1_PRF_DERIVE, { 8, 64, CKF_DERIVE }, PR_TRUE },
    676    { CKM_IKE1_EXTENDED_DERIVE, { 8, 255 * 64, CKF_DERIVE }, PR_TRUE },
    677    { CKM_NSS_IKE_PRF_PLUS_DERIVE, { 8, 255 * 64, CKF_DERIVE }, PR_TRUE },
    678    { CKM_NSS_IKE_PRF_DERIVE, { 8, 64, CKF_DERIVE }, PR_TRUE },
    679    { CKM_NSS_IKE1_PRF_DERIVE, { 8, 64, CKF_DERIVE }, PR_TRUE },
    680    { CKM_NSS_IKE1_APP_B_PRF_DERIVE, { 8, 255 * 64, CKF_DERIVE }, PR_TRUE },
    681 /* -------------------- Kyber Operations ----------------------- */
    682 #ifndef NSS_DISABLE_KYBER
    683    { CKM_NSS_KYBER_KEY_PAIR_GEN, { 0, 0, CKF_GENERATE_KEY_PAIR }, PR_TRUE },
    684    { CKM_NSS_KYBER, { 0, 0, CKF_KEM }, PR_TRUE },
    685 #endif
    686    { CKM_NSS_ML_KEM_KEY_PAIR_GEN, { 0, 0, CKF_GENERATE_KEY_PAIR }, PR_TRUE },
    687    { CKM_NSS_ML_KEM, { 0, 0, CKF_KEM }, PR_TRUE },
    688    { CKM_ML_KEM_KEY_PAIR_GEN, { 0, 0, CKF_GENERATE_KEY_PAIR }, PR_TRUE },
    689    { CKM_ML_KEM, { 0, 0, CKF_KEM }, PR_TRUE },
    690 /* don't advertize ML_DSA support until we have it working in freebl */
    691 #ifdef NSS_ENABLE_ML_DSA
    692    { CKM_ML_DSA_KEY_PAIR_GEN, { ML_DSA_44_PUBLICKEY_LEN, ML_DSA_87_PUBLICKEY_LEN, CKF_GENERATE }, PR_TRUE },
    693    { CKM_ML_DSA, { ML_DSA_44_PUBLICKEY_LEN, ML_DSA_87_PUBLICKEY_LEN, CKF_SN_VR }, PR_TRUE },
    694 #endif
    695 };
    696 static const CK_ULONG mechanismCount = sizeof(mechanisms) / sizeof(mechanisms[0]);
    697 
    698 /* sigh global so fipstokn can read it */
    699 PRBool nsc_init = PR_FALSE;
    700 
    701 #if defined(CHECK_FORK_PTHREAD) || defined(CHECK_FORK_MIXED)
    702 
    703 #include <pthread.h>
    704 
    705 static void
    706 ForkedChild(void)
    707 {
    708    if (nsc_init || nsf_init) {
    709        forked = PR_TRUE;
    710    }
    711 }
    712 
    713 #endif
    714 
    715 #define SFTKFreeWrap(ctxtype, mmm) \
    716    void SFTKFree_##mmm(void *vp)  \
    717    {                              \
    718        ctxtype *p = vp;           \
    719        mmm(p);                    \
    720    }
    721 
    722 SFTKFreeWrap(NSSLOWKEYPublicKey, nsslowkey_DestroyPublicKey);
    723 SFTKFreeWrap(NSSLOWKEYPrivateKey, nsslowkey_DestroyPrivateKey);
    724 
    725 static char *
    726 sftk_setStringName(const char *inString, char *buffer, int buffer_length, PRBool nullTerminate)
    727 {
    728    int full_length, string_length;
    729 
    730    full_length = nullTerminate ? buffer_length - 1 : buffer_length;
    731    string_length = PORT_Strlen(inString);
    732    /*
    733     *  shorten the string, respecting utf8 encoding
    734     *  to do so, we work backward from the end
    735     *  bytes looking from the end are either:
    736     *    - ascii [0x00,0x7f]
    737     *    - the [2-n]th byte of a multibyte sequence
    738     *        [0x3F,0xBF], i.e, most significant 2 bits are '10'
    739     *    - the first byte of a multibyte sequence [0xC0,0xFD],
    740     *        i.e, most significant 2 bits are '11'
    741     *
    742     *    When the string is too long, we lop off any trailing '10' bytes,
    743     *  if any. When these are all eliminated we lop off
    744     *  one additional byte. Thus if we lopped any '10'
    745     *  we'll be lopping a '11' byte (the first byte of the multibyte sequence),
    746     *  otherwise we're lopping off an ascii character.
    747     *
    748     *    To test for '10' bytes, we first AND it with
    749     *  11000000 (0xc0) so that we get 10000000 (0x80) if and only if
    750     *  the byte starts with 10. We test for equality.
    751     */
    752    while (string_length > full_length) {
    753        /* need to shorten */
    754        while (string_length > 0 &&
    755               ((inString[string_length - 1] & (char)0xc0) == (char)0x80)) {
    756            /* lop off '10' byte */
    757            string_length--;
    758        }
    759        /*
    760         * test string_length in case bad data is received
    761         * and string consisted of all '10' bytes,
    762         * avoiding any infinite loop
    763         */
    764        if (string_length) {
    765            /* remove either '11' byte or an asci byte */
    766            string_length--;
    767        }
    768    }
    769    PORT_Memset(buffer, ' ', full_length);
    770    if (nullTerminate) {
    771        buffer[full_length] = 0;
    772    }
    773    PORT_Memcpy(buffer, inString, string_length);
    774    return buffer;
    775 }
    776 /*
    777 * Configuration utils
    778 */
    779 static CK_RV
    780 sftk_configure(const char *man, const char *libdes)
    781 {
    782 
    783    /* make sure the internationalization was done correctly... */
    784    if (man) {
    785        manufacturerID = sftk_setStringName(man, manufacturerID_space,
    786                                            sizeof(manufacturerID_space), PR_TRUE);
    787    }
    788    if (libdes) {
    789        libraryDescription = sftk_setStringName(libdes,
    790                                                libraryDescription_space, sizeof(libraryDescription_space),
    791                                                PR_TRUE);
    792    }
    793 
    794    return CKR_OK;
    795 }
    796 
    797 /*
    798 * ******************** Password Utilities *******************************
    799 */
    800 
    801 /*
    802 * see if the key DB password is enabled
    803 */
    804 static PRBool
    805 sftk_hasNullPassword(SFTKSlot *slot, SFTKDBHandle *keydb)
    806 {
    807    PRBool pwenabled;
    808 
    809    pwenabled = PR_FALSE;
    810    if (sftkdb_HasPasswordSet(keydb) == SECSuccess) {
    811        PRBool tokenRemoved = PR_FALSE;
    812        SECStatus rv = sftkdb_CheckPasswordNull(keydb, &tokenRemoved);
    813        if (tokenRemoved) {
    814            sftk_CloseAllSessions(slot, PR_FALSE);
    815        }
    816        return (rv == SECSuccess);
    817    }
    818 
    819    return pwenabled;
    820 }
    821 
    822 /*
    823 * ******************** Object Creation Utilities ***************************
    824 */
    825 
    826 /* Make sure a given attribute exists. If it doesn't, initialize it to
    827 * value and len
    828 */
    829 CK_RV
    830 sftk_defaultAttribute(SFTKObject *object, CK_ATTRIBUTE_TYPE type,
    831                      const void *value, unsigned int len)
    832 {
    833    if (!sftk_hasAttribute(object, type)) {
    834        return sftk_AddAttributeType(object, type, value, len);
    835    }
    836    return CKR_OK;
    837 }
    838 
    839 /*
    840 * check the consistancy and initialize a Data Object
    841 */
    842 static CK_RV
    843 sftk_handleDataObject(SFTKSession *session, SFTKObject *object)
    844 {
    845    CK_RV crv;
    846 
    847    /* first reject private and token data objects */
    848    if (sftk_isTrue(object, CKA_PRIVATE) || sftk_isTrue(object, CKA_TOKEN)) {
    849        return CKR_ATTRIBUTE_VALUE_INVALID;
    850    }
    851 
    852    /* now just verify the required date fields */
    853    crv = sftk_defaultAttribute(object, CKA_APPLICATION, NULL, 0);
    854    if (crv != CKR_OK)
    855        return crv;
    856    crv = sftk_defaultAttribute(object, CKA_VALUE, NULL, 0);
    857    if (crv != CKR_OK)
    858        return crv;
    859 
    860    return CKR_OK;
    861 }
    862 
    863 /*
    864 * check the consistancy and initialize a Certificate Object
    865 */
    866 static CK_RV
    867 sftk_handleCertObject(SFTKSession *session, SFTKObject *object)
    868 {
    869    CK_CERTIFICATE_TYPE type;
    870    SFTKAttribute *attribute;
    871    CK_RV crv;
    872 
    873    /* certificates must have a type */
    874    if (!sftk_hasAttribute(object, CKA_CERTIFICATE_TYPE)) {
    875        return CKR_TEMPLATE_INCOMPLETE;
    876    }
    877 
    878    /* we can't store any certs private */
    879    if (sftk_isTrue(object, CKA_PRIVATE)) {
    880        return CKR_ATTRIBUTE_VALUE_INVALID;
    881    }
    882 
    883    /* We only support X.509 Certs for now */
    884    attribute = sftk_FindAttribute(object, CKA_CERTIFICATE_TYPE);
    885    if (attribute == NULL)
    886        return CKR_TEMPLATE_INCOMPLETE;
    887    type = *(CK_CERTIFICATE_TYPE *)attribute->attrib.pValue;
    888    sftk_FreeAttribute(attribute);
    889 
    890    if (type != CKC_X_509) {
    891        return CKR_ATTRIBUTE_VALUE_INVALID;
    892    }
    893 
    894    /* X.509 Certificate */
    895 
    896    /* make sure we have a cert */
    897    if (!sftk_hasAttribute(object, CKA_VALUE)) {
    898        return CKR_TEMPLATE_INCOMPLETE;
    899    }
    900 
    901    /* in PKCS #11, Subject is a required field */
    902    if (!sftk_hasAttribute(object, CKA_SUBJECT)) {
    903        return CKR_TEMPLATE_INCOMPLETE;
    904    }
    905 
    906    /* in PKCS #11, Issuer is a required field */
    907    if (!sftk_hasAttribute(object, CKA_ISSUER)) {
    908        return CKR_TEMPLATE_INCOMPLETE;
    909    }
    910 
    911    /* in PKCS #11, Serial is a required field */
    912    if (!sftk_hasAttribute(object, CKA_SERIAL_NUMBER)) {
    913        return CKR_TEMPLATE_INCOMPLETE;
    914    }
    915 
    916    /* add it to the object */
    917    object->objectInfo = NULL;
    918    object->infoFree = (SFTKFree)NULL;
    919 
    920    /* now just verify the required date fields */
    921    crv = sftk_defaultAttribute(object, CKA_ID, NULL, 0);
    922    if (crv != CKR_OK) {
    923        return crv;
    924    }
    925 
    926    if (sftk_isTrue(object, CKA_TOKEN)) {
    927        SFTKSlot *slot = session->slot;
    928        SFTKDBHandle *certHandle = sftk_getCertDB(slot);
    929 
    930        if (certHandle == NULL) {
    931            return CKR_TOKEN_WRITE_PROTECTED;
    932        }
    933 
    934        crv = sftkdb_write(certHandle, object, &object->handle);
    935        sftk_freeDB(certHandle);
    936        return crv;
    937    }
    938 
    939    return CKR_OK;
    940 }
    941 
    942 /*
    943 * check the consistancy and initialize a Trust Object
    944 */
    945 static CK_RV
    946 sftk_handleNSSTrustObject(SFTKSession *session, SFTKObject *object)
    947 {
    948    /* we can't store any certs private */
    949    if (sftk_isTrue(object, CKA_PRIVATE)) {
    950        return CKR_ATTRIBUTE_VALUE_INVALID;
    951    }
    952 
    953    /* certificates must have a type */
    954    if (!sftk_hasAttribute(object, CKA_ISSUER)) {
    955        return CKR_TEMPLATE_INCOMPLETE;
    956    }
    957    if (!sftk_hasAttribute(object, CKA_SERIAL_NUMBER)) {
    958        return CKR_TEMPLATE_INCOMPLETE;
    959    }
    960    if (!sftk_hasAttribute(object, CKA_NSS_CERT_SHA1_HASH)) {
    961        return CKR_TEMPLATE_INCOMPLETE;
    962    }
    963    if (!sftk_hasAttribute(object, CKA_NSS_CERT_MD5_HASH)) {
    964        return CKR_TEMPLATE_INCOMPLETE;
    965    }
    966 
    967    if (sftk_isTrue(object, CKA_TOKEN)) {
    968        SFTKSlot *slot = session->slot;
    969        SFTKDBHandle *certHandle = sftk_getCertDB(slot);
    970        CK_RV crv;
    971 
    972        if (certHandle == NULL) {
    973            return CKR_TOKEN_WRITE_PROTECTED;
    974        }
    975 
    976        crv = sftkdb_write(certHandle, object, &object->handle);
    977        sftk_freeDB(certHandle);
    978        return crv;
    979    }
    980 
    981    return CKR_OK;
    982 }
    983 
    984 /*
    985 * check the consistancy and initialize a Trust Object
    986 */
    987 static CK_RV
    988 sftk_handleTrustObject(SFTKSession *session, SFTKObject *object)
    989 {
    990    /* we can't store any certs private */
    991    if (sftk_isTrue(object, CKA_PRIVATE)) {
    992        return CKR_ATTRIBUTE_VALUE_INVALID;
    993    }
    994 
    995    /* certificates must have a type */
    996    if (!sftk_hasAttribute(object, CKA_ISSUER)) {
    997        return CKR_TEMPLATE_INCOMPLETE;
    998    }
    999    if (!sftk_hasAttribute(object, CKA_SERIAL_NUMBER)) {
   1000        return CKR_TEMPLATE_INCOMPLETE;
   1001    }
   1002    if (!sftk_hasAttribute(object, CKA_HASH_OF_CERTIFICATE)) {
   1003        return CKR_TEMPLATE_INCOMPLETE;
   1004    }
   1005    if (!sftk_hasAttribute(object, CKA_NAME_HASH_ALGORITHM)) {
   1006        return CKR_TEMPLATE_INCOMPLETE;
   1007    }
   1008 
   1009    if (sftk_isTrue(object, CKA_TOKEN)) {
   1010        SFTKSlot *slot = session->slot;
   1011        SFTKDBHandle *certHandle = sftk_getCertDB(slot);
   1012        CK_RV crv;
   1013 
   1014        if (certHandle == NULL) {
   1015            return CKR_TOKEN_WRITE_PROTECTED;
   1016        }
   1017 
   1018        crv = sftkdb_write(certHandle, object, &object->handle);
   1019        sftk_freeDB(certHandle);
   1020        return crv;
   1021    }
   1022 
   1023    return CKR_OK;
   1024 }
   1025 
   1026 /*
   1027 * check the consistancy and initialize a Trust Object
   1028 */
   1029 static CK_RV
   1030 sftk_handleSMimeObject(SFTKSession *session, SFTKObject *object)
   1031 {
   1032 
   1033    /* we can't store any certs private */
   1034    if (sftk_isTrue(object, CKA_PRIVATE)) {
   1035        return CKR_ATTRIBUTE_VALUE_INVALID;
   1036    }
   1037 
   1038    /* certificates must have a type */
   1039    if (!sftk_hasAttribute(object, CKA_SUBJECT)) {
   1040        return CKR_TEMPLATE_INCOMPLETE;
   1041    }
   1042    if (!sftk_hasAttribute(object, CKA_NSS_EMAIL)) {
   1043        return CKR_TEMPLATE_INCOMPLETE;
   1044    }
   1045 
   1046    if (sftk_isTrue(object, CKA_TOKEN)) {
   1047        SFTKSlot *slot = session->slot;
   1048        SFTKDBHandle *certHandle;
   1049        CK_RV crv;
   1050 
   1051        PORT_Assert(slot);
   1052        if (slot == NULL) {
   1053            return CKR_SESSION_HANDLE_INVALID;
   1054        }
   1055 
   1056        certHandle = sftk_getCertDB(slot);
   1057        if (certHandle == NULL) {
   1058            return CKR_TOKEN_WRITE_PROTECTED;
   1059        }
   1060 
   1061        crv = sftkdb_write(certHandle, object, &object->handle);
   1062        sftk_freeDB(certHandle);
   1063        return crv;
   1064    }
   1065 
   1066    return CKR_OK;
   1067 }
   1068 
   1069 /*
   1070 * check the consistancy and initialize a Trust Object
   1071 */
   1072 static CK_RV
   1073 sftk_handleCrlObject(SFTKSession *session, SFTKObject *object)
   1074 {
   1075 
   1076    /* we can't store any certs private */
   1077    if (sftk_isTrue(object, CKA_PRIVATE)) {
   1078        return CKR_ATTRIBUTE_VALUE_INVALID;
   1079    }
   1080 
   1081    /* certificates must have a type */
   1082    if (!sftk_hasAttribute(object, CKA_SUBJECT)) {
   1083        return CKR_TEMPLATE_INCOMPLETE;
   1084    }
   1085    if (!sftk_hasAttribute(object, CKA_VALUE)) {
   1086        return CKR_TEMPLATE_INCOMPLETE;
   1087    }
   1088 
   1089    if (sftk_isTrue(object, CKA_TOKEN)) {
   1090        SFTKSlot *slot = session->slot;
   1091        SFTKDBHandle *certHandle = sftk_getCertDB(slot);
   1092        CK_RV crv;
   1093 
   1094        if (certHandle == NULL) {
   1095            return CKR_TOKEN_WRITE_PROTECTED;
   1096        }
   1097 
   1098        crv = sftkdb_write(certHandle, object, &object->handle);
   1099        sftk_freeDB(certHandle);
   1100        return crv;
   1101    }
   1102 
   1103    return CKR_OK;
   1104 }
   1105 
   1106 /*
   1107 * check the consistancy and initialize a Public Key Object
   1108 */
   1109 static CK_RV
   1110 sftk_handlePublicKeyObject(SFTKSession *session, SFTKObject *object,
   1111                           CK_KEY_TYPE key_type)
   1112 {
   1113    CK_BBOOL encrypt = CK_TRUE;
   1114    CK_BBOOL recover = CK_TRUE;
   1115    CK_BBOOL wrap = CK_TRUE;
   1116    CK_BBOOL derive = CK_FALSE;
   1117    CK_BBOOL verify = CK_TRUE;
   1118    CK_BBOOL encapsulate = CK_FALSE;
   1119    CK_ULONG paramSet = 0;
   1120    CK_RV crv;
   1121 
   1122    switch (key_type) {
   1123        case CKK_RSA:
   1124            crv = sftk_ConstrainAttribute(object, CKA_MODULUS,
   1125                                          RSA_MIN_MODULUS_BITS, 0, 0);
   1126            if (crv != CKR_OK) {
   1127                return crv;
   1128            }
   1129            crv = sftk_ConstrainAttribute(object, CKA_PUBLIC_EXPONENT, 2, 0, 0);
   1130            if (crv != CKR_OK) {
   1131                return crv;
   1132            }
   1133            break;
   1134        case CKK_DSA:
   1135            crv = sftk_ConstrainAttribute(object, CKA_SUBPRIME,
   1136                                          DSA_MIN_Q_BITS, DSA_MAX_Q_BITS, 0);
   1137            if (crv != CKR_OK) {
   1138                return crv;
   1139            }
   1140            crv = sftk_ConstrainAttribute(object, CKA_PRIME,
   1141                                          DSA_MIN_P_BITS, DSA_MAX_P_BITS, 64);
   1142            if (crv != CKR_OK) {
   1143                return crv;
   1144            }
   1145            crv = sftk_ConstrainAttribute(object, CKA_BASE, 2, DSA_MAX_P_BITS, 0);
   1146            if (crv != CKR_OK) {
   1147                return crv;
   1148            }
   1149            crv = sftk_ConstrainAttribute(object, CKA_VALUE, 2, DSA_MAX_P_BITS, 0);
   1150            if (crv != CKR_OK) {
   1151                return crv;
   1152            }
   1153            encrypt = CK_FALSE;
   1154            recover = CK_FALSE;
   1155            wrap = CK_FALSE;
   1156            break;
   1157        case CKK_DH:
   1158            crv = sftk_ConstrainAttribute(object, CKA_PRIME,
   1159                                          DH_MIN_P_BITS, DH_MAX_P_BITS, 0);
   1160            if (crv != CKR_OK) {
   1161                return crv;
   1162            }
   1163            crv = sftk_ConstrainAttribute(object, CKA_BASE, 2, DH_MAX_P_BITS, 0);
   1164            if (crv != CKR_OK) {
   1165                return crv;
   1166            }
   1167            crv = sftk_ConstrainAttribute(object, CKA_VALUE, 2, DH_MAX_P_BITS, 0);
   1168            if (crv != CKR_OK) {
   1169                return crv;
   1170            }
   1171            verify = CK_FALSE;
   1172            derive = CK_TRUE;
   1173            encrypt = CK_FALSE;
   1174            recover = CK_FALSE;
   1175            wrap = CK_FALSE;
   1176            break;
   1177        case CKK_EC_MONTGOMERY:
   1178        case CKK_EC_EDWARDS:
   1179        case CKK_EC:
   1180            if (!sftk_hasAttribute(object, CKA_EC_PARAMS)) {
   1181                return CKR_TEMPLATE_INCOMPLETE;
   1182            }
   1183            if (!sftk_hasAttribute(object, CKA_EC_POINT)) {
   1184                return CKR_TEMPLATE_INCOMPLETE;
   1185            }
   1186            /* for ECDSA and EDDSA. Change if the structure of any of them is modified. */
   1187            derive = (key_type == CKK_EC_EDWARDS) ? CK_FALSE : CK_TRUE;    /* CK_TRUE for ECDH */
   1188            verify = (key_type == CKK_EC_MONTGOMERY) ? CK_FALSE : CK_TRUE; /* for ECDSA and EDDSA */
   1189            encrypt = CK_FALSE;
   1190            recover = CK_FALSE;
   1191            wrap = CK_FALSE;
   1192            break;
   1193 #ifndef NSS_DISABLE_KYBER
   1194        case CKK_NSS_KYBER:
   1195 #endif
   1196        case CKK_NSS_ML_KEM:
   1197        case CKK_ML_KEM:
   1198            if (!sftk_hasAttribute(object, CKA_PARAMETER_SET)) {
   1199                if (!sftk_hasAttribute(object, CKA_NSS_PARAMETER_SET)) {
   1200                    return CKR_TEMPLATE_INCOMPLETE;
   1201                }
   1202            }
   1203            derive = CK_FALSE;
   1204            verify = CK_FALSE;
   1205            encrypt = CK_FALSE;
   1206            recover = CK_FALSE;
   1207            wrap = CK_FALSE;
   1208            encapsulate = CK_TRUE;
   1209            break;
   1210        case CKK_ML_DSA:
   1211            if (!sftk_hasAttribute(object, CKA_PARAMETER_SET)) {
   1212                return CKR_TEMPLATE_INCOMPLETE;
   1213            }
   1214            crv = sftk_GetULongAttribute(object, CKA_PARAMETER_SET,
   1215                                         &paramSet);
   1216            if (crv != CKR_OK) {
   1217                return crv;
   1218            }
   1219            if (sftk_MLDSAGetSigLen(paramSet) == 0) {
   1220                return CKR_ATTRIBUTE_VALUE_INVALID;
   1221            }
   1222            derive = CK_FALSE;
   1223            verify = CK_TRUE;
   1224            encrypt = CK_FALSE;
   1225            recover = CK_FALSE;
   1226            wrap = CK_FALSE;
   1227            encapsulate = CK_FALSE;
   1228            break;
   1229        default:
   1230            return CKR_ATTRIBUTE_VALUE_INVALID;
   1231    }
   1232 
   1233    /* make sure the required fields exist */
   1234    crv = sftk_defaultAttribute(object, CKA_SUBJECT, NULL, 0);
   1235    if (crv != CKR_OK)
   1236        return crv;
   1237    crv = sftk_defaultAttribute(object, CKA_ENCRYPT, &encrypt, sizeof(CK_BBOOL));
   1238    if (crv != CKR_OK)
   1239        return crv;
   1240    crv = sftk_defaultAttribute(object, CKA_VERIFY, &verify, sizeof(CK_BBOOL));
   1241    if (crv != CKR_OK)
   1242        return crv;
   1243    crv = sftk_defaultAttribute(object, CKA_VERIFY_RECOVER,
   1244                                &recover, sizeof(CK_BBOOL));
   1245    if (crv != CKR_OK)
   1246        return crv;
   1247    crv = sftk_defaultAttribute(object, CKA_WRAP, &wrap, sizeof(CK_BBOOL));
   1248    if (crv != CKR_OK)
   1249        return crv;
   1250    crv = sftk_defaultAttribute(object, CKA_DERIVE, &derive, sizeof(CK_BBOOL));
   1251    if (crv != CKR_OK)
   1252        return crv;
   1253    crv = sftk_defaultAttribute(object, CKA_ENCAPSULATE, &encapsulate,
   1254                                sizeof(CK_BBOOL));
   1255    if (crv != CKR_OK)
   1256        return crv;
   1257    object->objectInfo = sftk_GetPubKey(object, key_type, &crv);
   1258    if (object->objectInfo == NULL) {
   1259        return crv;
   1260    }
   1261    object->infoFree = SFTKFree_nsslowkey_DestroyPublicKey;
   1262 
   1263    /* Check that an imported EC key is valid */
   1264    if (key_type == CKK_EC || key_type == CKK_EC_EDWARDS || key_type == CKK_EC_MONTGOMERY) {
   1265        NSSLOWKEYPublicKey *pubKey = (NSSLOWKEYPublicKey *)object->objectInfo;
   1266        SECStatus rv = EC_ValidatePublicKey(&pubKey->u.ec.ecParams,
   1267                                            &pubKey->u.ec.publicValue);
   1268 
   1269        if (rv != SECSuccess) {
   1270            return CKR_TEMPLATE_INCONSISTENT;
   1271        }
   1272    }
   1273 
   1274    if (sftk_isTrue(object, CKA_TOKEN)) {
   1275        SFTKSlot *slot = session->slot;
   1276        SFTKDBHandle *certHandle = sftk_getCertDB(slot);
   1277 
   1278        if (certHandle == NULL) {
   1279            return CKR_TOKEN_WRITE_PROTECTED;
   1280        }
   1281 
   1282        crv = sftkdb_write(certHandle, object, &object->handle);
   1283        sftk_freeDB(certHandle);
   1284        return crv;
   1285    }
   1286 
   1287    return CKR_OK;
   1288 }
   1289 
   1290 static NSSLOWKEYPrivateKey *
   1291 sftk_mkPrivKey(SFTKObject *object, CK_KEY_TYPE key, CK_RV *rvp);
   1292 
   1293 static SECStatus
   1294 sftk_verifyRSAPrivateKey(SFTKObject *object, PRBool fillIfNeeded);
   1295 
   1296 /*
   1297 * check the consistancy and initialize a Private Key Object
   1298 */
   1299 static CK_RV
   1300 sftk_handlePrivateKeyObject(SFTKSession *session, SFTKObject *object, CK_KEY_TYPE key_type)
   1301 {
   1302    CK_BBOOL cktrue = CK_TRUE;
   1303    CK_BBOOL encrypt = CK_TRUE;
   1304    CK_BBOOL sign = CK_FALSE;
   1305    CK_BBOOL recover = CK_TRUE;
   1306    CK_BBOOL wrap = CK_TRUE;
   1307    CK_BBOOL derive = CK_TRUE;
   1308    CK_BBOOL decapsulate = CK_FALSE;
   1309    CK_BBOOL ckfalse = CK_FALSE;
   1310    CK_ULONG paramSet = 0;
   1311    PRBool createObjectInfo = PR_TRUE;
   1312    PRBool fillPrivateKey = PR_FALSE;
   1313    int missing_rsa_mod_component = 0;
   1314    int missing_rsa_exp_component = 0;
   1315    int missing_rsa_crt_component = 0;
   1316 
   1317    SECItem mod;
   1318    CK_RV crv;
   1319    SECStatus rv;
   1320 
   1321    switch (key_type) {
   1322        case CKK_RSA:
   1323            if (!sftk_hasAttribute(object, CKA_MODULUS)) {
   1324                missing_rsa_mod_component++;
   1325            }
   1326            if (!sftk_hasAttribute(object, CKA_PUBLIC_EXPONENT)) {
   1327                missing_rsa_exp_component++;
   1328            }
   1329            if (!sftk_hasAttribute(object, CKA_PRIVATE_EXPONENT)) {
   1330                missing_rsa_exp_component++;
   1331            }
   1332            if (!sftk_hasAttribute(object, CKA_PRIME_1)) {
   1333                missing_rsa_mod_component++;
   1334            }
   1335            if (!sftk_hasAttribute(object, CKA_PRIME_2)) {
   1336                missing_rsa_mod_component++;
   1337            }
   1338            if (!sftk_hasAttribute(object, CKA_EXPONENT_1)) {
   1339                missing_rsa_crt_component++;
   1340            }
   1341            if (!sftk_hasAttribute(object, CKA_EXPONENT_2)) {
   1342                missing_rsa_crt_component++;
   1343            }
   1344            if (!sftk_hasAttribute(object, CKA_COEFFICIENT)) {
   1345                missing_rsa_crt_component++;
   1346            }
   1347            if (missing_rsa_mod_component || missing_rsa_exp_component ||
   1348                missing_rsa_crt_component) {
   1349                /* we are missing a component, see if we have enough to rebuild
   1350                 * the rest */
   1351                int have_exp = 2 - missing_rsa_exp_component;
   1352                int have_component = 5 -
   1353                                     (missing_rsa_exp_component + missing_rsa_mod_component);
   1354 
   1355                if ((have_exp == 0) || (have_component < 3)) {
   1356                    /* nope, not enough to reconstruct the private key */
   1357                    return CKR_TEMPLATE_INCOMPLETE;
   1358                }
   1359                fillPrivateKey = PR_TRUE;
   1360            }
   1361            /*verify the parameters for consistency*/
   1362            rv = sftk_verifyRSAPrivateKey(object, fillPrivateKey);
   1363            if (rv != SECSuccess) {
   1364                return CKR_TEMPLATE_INCOMPLETE;
   1365            }
   1366 
   1367            /* make sure Netscape DB attribute is set correctly */
   1368            crv = sftk_Attribute2SSecItem(NULL, &mod, object, CKA_MODULUS);
   1369            if (crv != CKR_OK)
   1370                return crv;
   1371            crv = sftk_forceAttribute(object, CKA_NSS_DB,
   1372                                      sftk_item_expand(&mod));
   1373            if (mod.data)
   1374                SECITEM_ZfreeItem(&mod, PR_FALSE);
   1375            if (crv != CKR_OK)
   1376                return crv;
   1377 
   1378            sign = CK_TRUE;
   1379            derive = CK_FALSE;
   1380            break;
   1381        case CKK_DSA:
   1382            if (!sftk_hasAttribute(object, CKA_SUBPRIME)) {
   1383                return CKR_TEMPLATE_INCOMPLETE;
   1384            }
   1385            sign = CK_TRUE;
   1386            derive = CK_FALSE;
   1387        /* fall through */
   1388        case CKK_DH:
   1389            if (!sftk_hasAttribute(object, CKA_PRIME)) {
   1390                return CKR_TEMPLATE_INCOMPLETE;
   1391            }
   1392            if (!sftk_hasAttribute(object, CKA_BASE)) {
   1393                return CKR_TEMPLATE_INCOMPLETE;
   1394            }
   1395            if (!sftk_hasAttribute(object, CKA_VALUE)) {
   1396                return CKR_TEMPLATE_INCOMPLETE;
   1397            }
   1398            /* allow subprime to be set after the fact */
   1399            crv = sftk_defaultAttribute(object, CKA_SUBPRIME, NULL, 0);
   1400            if (crv != CKR_OK) {
   1401                return crv;
   1402            }
   1403            encrypt = CK_FALSE;
   1404            recover = CK_FALSE;
   1405            wrap = CK_FALSE;
   1406            break;
   1407        case CKK_EC:
   1408        case CKK_EC_EDWARDS:
   1409        case CKK_EC_MONTGOMERY:
   1410            if (!sftk_hasAttribute(object, CKA_EC_PARAMS)) {
   1411                return CKR_TEMPLATE_INCOMPLETE;
   1412            }
   1413            if (!sftk_hasAttribute(object, CKA_VALUE)) {
   1414                return CKR_TEMPLATE_INCOMPLETE;
   1415            }
   1416            /* for ECDSA and EDDSA. Change if the structure of any of them is modified. */
   1417            derive = (key_type == CKK_EC_EDWARDS) ? CK_FALSE : CK_TRUE;  /* CK_TRUE for ECDH */
   1418            sign = (key_type == CKK_EC_MONTGOMERY) ? CK_FALSE : CK_TRUE; /* for ECDSA and EDDSA */
   1419            encrypt = CK_FALSE;
   1420            recover = CK_FALSE;
   1421            wrap = CK_FALSE;
   1422            break;
   1423        case CKK_NSS_JPAKE_ROUND1:
   1424            if (!sftk_hasAttribute(object, CKA_PRIME) ||
   1425                !sftk_hasAttribute(object, CKA_SUBPRIME) ||
   1426                !sftk_hasAttribute(object, CKA_BASE)) {
   1427                return CKR_TEMPLATE_INCOMPLETE;
   1428            }
   1429        /* fall through */
   1430        case CKK_NSS_JPAKE_ROUND2:
   1431            /* CKA_NSS_JPAKE_SIGNERID and CKA_NSS_JPAKE_PEERID are checked in
   1432               the J-PAKE code. */
   1433            encrypt = sign = recover = wrap = CK_FALSE;
   1434            derive = CK_TRUE;
   1435            createObjectInfo = PR_FALSE;
   1436            break;
   1437 #ifndef NSS_DISABLE_KYBER
   1438        case CKK_NSS_KYBER:
   1439 #endif
   1440        case CKK_NSS_ML_KEM:
   1441        case CKK_ML_KEM:
   1442            if (!sftk_hasAttribute(object, CKA_KEY_TYPE)) {
   1443                return CKR_TEMPLATE_INCOMPLETE;
   1444            }
   1445            if (!sftk_hasAttribute(object, CKA_VALUE)) {
   1446                return CKR_TEMPLATE_INCOMPLETE;
   1447            }
   1448            if (!sftk_hasAttribute(object, CKA_PARAMETER_SET)) {
   1449                if (!sftk_hasAttribute(object, CKA_NSS_PARAMETER_SET)) {
   1450                    return CKR_TEMPLATE_INCOMPLETE;
   1451                }
   1452            }
   1453            derive = CK_FALSE;
   1454            sign = CK_FALSE;
   1455            encrypt = CK_FALSE;
   1456            recover = CK_FALSE;
   1457            wrap = CK_FALSE;
   1458            decapsulate = CK_TRUE;
   1459            break;
   1460        case CKK_ML_DSA:
   1461            if (!sftk_hasAttribute(object, CKA_KEY_TYPE)) {
   1462                return CKR_TEMPLATE_INCOMPLETE;
   1463            }
   1464            /* make sure we have a CKA_PARAMETER_SET */
   1465            if (!sftk_hasAttribute(object, CKA_PARAMETER_SET)) {
   1466                return CKR_TEMPLATE_INCOMPLETE;
   1467            }
   1468            /* make sure it's one we understand */
   1469            crv = sftk_GetULongAttribute(object, CKA_PARAMETER_SET,
   1470                                         &paramSet);
   1471            if (crv != CKR_OK) {
   1472                return crv;
   1473            }
   1474            if (sftk_MLDSAGetSigLen(paramSet) == 0) {
   1475                return CKR_ATTRIBUTE_VALUE_INVALID;
   1476            }
   1477            /*
   1478             * if we have a seed deal with making sure seed and
   1479             * CKA_VALUE . We skip this step if the SEED and VALUE
   1480             * was generated together by us. */
   1481            if (sftk_hasAttribute(object, CKA_SEED)) {
   1482                PRBool seedOK = sftk_hasAttribute(object, CKA_NSS_SEED_OK);
   1483                SFTKAttribute *seedAttribute = sftk_FindAttribute(object,
   1484                                                                  CKA_SEED);
   1485                PORT_Assert(seedAttribute);
   1486                crv = CKR_OK;
   1487                if (seedAttribute->attrib.ulValueLen != 0) {
   1488                    SFTKAttribute *valueAttribute =
   1489                        sftk_FindAttribute(object, CKA_VALUE);
   1490                    unsigned int valueLen = valueAttribute ? valueAttribute->attrib.ulValueLen : 0;
   1491                    if (!seedOK || valueLen == 0) {
   1492                        MLDSAPrivateKey privKey;
   1493                        MLDSAPublicKey pubKey;
   1494                        SECItem seedItem;
   1495 
   1496                        seedItem.data = seedAttribute->attrib.pValue;
   1497                        seedItem.len = seedAttribute->attrib.ulValueLen;
   1498                        rv = MLDSA_NewKey(paramSet, &seedItem, &privKey,
   1499                                          &pubKey);
   1500                        if (rv != SECSuccess) {
   1501                            crv = CKR_ATTRIBUTE_VALUE_INVALID;
   1502                        } else if (valueLen == 0) {
   1503                            crv = sftk_forceAttribute(object, CKA_VALUE,
   1504                                                      privKey.keyVal,
   1505                                                      privKey.keyValLen);
   1506                        } else {
   1507                            /* we have the value, so we must need to
   1508                             * verify it */
   1509                            PORT_Assert(!seedOK);
   1510                            if ((privKey.keyValLen != valueLen) ||
   1511                                (PORT_Memcmp(valueAttribute->attrib.pValue,
   1512                                             privKey.keyVal, valueLen) != 0)) {
   1513                                crv = CKR_ATTRIBUTE_VALUE_INVALID;
   1514                            }
   1515                        }
   1516                        PORT_SafeZero(&privKey, sizeof(privKey));
   1517                        PORT_SafeZero(&pubKey, sizeof(pubKey));
   1518                    }
   1519                    if (valueAttribute)
   1520                        sftk_FreeAttribute(valueAttribute);
   1521                }
   1522                sftk_FreeAttribute(seedAttribute);
   1523                if (crv != CKR_OK) {
   1524                    return crv;
   1525                }
   1526            }
   1527            sftk_DeleteAttributeType(object, CKA_NSS_SEED_OK);
   1528            /* if we got this far, we should have a CKA_VALUE, either but
   1529             * one given to us, or by it being generated above */
   1530            if (!sftk_hasAttribute(object, CKA_VALUE)) {
   1531                return CKR_TEMPLATE_INCOMPLETE;
   1532            }
   1533            encrypt = decapsulate = recover = wrap = CK_FALSE;
   1534            sign = CK_TRUE;
   1535            break;
   1536 
   1537        default:
   1538            return CKR_ATTRIBUTE_VALUE_INVALID;
   1539    }
   1540    crv = sftk_defaultAttribute(object, CKA_SUBJECT, NULL, 0);
   1541    if (crv != CKR_OK)
   1542        return crv;
   1543    crv = sftk_defaultAttribute(object, CKA_SENSITIVE, &cktrue, sizeof(CK_BBOOL));
   1544    if (crv != CKR_OK)
   1545        return crv;
   1546    crv = sftk_defaultAttribute(object, CKA_EXTRACTABLE, &cktrue, sizeof(CK_BBOOL));
   1547    if (crv != CKR_OK)
   1548        return crv;
   1549    crv = sftk_defaultAttribute(object, CKA_DECRYPT, &encrypt, sizeof(CK_BBOOL));
   1550    if (crv != CKR_OK)
   1551        return crv;
   1552    crv = sftk_defaultAttribute(object, CKA_SIGN, &sign, sizeof(CK_BBOOL));
   1553    if (crv != CKR_OK)
   1554        return crv;
   1555    crv = sftk_defaultAttribute(object, CKA_SIGN_RECOVER, &recover,
   1556                                sizeof(CK_BBOOL));
   1557    if (crv != CKR_OK)
   1558        return crv;
   1559    crv = sftk_defaultAttribute(object, CKA_UNWRAP, &wrap, sizeof(CK_BBOOL));
   1560    if (crv != CKR_OK)
   1561        return crv;
   1562    crv = sftk_defaultAttribute(object, CKA_DERIVE, &derive, sizeof(CK_BBOOL));
   1563    if (crv != CKR_OK)
   1564        return crv;
   1565    crv = sftk_defaultAttribute(object, CKA_DECAPSULATE, &decapsulate,
   1566                                sizeof(CK_BBOOL));
   1567    if (crv != CKR_OK)
   1568        return crv;
   1569    /* the next two bits get modified only in the key gen and token cases */
   1570    crv = sftk_forceAttribute(object, CKA_ALWAYS_SENSITIVE,
   1571                              &ckfalse, sizeof(CK_BBOOL));
   1572    if (crv != CKR_OK)
   1573        return crv;
   1574    crv = sftk_forceAttribute(object, CKA_NEVER_EXTRACTABLE,
   1575                              &ckfalse, sizeof(CK_BBOOL));
   1576    if (crv != CKR_OK)
   1577        return crv;
   1578 
   1579    /* should we check the non-token RSA private keys? */
   1580 
   1581    if (sftk_isTrue(object, CKA_TOKEN)) {
   1582        SFTKSlot *slot = session->slot;
   1583        SFTKDBHandle *keyHandle = sftk_getKeyDB(slot);
   1584 
   1585        if (keyHandle == NULL) {
   1586            return CKR_TOKEN_WRITE_PROTECTED;
   1587        }
   1588 
   1589        crv = sftkdb_write(keyHandle, object, &object->handle);
   1590        sftk_freeDB(keyHandle);
   1591        return crv;
   1592    } else if (createObjectInfo) {
   1593        object->objectInfo = sftk_mkPrivKey(object, key_type, &crv);
   1594        if (object->objectInfo == NULL)
   1595            return crv;
   1596        object->infoFree = SFTKFree_nsslowkey_DestroyPrivateKey;
   1597    }
   1598    return CKR_OK;
   1599 }
   1600 
   1601 /* forward declare the DES formating function for handleSecretKey */
   1602 void sftk_FormatDESKey(unsigned char *key, int length);
   1603 
   1604 /* Validate secret key data, and set defaults */
   1605 static CK_RV
   1606 validateSecretKey(SFTKSession *session, SFTKObject *object,
   1607                  CK_KEY_TYPE key_type, PRBool isFIPS)
   1608 {
   1609    CK_RV crv;
   1610    CK_BBOOL cktrue = CK_TRUE;
   1611    CK_BBOOL ckfalse = CK_FALSE;
   1612    SFTKAttribute *attribute = NULL;
   1613    unsigned long requiredLen;
   1614 
   1615    crv = sftk_defaultAttribute(object, CKA_SENSITIVE,
   1616                                isFIPS ? &cktrue : &ckfalse, sizeof(CK_BBOOL));
   1617    if (crv != CKR_OK)
   1618        return crv;
   1619    crv = sftk_defaultAttribute(object, CKA_EXTRACTABLE,
   1620                                &cktrue, sizeof(CK_BBOOL));
   1621    if (crv != CKR_OK)
   1622        return crv;
   1623    crv = sftk_defaultAttribute(object, CKA_ENCRYPT, &cktrue, sizeof(CK_BBOOL));
   1624    if (crv != CKR_OK)
   1625        return crv;
   1626    crv = sftk_defaultAttribute(object, CKA_DECRYPT, &cktrue, sizeof(CK_BBOOL));
   1627    if (crv != CKR_OK)
   1628        return crv;
   1629    crv = sftk_defaultAttribute(object, CKA_SIGN, &ckfalse, sizeof(CK_BBOOL));
   1630    if (crv != CKR_OK)
   1631        return crv;
   1632    crv = sftk_defaultAttribute(object, CKA_VERIFY, &ckfalse, sizeof(CK_BBOOL));
   1633    if (crv != CKR_OK)
   1634        return crv;
   1635    crv = sftk_defaultAttribute(object, CKA_WRAP, &cktrue, sizeof(CK_BBOOL));
   1636    if (crv != CKR_OK)
   1637        return crv;
   1638    crv = sftk_defaultAttribute(object, CKA_UNWRAP, &cktrue, sizeof(CK_BBOOL));
   1639    if (crv != CKR_OK)
   1640        return crv;
   1641 
   1642    if (!sftk_hasAttribute(object, CKA_VALUE)) {
   1643        return CKR_TEMPLATE_INCOMPLETE;
   1644    }
   1645    /* the next two bits get modified only in the key gen and token cases */
   1646    crv = sftk_forceAttribute(object, CKA_ALWAYS_SENSITIVE,
   1647                              &ckfalse, sizeof(CK_BBOOL));
   1648    if (crv != CKR_OK)
   1649        return crv;
   1650    crv = sftk_forceAttribute(object, CKA_NEVER_EXTRACTABLE,
   1651                              &ckfalse, sizeof(CK_BBOOL));
   1652    if (crv != CKR_OK)
   1653        return crv;
   1654 
   1655    /* some types of keys have a value length */
   1656    crv = CKR_OK;
   1657    switch (key_type) {
   1658        /* force CKA_VALUE_LEN to be set */
   1659        case CKK_GENERIC_SECRET:
   1660        case CKK_RC2:
   1661        case CKK_RC4:
   1662 #if NSS_SOFTOKEN_DOES_RC5
   1663        case CKK_RC5:
   1664 #endif
   1665 #ifdef NSS_SOFTOKEN_DOES_CAST
   1666        case CKK_CAST:
   1667        case CKK_CAST3:
   1668        case CKK_CAST5:
   1669 #endif
   1670 #if NSS_SOFTOKEN_DOES_IDEA
   1671        case CKK_IDEA:
   1672 #endif
   1673            attribute = sftk_FindAttribute(object, CKA_VALUE);
   1674            /* shouldn't happen */
   1675            if (attribute == NULL)
   1676                return CKR_TEMPLATE_INCOMPLETE;
   1677            crv = sftk_forceAttribute(object, CKA_VALUE_LEN,
   1678                                      &attribute->attrib.ulValueLen, sizeof(CK_ULONG));
   1679            sftk_FreeAttribute(attribute);
   1680            break;
   1681        /* force the value to have the correct parity */
   1682        case CKK_DES:
   1683        case CKK_DES2:
   1684        case CKK_DES3:
   1685        case CKK_CDMF:
   1686            attribute = sftk_FindAttribute(object, CKA_VALUE);
   1687            /* shouldn't happen */
   1688            if (attribute == NULL)
   1689                return CKR_TEMPLATE_INCOMPLETE;
   1690            requiredLen = sftk_MapKeySize(key_type);
   1691            if (attribute->attrib.ulValueLen != requiredLen) {
   1692                sftk_FreeAttribute(attribute);
   1693                return CKR_KEY_SIZE_RANGE;
   1694            }
   1695            sftk_FormatDESKey((unsigned char *)attribute->attrib.pValue,
   1696                              attribute->attrib.ulValueLen);
   1697            sftk_FreeAttribute(attribute);
   1698            break;
   1699        case CKK_AES:
   1700            attribute = sftk_FindAttribute(object, CKA_VALUE);
   1701            /* shouldn't happen */
   1702            if (attribute == NULL)
   1703                return CKR_TEMPLATE_INCOMPLETE;
   1704            if (attribute->attrib.ulValueLen != 16 &&
   1705                attribute->attrib.ulValueLen != 24 &&
   1706                attribute->attrib.ulValueLen != 32) {
   1707                sftk_FreeAttribute(attribute);
   1708                return CKR_KEY_SIZE_RANGE;
   1709            }
   1710            crv = sftk_forceAttribute(object, CKA_VALUE_LEN,
   1711                                      &attribute->attrib.ulValueLen, sizeof(CK_ULONG));
   1712            sftk_FreeAttribute(attribute);
   1713            break;
   1714        default:
   1715            break;
   1716    }
   1717 
   1718    return crv;
   1719 }
   1720 
   1721 /*
   1722 * check the consistancy and initialize a Secret Key Object
   1723 */
   1724 static CK_RV
   1725 sftk_handleSecretKeyObject(SFTKSession *session, SFTKObject *object,
   1726                           CK_KEY_TYPE key_type, PRBool isFIPS)
   1727 {
   1728    CK_RV crv;
   1729 
   1730    /* First validate and set defaults */
   1731    crv = validateSecretKey(session, object, key_type, isFIPS);
   1732    if (crv != CKR_OK)
   1733        goto loser;
   1734 
   1735    /* If the object is a TOKEN object, store in the database */
   1736    if (sftk_isTrue(object, CKA_TOKEN)) {
   1737        SFTKSlot *slot = session->slot;
   1738        SFTKDBHandle *keyHandle = sftk_getKeyDB(slot);
   1739 
   1740        if (keyHandle == NULL) {
   1741            return CKR_TOKEN_WRITE_PROTECTED;
   1742        }
   1743 
   1744        crv = sftkdb_write(keyHandle, object, &object->handle);
   1745        sftk_freeDB(keyHandle);
   1746        return crv;
   1747    }
   1748 
   1749 loser:
   1750 
   1751    return crv;
   1752 }
   1753 
   1754 /*
   1755 * check the consistancy and initialize a Key Object
   1756 */
   1757 static CK_RV
   1758 sftk_handleKeyObject(SFTKSession *session, SFTKObject *object)
   1759 {
   1760    SFTKAttribute *attribute;
   1761    CK_KEY_TYPE key_type;
   1762    CK_BBOOL ckfalse = CK_FALSE;
   1763    CK_RV crv;
   1764 
   1765    /* verify the required fields */
   1766    if (!sftk_hasAttribute(object, CKA_KEY_TYPE)) {
   1767        return CKR_TEMPLATE_INCOMPLETE;
   1768    }
   1769 
   1770    /* now verify the common fields */
   1771    crv = sftk_defaultAttribute(object, CKA_ID, NULL, 0);
   1772    if (crv != CKR_OK)
   1773        return crv;
   1774    crv = sftk_defaultAttribute(object, CKA_START_DATE, NULL, 0);
   1775    if (crv != CKR_OK)
   1776        return crv;
   1777    crv = sftk_defaultAttribute(object, CKA_END_DATE, NULL, 0);
   1778    if (crv != CKR_OK)
   1779        return crv;
   1780    /* CKA_DERIVE is common to all keys, but it's default value is
   1781     * key dependent */
   1782    crv = sftk_defaultAttribute(object, CKA_LOCAL, &ckfalse, sizeof(CK_BBOOL));
   1783    if (crv != CKR_OK)
   1784        return crv;
   1785 
   1786    /* get the key type */
   1787    attribute = sftk_FindAttribute(object, CKA_KEY_TYPE);
   1788    if (!attribute) {
   1789        return CKR_ATTRIBUTE_VALUE_INVALID;
   1790    }
   1791    key_type = *(CK_KEY_TYPE *)attribute->attrib.pValue;
   1792    sftk_FreeAttribute(attribute);
   1793 
   1794    switch (object->objclass) {
   1795        case CKO_PUBLIC_KEY:
   1796            return sftk_handlePublicKeyObject(session, object, key_type);
   1797        case CKO_PRIVATE_KEY:
   1798            return sftk_handlePrivateKeyObject(session, object, key_type);
   1799        case CKO_SECRET_KEY:
   1800            /* make sure the required fields exist */
   1801            return sftk_handleSecretKeyObject(session, object, key_type,
   1802                                              (PRBool)(sftk_isFIPS(session->slot->slotID)));
   1803        default:
   1804            break;
   1805    }
   1806    return CKR_ATTRIBUTE_VALUE_INVALID;
   1807 }
   1808 
   1809 /*
   1810 * check the consistancy and Verify a DSA Parameter Object
   1811 */
   1812 static CK_RV
   1813 sftk_handleDSAParameterObject(SFTKSession *session, SFTKObject *object)
   1814 {
   1815    SFTKAttribute *primeAttr = NULL;
   1816    SFTKAttribute *subPrimeAttr = NULL;
   1817    SFTKAttribute *baseAttr = NULL;
   1818    SFTKAttribute *seedAttr = NULL;
   1819    SFTKAttribute *hAttr = NULL;
   1820    SFTKAttribute *attribute;
   1821    CK_RV crv = CKR_TEMPLATE_INCOMPLETE;
   1822    PQGParams params;
   1823    PQGVerify vfy, *verify = NULL;
   1824    SECStatus result, rv;
   1825    /* This bool keeps track of whether or not we need verify parameters.
   1826     * If a P, Q and G or supplied, we dont' need verify parameters, as we
   1827     * have PQ and G.
   1828     *   - If G is not supplied, the presumption is that we want to
   1829     * verify P and Q only.
   1830     *   - If counter is supplied, it is presumed we want to verify PQ because
   1831     * the counter is only used in verification.
   1832     *   - If H is supplied, is is presumed we want to verify G because H is
   1833     * only used to verify G.
   1834     *   - Any verification step must have the SEED (counter or H could be
   1835     * missing depending on exactly what we want to verify). If SEED is supplied,
   1836     * the code just goes ahead and runs verify (other errors are parameter
   1837     * errors are detected by the PQG_VerifyParams function). If SEED is not
   1838     * supplied, but we determined that we are trying to verify (because needVfy
   1839     * is set, go ahead and return CKR_TEMPLATE_INCOMPLETE.
   1840     */
   1841    PRBool needVfy = PR_FALSE;
   1842 
   1843    primeAttr = sftk_FindAttribute(object, CKA_PRIME);
   1844    if (primeAttr == NULL)
   1845        goto loser;
   1846    params.prime.data = primeAttr->attrib.pValue;
   1847    params.prime.len = primeAttr->attrib.ulValueLen;
   1848 
   1849    subPrimeAttr = sftk_FindAttribute(object, CKA_SUBPRIME);
   1850    if (subPrimeAttr == NULL)
   1851        goto loser;
   1852    params.subPrime.data = subPrimeAttr->attrib.pValue;
   1853    params.subPrime.len = subPrimeAttr->attrib.ulValueLen;
   1854 
   1855    baseAttr = sftk_FindAttribute(object, CKA_BASE);
   1856    if (baseAttr != NULL) {
   1857        params.base.data = baseAttr->attrib.pValue;
   1858        params.base.len = baseAttr->attrib.ulValueLen;
   1859    } else {
   1860        params.base.data = NULL;
   1861        params.base.len = 0;
   1862        needVfy = PR_TRUE; /* presumably only including PQ so we can verify
   1863                            * them. */
   1864    }
   1865 
   1866    attribute = sftk_FindAttribute(object, CKA_NSS_PQG_COUNTER);
   1867    if (attribute != NULL) {
   1868        vfy.counter = *(CK_ULONG *)attribute->attrib.pValue;
   1869        sftk_FreeAttribute(attribute);
   1870        needVfy = PR_TRUE; /* included a count so we can verify PQ */
   1871    } else {
   1872        vfy.counter = -1;
   1873    }
   1874 
   1875    hAttr = sftk_FindAttribute(object, CKA_NSS_PQG_H);
   1876    if (hAttr != NULL) {
   1877        vfy.h.data = hAttr->attrib.pValue;
   1878        vfy.h.len = hAttr->attrib.ulValueLen;
   1879        needVfy = PR_TRUE; /* included H so we can verify G */
   1880    } else {
   1881        vfy.h.data = NULL;
   1882        vfy.h.len = 0;
   1883    }
   1884    seedAttr = sftk_FindAttribute(object, CKA_NSS_PQG_SEED);
   1885    if (seedAttr != NULL) {
   1886        vfy.seed.data = seedAttr->attrib.pValue;
   1887        vfy.seed.len = seedAttr->attrib.ulValueLen;
   1888 
   1889        verify = &vfy;
   1890    } else if (needVfy) {
   1891        goto loser; /* Verify always needs seed, if we need verify and not seed
   1892                     * then fail */
   1893    }
   1894 
   1895    crv = CKR_FUNCTION_FAILED;
   1896    rv = PQG_VerifyParams(&params, verify, &result);
   1897    if (rv == SECSuccess) {
   1898        crv = (result == SECSuccess) ? CKR_OK : CKR_ATTRIBUTE_VALUE_INVALID;
   1899    }
   1900 
   1901 loser:
   1902    if (hAttr)
   1903        sftk_FreeAttribute(hAttr);
   1904    if (seedAttr)
   1905        sftk_FreeAttribute(seedAttr);
   1906    if (baseAttr)
   1907        sftk_FreeAttribute(baseAttr);
   1908    if (subPrimeAttr)
   1909        sftk_FreeAttribute(subPrimeAttr);
   1910    if (primeAttr)
   1911        sftk_FreeAttribute(primeAttr);
   1912 
   1913    return crv;
   1914 }
   1915 
   1916 /*
   1917 * check the consistancy and initialize a Key Parameter Object
   1918 */
   1919 static CK_RV
   1920 sftk_handleKeyParameterObject(SFTKSession *session, SFTKObject *object)
   1921 {
   1922    SFTKAttribute *attribute;
   1923    CK_KEY_TYPE key_type;
   1924    CK_BBOOL ckfalse = CK_FALSE;
   1925    CK_RV crv;
   1926 
   1927    /* verify the required fields */
   1928    if (!sftk_hasAttribute(object, CKA_KEY_TYPE)) {
   1929        return CKR_TEMPLATE_INCOMPLETE;
   1930    }
   1931 
   1932    /* now verify the common fields */
   1933    crv = sftk_defaultAttribute(object, CKA_LOCAL, &ckfalse, sizeof(CK_BBOOL));
   1934    if (crv != CKR_OK)
   1935        return crv;
   1936 
   1937    /* get the key type */
   1938    attribute = sftk_FindAttribute(object, CKA_KEY_TYPE);
   1939    if (!attribute) {
   1940        return CKR_ATTRIBUTE_VALUE_INVALID;
   1941    }
   1942    key_type = *(CK_KEY_TYPE *)attribute->attrib.pValue;
   1943    sftk_FreeAttribute(attribute);
   1944 
   1945    switch (key_type) {
   1946        case CKK_DSA:
   1947            return sftk_handleDSAParameterObject(session, object);
   1948 
   1949        default:
   1950            break;
   1951    }
   1952    return CKR_KEY_TYPE_INCONSISTENT;
   1953 }
   1954 
   1955 /*
   1956 * Handle Object does all the object consistancy checks, automatic attribute
   1957 * generation, attribute defaulting, etc. If handleObject succeeds, the object
   1958 * will be assigned an object handle, and the object installed in the session
   1959 * or stored in the DB.
   1960 */
   1961 CK_RV
   1962 sftk_handleObject(SFTKObject *object, SFTKSession *session)
   1963 {
   1964    SFTKSlot *slot = session->slot;
   1965    SFTKAttribute *attribute;
   1966    CK_BBOOL ckfalse = CK_FALSE;
   1967    CK_BBOOL cktrue = CK_TRUE;
   1968    PRBool isLoggedIn, needLogin;
   1969    CK_RV crv;
   1970 
   1971    /* make sure all the base object types are defined. If not set the
   1972     * defaults */
   1973    crv = sftk_defaultAttribute(object, CKA_TOKEN, &ckfalse, sizeof(CK_BBOOL));
   1974    if (crv != CKR_OK)
   1975        return crv;
   1976    crv = sftk_defaultAttribute(object, CKA_PRIVATE, &ckfalse, sizeof(CK_BBOOL));
   1977    if (crv != CKR_OK)
   1978        return crv;
   1979    crv = sftk_defaultAttribute(object, CKA_LABEL, NULL, 0);
   1980    if (crv != CKR_OK)
   1981        return crv;
   1982    crv = sftk_defaultAttribute(object, CKA_MODIFIABLE, &cktrue, sizeof(CK_BBOOL));
   1983    if (crv != CKR_OK)
   1984        return crv;
   1985 
   1986    PZ_Lock(slot->slotLock);
   1987    isLoggedIn = slot->isLoggedIn;
   1988    needLogin = slot->needLogin;
   1989    PZ_Unlock(slot->slotLock);
   1990 
   1991    /* don't create a private object if we aren't logged in */
   1992    if (!isLoggedIn && needLogin && sftk_isTrue(object, CKA_PRIVATE)) {
   1993        return CKR_USER_NOT_LOGGED_IN;
   1994    }
   1995 
   1996    if (((session->info.flags & CKF_RW_SESSION) == 0) &&
   1997        (sftk_isTrue(object, CKA_TOKEN))) {
   1998        return CKR_SESSION_READ_ONLY;
   1999    }
   2000 
   2001    /* Assign a unique SESSION object handle to every new object,
   2002     * whether it is a session object or a token object.
   2003     * At this point, all new objects are structured as session objects.
   2004     * Objects with the CKA_TOKEN attribute true will be turned into
   2005     * token objects and will have a token object handle assigned to
   2006     * them by a call to sftk_mkHandle in the handler for each object
   2007     * class, invoked below.
   2008     *
   2009     * It may be helpful to note/remember that
   2010     * sftk_narrowToXxxObject uses sftk_isToken,
   2011     * sftk_isToken examines the sign bit of the object's handle, but
   2012     * sftk_isTrue(...,CKA_TOKEN) examines the CKA_TOKEN attribute.
   2013     */
   2014    object->handle = sftk_getNextHandle(slot);
   2015 
   2016    /* get the object class */
   2017    attribute = sftk_FindAttribute(object, CKA_CLASS);
   2018    if (attribute == NULL) {
   2019        return CKR_TEMPLATE_INCOMPLETE;
   2020    }
   2021    object->objclass = *(CK_OBJECT_CLASS *)attribute->attrib.pValue;
   2022    sftk_FreeAttribute(attribute);
   2023 
   2024    /* Now handle the specific object class.
   2025     * At this point, all objects are session objects, and the session
   2026     * number must be passed to the object class handlers.
   2027     */
   2028    switch (object->objclass) {
   2029        case CKO_DATA:
   2030            crv = sftk_handleDataObject(session, object);
   2031            break;
   2032        case CKO_CERTIFICATE:
   2033            crv = sftk_handleCertObject(session, object);
   2034            break;
   2035        case CKO_NSS_TRUST:
   2036            crv = sftk_handleNSSTrustObject(session, object);
   2037            break;
   2038        case CKO_TRUST:
   2039            crv = sftk_handleTrustObject(session, object);
   2040            break;
   2041        case CKO_NSS_CRL:
   2042            crv = sftk_handleCrlObject(session, object);
   2043            break;
   2044        case CKO_NSS_SMIME:
   2045            crv = sftk_handleSMimeObject(session, object);
   2046            break;
   2047        case CKO_PRIVATE_KEY:
   2048        case CKO_PUBLIC_KEY:
   2049        case CKO_SECRET_KEY:
   2050            crv = sftk_handleKeyObject(session, object);
   2051            break;
   2052        case CKO_DOMAIN_PARAMETERS:
   2053            crv = sftk_handleKeyParameterObject(session, object);
   2054            break;
   2055        default:
   2056            crv = CKR_ATTRIBUTE_VALUE_INVALID;
   2057            break;
   2058    }
   2059 
   2060    /* can't fail from here on out unless the pk_handlXXX functions have
   2061     * failed the request */
   2062    if (crv != CKR_OK) {
   2063        return crv;
   2064    }
   2065 
   2066    /* Now link the object into the slot and session structures.
   2067     * If the object has a true CKA_TOKEN attribute, the above object
   2068     * class handlers will have set the sign bit in the object handle,
   2069     * causing the following test to be true.
   2070     */
   2071    if (sftk_isToken(object->handle)) {
   2072        sftk_convertSessionToToken(object);
   2073    } else {
   2074        object->slot = slot;
   2075        sftk_AddObject(session, object);
   2076    }
   2077 
   2078    return CKR_OK;
   2079 }
   2080 
   2081 /*
   2082 * ******************** Public Key Utilities ***************************
   2083 */
   2084 /* Generate a low public key structure from an object */
   2085 NSSLOWKEYPublicKey *
   2086 sftk_GetPubKey(SFTKObject *object, CK_KEY_TYPE key_type,
   2087               CK_RV *crvp)
   2088 {
   2089    NSSLOWKEYPublicKey *pubKey;
   2090    PLArenaPool *arena;
   2091    CK_RV crv;
   2092 
   2093    if (object->objclass != CKO_PUBLIC_KEY) {
   2094        *crvp = CKR_KEY_TYPE_INCONSISTENT;
   2095        return NULL;
   2096    }
   2097 
   2098    if (sftk_isToken(object->handle)) {
   2099        /* ferret out the token object handle */
   2100    }
   2101 
   2102    /* If we already have a key, use it */
   2103    if (object->objectInfo) {
   2104        *crvp = CKR_OK;
   2105        return (NSSLOWKEYPublicKey *)object->objectInfo;
   2106    }
   2107 
   2108    /* allocate the structure */
   2109    arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
   2110    if (arena == NULL) {
   2111        *crvp = CKR_HOST_MEMORY;
   2112        return NULL;
   2113    }
   2114 
   2115    pubKey = (NSSLOWKEYPublicKey *)
   2116        PORT_ArenaAlloc(arena, sizeof(NSSLOWKEYPublicKey));
   2117    if (pubKey == NULL) {
   2118        PORT_FreeArena(arena, PR_FALSE);
   2119        *crvp = CKR_HOST_MEMORY;
   2120        return NULL;
   2121    }
   2122 
   2123    /* fill in the structure */
   2124    pubKey->arena = arena;
   2125    switch (key_type) {
   2126        case CKK_RSA:
   2127            pubKey->keyType = NSSLOWKEYRSAKey;
   2128            crv = sftk_Attribute2SSecItem(arena, &pubKey->u.rsa.modulus,
   2129                                          object, CKA_MODULUS);
   2130            if (crv != CKR_OK)
   2131                break;
   2132            crv = sftk_Attribute2SSecItem(arena, &pubKey->u.rsa.publicExponent,
   2133                                          object, CKA_PUBLIC_EXPONENT);
   2134            break;
   2135        case CKK_DSA:
   2136            pubKey->keyType = NSSLOWKEYDSAKey;
   2137            crv = sftk_Attribute2SSecItem(arena, &pubKey->u.dsa.params.prime,
   2138                                          object, CKA_PRIME);
   2139            if (crv != CKR_OK)
   2140                break;
   2141            crv = sftk_Attribute2SSecItem(arena, &pubKey->u.dsa.params.subPrime,
   2142                                          object, CKA_SUBPRIME);
   2143            if (crv != CKR_OK)
   2144                break;
   2145            crv = sftk_Attribute2SSecItem(arena, &pubKey->u.dsa.params.base,
   2146                                          object, CKA_BASE);
   2147            if (crv != CKR_OK)
   2148                break;
   2149            crv = sftk_Attribute2SSecItem(arena, &pubKey->u.dsa.publicValue,
   2150                                          object, CKA_VALUE);
   2151            break;
   2152        case CKK_DH:
   2153            pubKey->keyType = NSSLOWKEYDHKey;
   2154            crv = sftk_Attribute2SSecItem(arena, &pubKey->u.dh.prime,
   2155                                          object, CKA_PRIME);
   2156            if (crv != CKR_OK)
   2157                break;
   2158            crv = sftk_Attribute2SSecItem(arena, &pubKey->u.dh.base,
   2159                                          object, CKA_BASE);
   2160            if (crv != CKR_OK)
   2161                break;
   2162            crv = sftk_Attribute2SSecItem(arena, &pubKey->u.dh.publicValue,
   2163                                          object, CKA_VALUE);
   2164            break;
   2165        case CKK_EC_EDWARDS:
   2166        case CKK_EC_MONTGOMERY:
   2167        case CKK_EC:
   2168            pubKey->keyType = NSSLOWKEYECKey;
   2169            crv = sftk_Attribute2SSecItem(arena,
   2170                                          &pubKey->u.ec.ecParams.DEREncoding,
   2171                                          object, CKA_EC_PARAMS);
   2172            if (crv != CKR_OK)
   2173                break;
   2174 
   2175            /* Fill out the rest of the ecParams structure
   2176             * based on the encoded params
   2177             */
   2178            if (EC_FillParams(arena, &pubKey->u.ec.ecParams.DEREncoding,
   2179                              &pubKey->u.ec.ecParams) != SECSuccess) {
   2180                crv = CKR_DOMAIN_PARAMS_INVALID;
   2181                break;
   2182            }
   2183 
   2184            crv = sftk_Attribute2SSecItem(arena, &pubKey->u.ec.publicValue,
   2185                                          object, CKA_EC_POINT);
   2186            if (crv == CKR_OK) {
   2187                unsigned int keyLen = EC_GetPointSize(&pubKey->u.ec.ecParams);
   2188                /* special note: We can't just use the first byte to distinguish
   2189                 * between EC_POINT_FORM_UNCOMPRESSED and SEC_ASN1_OCTET_STRING.
   2190                 * Both are 0x04. */
   2191 
   2192                /* Handle the non-DER encoded case.
   2193                 * Some curves are always pressumed to be non-DER.
   2194                 */
   2195 
   2196                /* is the public key in uncompressed form? */
   2197                if (pubKey->u.ec.ecParams.type != ec_params_named ||
   2198                    (pubKey->u.ec.publicValue.len == keyLen &&
   2199                     pubKey->u.ec.publicValue.data[0] == EC_POINT_FORM_UNCOMPRESSED)) {
   2200                    break; /* key was not DER encoded, no need to unwrap */
   2201                }
   2202 
   2203                /* handle the encoded case */
   2204                if (pubKey->u.ec.publicValue.data[0] == SEC_ASN1_OCTET_STRING) {
   2205                    SECItem publicValue;
   2206                    SECStatus rv;
   2207 
   2208                    rv = SEC_QuickDERDecodeItem(arena, &publicValue,
   2209                                                SEC_ASN1_GET(SEC_OctetStringTemplate),
   2210                                                &pubKey->u.ec.publicValue);
   2211                    /* nope, didn't decode correctly */
   2212                    if (rv != SECSuccess) {
   2213                        crv = CKR_ATTRIBUTE_VALUE_INVALID;
   2214                        break;
   2215                    }
   2216 
   2217                    if (publicValue.len == keyLen && publicValue.data[0] == EC_POINT_FORM_UNCOMPRESSED) {
   2218                        /* Received uncompressed point */
   2219                        pubKey->u.ec.publicValue = publicValue;
   2220                        break;
   2221                    }
   2222 
   2223                    /* Trying to decompress */
   2224                    SECItem publicDecompressed = { siBuffer, NULL, 0 };
   2225                    (void)SECITEM_AllocItem(arena, &publicDecompressed, keyLen);
   2226                    if (EC_DecompressPublicKey(&publicValue, &pubKey->u.ec.ecParams, &publicDecompressed) == SECFailure) {
   2227                        crv = CKR_ATTRIBUTE_VALUE_INVALID;
   2228                        break;
   2229                    }
   2230 
   2231                    /* replace our previous public key with the decoded decompressed key */
   2232                    pubKey->u.ec.publicValue = publicDecompressed;
   2233 
   2234                    SECItem publicDecompressedEncoded = { siBuffer, NULL, 0 };
   2235                    (void)SEC_ASN1EncodeItem(arena, &publicDecompressedEncoded, &publicDecompressed,
   2236                                             SEC_ASN1_GET(SEC_OctetStringTemplate));
   2237                    if (CKR_OK != sftk_forceAttribute(object, CKA_EC_POINT, sftk_item_expand(&publicDecompressedEncoded))) {
   2238                        crv = CKR_ATTRIBUTE_VALUE_INVALID;
   2239                        break;
   2240                    }
   2241 
   2242                    break;
   2243                }
   2244                crv = CKR_ATTRIBUTE_VALUE_INVALID;
   2245            }
   2246            break;
   2247 #ifndef NSS_DISABLE_KYBER
   2248        case CKK_NSS_KYBER:
   2249 #endif
   2250        case CKK_NSS_ML_KEM:
   2251        case CKK_ML_KEM:
   2252            crv = CKR_OK;
   2253            break;
   2254        case CKK_ML_DSA:
   2255            pubKey->keyType = NSSLOWKEYMLDSAKey;
   2256            crv = sftk_ReadAttribute(object, CKA_VALUE,
   2257                                     pubKey->u.mldsa.keyVal,
   2258                                     sizeof(pubKey->u.mldsa.keyVal),
   2259                                     &pubKey->u.mldsa.keyValLen);
   2260            if (crv != CKR_OK) {
   2261                break;
   2262            }
   2263            crv = sftk_GetULongAttribute(object, CKA_PARAMETER_SET,
   2264                                         &pubKey->u.mldsa.paramSet);
   2265 
   2266            break;
   2267        default:
   2268            crv = CKR_KEY_TYPE_INCONSISTENT;
   2269            break;
   2270    }
   2271    *crvp = crv;
   2272    if (crv != CKR_OK) {
   2273        PORT_FreeArena(arena, PR_TRUE);
   2274        return NULL;
   2275    }
   2276 
   2277    object->objectInfo = pubKey;
   2278    object->infoFree = SFTKFree_nsslowkey_DestroyPublicKey;
   2279    return pubKey;
   2280 }
   2281 
   2282 /* make a private key from a verified object */
   2283 static NSSLOWKEYPrivateKey *
   2284 sftk_mkPrivKey(SFTKObject *object, CK_KEY_TYPE key_type, CK_RV *crvp)
   2285 {
   2286    NSSLOWKEYPrivateKey *privKey;
   2287    SFTKItemTemplate itemTemplate[SFTK_MAX_ITEM_TEMPLATE];
   2288    int itemTemplateCount = 0;
   2289    PLArenaPool *arena;
   2290    CK_RV crv = CKR_OK;
   2291    SECStatus rv;
   2292 
   2293    arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
   2294    if (arena == NULL) {
   2295        *crvp = CKR_HOST_MEMORY;
   2296        return NULL;
   2297    }
   2298 
   2299    privKey = (NSSLOWKEYPrivateKey *)
   2300        PORT_ArenaZAlloc(arena, sizeof(NSSLOWKEYPrivateKey));
   2301    if (privKey == NULL) {
   2302        PORT_FreeArena(arena, PR_FALSE);
   2303        *crvp = CKR_HOST_MEMORY;
   2304        return NULL;
   2305    }
   2306 
   2307    /* in future this would be a switch on key_type */
   2308    privKey->arena = arena;
   2309    switch (key_type) {
   2310        case CKK_RSA:
   2311            privKey->keyType = NSSLOWKEYRSAKey;
   2312 
   2313            SFTK_SET_ITEM_TEMPLATE(itemTemplate, itemTemplateCount,
   2314                                   &privKey->u.rsa.modulus, CKA_MODULUS);
   2315            itemTemplateCount++;
   2316            SFTK_SET_ITEM_TEMPLATE(itemTemplate, itemTemplateCount,
   2317                                   &privKey->u.rsa.publicExponent, CKA_PUBLIC_EXPONENT);
   2318            itemTemplateCount++;
   2319            SFTK_SET_ITEM_TEMPLATE(itemTemplate, itemTemplateCount,
   2320                                   &privKey->u.rsa.privateExponent, CKA_PRIVATE_EXPONENT);
   2321            itemTemplateCount++;
   2322            SFTK_SET_ITEM_TEMPLATE(itemTemplate, itemTemplateCount,
   2323                                   &privKey->u.rsa.prime1, CKA_PRIME_1);
   2324            itemTemplateCount++;
   2325            SFTK_SET_ITEM_TEMPLATE(itemTemplate, itemTemplateCount,
   2326                                   &privKey->u.rsa.prime2, CKA_PRIME_2);
   2327            itemTemplateCount++;
   2328            SFTK_SET_ITEM_TEMPLATE(itemTemplate, itemTemplateCount,
   2329                                   &privKey->u.rsa.exponent1, CKA_EXPONENT_1);
   2330            itemTemplateCount++;
   2331            SFTK_SET_ITEM_TEMPLATE(itemTemplate, itemTemplateCount,
   2332                                   &privKey->u.rsa.exponent2, CKA_EXPONENT_2);
   2333            itemTemplateCount++;
   2334            SFTK_SET_ITEM_TEMPLATE(itemTemplate, itemTemplateCount,
   2335                                   &privKey->u.rsa.coefficient, CKA_COEFFICIENT);
   2336            itemTemplateCount++;
   2337            rv = DER_SetUInteger(privKey->arena, &privKey->u.rsa.version,
   2338                                 NSSLOWKEY_PRIVATE_KEY_INFO_VERSION);
   2339            if (rv != SECSuccess)
   2340                crv = CKR_HOST_MEMORY;
   2341            break;
   2342 
   2343        case CKK_DSA:
   2344            privKey->keyType = NSSLOWKEYDSAKey;
   2345            SFTK_SET_ITEM_TEMPLATE(itemTemplate, itemTemplateCount,
   2346                                   &privKey->u.dsa.params.prime, CKA_PRIME);
   2347            itemTemplateCount++;
   2348            SFTK_SET_ITEM_TEMPLATE(itemTemplate, itemTemplateCount,
   2349                                   &privKey->u.dsa.params.subPrime, CKA_SUBPRIME);
   2350            itemTemplateCount++;
   2351            SFTK_SET_ITEM_TEMPLATE(itemTemplate, itemTemplateCount,
   2352                                   &privKey->u.dsa.params.base, CKA_BASE);
   2353            itemTemplateCount++;
   2354            SFTK_SET_ITEM_TEMPLATE(itemTemplate, itemTemplateCount,
   2355                                   &privKey->u.dsa.privateValue, CKA_VALUE);
   2356            itemTemplateCount++;
   2357            /* privKey was zero'd so public value is already set to NULL, 0
   2358             * if we don't set it explicitly */
   2359            break;
   2360 
   2361        case CKK_DH:
   2362            privKey->keyType = NSSLOWKEYDHKey;
   2363            SFTK_SET_ITEM_TEMPLATE(itemTemplate, itemTemplateCount,
   2364                                   &privKey->u.dh.prime, CKA_PRIME);
   2365            itemTemplateCount++;
   2366            SFTK_SET_ITEM_TEMPLATE(itemTemplate, itemTemplateCount,
   2367                                   &privKey->u.dh.base, CKA_BASE);
   2368            itemTemplateCount++;
   2369            SFTK_SET_ITEM_TEMPLATE(itemTemplate, itemTemplateCount,
   2370                                   &privKey->u.dh.privateValue, CKA_VALUE);
   2371            itemTemplateCount++;
   2372            /* privKey was zero'd so public value is already set to NULL, 0
   2373             * if we don't set it explicitly */
   2374            break;
   2375        case CKK_EC_EDWARDS:
   2376        case CKK_EC_MONTGOMERY:
   2377        case CKK_EC:
   2378            privKey->keyType = NSSLOWKEYECKey;
   2379            crv = sftk_Attribute2SSecItem(arena,
   2380                                          &privKey->u.ec.ecParams.DEREncoding,
   2381                                          object, CKA_EC_PARAMS);
   2382            if (crv != CKR_OK)
   2383                break;
   2384 
   2385            /* Fill out the rest of the ecParams structure
   2386             * based on the encoded params
   2387             */
   2388            if (EC_FillParams(arena, &privKey->u.ec.ecParams.DEREncoding,
   2389                              &privKey->u.ec.ecParams) != SECSuccess) {
   2390                crv = CKR_DOMAIN_PARAMS_INVALID;
   2391                break;
   2392            }
   2393            crv = sftk_Attribute2SSecItem(arena, &privKey->u.ec.privateValue,
   2394                                          object, CKA_VALUE);
   2395            if (crv != CKR_OK)
   2396                break;
   2397 
   2398            if (sftk_hasAttribute(object, CKA_NSS_DB)) {
   2399                crv = sftk_Attribute2SSecItem(arena, &privKey->u.ec.publicValue,
   2400                                              object, CKA_NSS_DB);
   2401                if (crv != CKR_OK) {
   2402                    break;
   2403                }
   2404                /* privKey was zero'd so public value is already set to NULL, 0
   2405                 * if we don't set it explicitly */
   2406            } else if (key_type == CKK_EC) {
   2407                /* as no public key was provided during the import, we need to derive it here.
   2408                 See: PK11_ImportAndReturnPrivateKey*/
   2409                (void)SECITEM_AllocItem(arena, &privKey->u.ec.publicValue, EC_GetPointSize(&privKey->u.ec.ecParams));
   2410                rv = EC_DerivePublicKey(&privKey->u.ec.privateValue, &privKey->u.ec.ecParams, &privKey->u.ec.publicValue);
   2411                if (rv != SECSuccess) {
   2412                    break;
   2413                }
   2414                sftk_forceAttribute(object, CKA_NSS_DB, privKey->u.ec.publicValue.data, privKey->u.ec.publicValue.len);
   2415            }
   2416 
   2417            rv = DER_SetUInteger(privKey->arena, &privKey->u.ec.version,
   2418                                 NSSLOWKEY_EC_PRIVATE_KEY_VERSION);
   2419            if (rv != SECSuccess) {
   2420                crv = CKR_HOST_MEMORY;
   2421 /* The following ifdef is needed for Linux arm distros and
   2422 * Android as gcc 4.6 has a bug when targeting arm (but not
   2423 * thumb). The bug has been fixed in gcc 4.7.
   2424 * http://gcc.gnu.org/bugzilla/show_bug.cgi?id=56561
   2425 */
   2426 #if defined(__arm__) && !defined(__thumb__) && defined(__GNUC__)
   2427                *crvp = CKR_HOST_MEMORY;
   2428                break;
   2429 #endif
   2430            }
   2431            break;
   2432 
   2433 #ifndef NSS_DISABLE_KYBER
   2434        case CKK_NSS_KYBER:
   2435 #endif
   2436        case CKK_NSS_ML_KEM:
   2437        case CKK_ML_KEM:
   2438            break;
   2439 
   2440        case CKK_ML_DSA:
   2441            privKey->keyType = NSSLOWKEYMLDSAKey;
   2442            crv = sftk_ReadAttribute(object, CKA_VALUE,
   2443                                     privKey->u.mldsa.keyVal,
   2444                                     sizeof(privKey->u.mldsa.keyVal),
   2445                                     &privKey->u.mldsa.keyValLen);
   2446            if (crv != CKR_OK) {
   2447                break;
   2448            }
   2449            crv = sftk_ReadAttribute(object, CKA_SEED,
   2450                                     privKey->u.mldsa.seed,
   2451                                     sizeof(privKey->u.mldsa.seed),
   2452                                     &privKey->u.mldsa.seedLen);
   2453            if (crv != CKR_OK) {
   2454                /* no seed value, just set it to zero. The seed
   2455                 * has been lost or discarded for this key */
   2456                privKey->u.mldsa.seedLen = 0;
   2457            }
   2458            crv = sftk_GetULongAttribute(object, CKA_PARAMETER_SET,
   2459                                         &privKey->u.mldsa.paramSet);
   2460 
   2461            break;
   2462 
   2463        default:
   2464            crv = CKR_KEY_TYPE_INCONSISTENT;
   2465            break;
   2466    }
   2467    if (crv == CKR_OK && itemTemplateCount != 0) {
   2468        PORT_Assert(itemTemplateCount > 0);
   2469        PORT_Assert(itemTemplateCount <= SFTK_MAX_ITEM_TEMPLATE);
   2470        crv = sftk_MultipleAttribute2SecItem(arena, object, itemTemplate,
   2471                                             itemTemplateCount);
   2472    }
   2473    *crvp = crv;
   2474    if (crv != CKR_OK) {
   2475        PORT_FreeArena(arena, PR_TRUE);
   2476        return NULL;
   2477    }
   2478    return privKey;
   2479 }
   2480 
   2481 /*
   2482 * If a partial RSA private key is present, fill in the rest if necessary,
   2483 * and then verify the parameters are well-formed
   2484 */
   2485 static SECStatus
   2486 sftk_verifyRSAPrivateKey(SFTKObject *object, PRBool fillIfNeeded)
   2487 {
   2488    RSAPrivateKey tmpKey = { 0 };
   2489    SFTKAttribute *modulus = NULL;
   2490    SFTKAttribute *prime1 = NULL;
   2491    SFTKAttribute *prime2 = NULL;
   2492    SFTKAttribute *privateExponent = NULL;
   2493    SFTKAttribute *publicExponent = NULL;
   2494    SFTKAttribute *exponent1 = NULL;
   2495    SFTKAttribute *exponent2 = NULL;
   2496    SFTKAttribute *coefficient = NULL;
   2497    SECStatus rv;
   2498    CK_RV crv;
   2499 
   2500    /* first fill in the components that we have. Populate only uses
   2501     * the non-crt components, so only fill those in  */
   2502    tmpKey.arena = NULL;
   2503    modulus = sftk_FindAttribute(object, CKA_MODULUS);
   2504    if (modulus) {
   2505        tmpKey.modulus.data = modulus->attrib.pValue;
   2506        tmpKey.modulus.len = modulus->attrib.ulValueLen;
   2507    }
   2508    prime1 = sftk_FindAttribute(object, CKA_PRIME_1);
   2509    if (prime1) {
   2510        tmpKey.prime1.data = prime1->attrib.pValue;
   2511        tmpKey.prime1.len = prime1->attrib.ulValueLen;
   2512    }
   2513    prime2 = sftk_FindAttribute(object, CKA_PRIME_2);
   2514    if (prime2) {
   2515        tmpKey.prime2.data = prime2->attrib.pValue;
   2516        tmpKey.prime2.len = prime2->attrib.ulValueLen;
   2517    }
   2518    privateExponent = sftk_FindAttribute(object, CKA_PRIVATE_EXPONENT);
   2519    if (privateExponent) {
   2520        tmpKey.privateExponent.data = privateExponent->attrib.pValue;
   2521        tmpKey.privateExponent.len = privateExponent->attrib.ulValueLen;
   2522    }
   2523    publicExponent = sftk_FindAttribute(object, CKA_PUBLIC_EXPONENT);
   2524    if (publicExponent) {
   2525        tmpKey.publicExponent.data = publicExponent->attrib.pValue;
   2526        tmpKey.publicExponent.len = publicExponent->attrib.ulValueLen;
   2527    }
   2528    exponent1 = sftk_FindAttribute(object, CKA_EXPONENT_1);
   2529    if (exponent1) {
   2530        tmpKey.exponent1.data = exponent1->attrib.pValue;
   2531        tmpKey.exponent1.len = exponent1->attrib.ulValueLen;
   2532    }
   2533    exponent2 = sftk_FindAttribute(object, CKA_EXPONENT_2);
   2534    if (exponent2) {
   2535        tmpKey.exponent2.data = exponent2->attrib.pValue;
   2536        tmpKey.exponent2.len = exponent2->attrib.ulValueLen;
   2537    }
   2538    coefficient = sftk_FindAttribute(object, CKA_COEFFICIENT);
   2539    if (coefficient) {
   2540        tmpKey.coefficient.data = coefficient->attrib.pValue;
   2541        tmpKey.coefficient.len = coefficient->attrib.ulValueLen;
   2542    }
   2543 
   2544    if (fillIfNeeded) {
   2545        /*
   2546         * populate requires one exponent plus 2 other components to work.
   2547         * we expected our caller to check that first. If that didn't happen,
   2548         * populate will simply return an error here.
   2549         */
   2550        rv = RSA_PopulatePrivateKey(&tmpKey);
   2551        if (rv != SECSuccess) {
   2552            goto loser;
   2553        }
   2554    }
   2555    rv = RSA_PrivateKeyCheck(&tmpKey);
   2556    if (rv != SECSuccess) {
   2557        goto loser;
   2558    }
   2559    /* now that we have a fully populated key, set all our attribute values */
   2560    rv = SECFailure;
   2561    if (!modulus || modulus->attrib.pValue != tmpKey.modulus.data) {
   2562        crv = sftk_forceAttribute(object, CKA_MODULUS,
   2563                                  sftk_item_expand(&tmpKey.modulus));
   2564        if (crv != CKR_OK)
   2565            goto loser;
   2566    }
   2567    if (!publicExponent ||
   2568        publicExponent->attrib.pValue != tmpKey.publicExponent.data) {
   2569        crv = sftk_forceAttribute(object, CKA_PUBLIC_EXPONENT,
   2570                                  sftk_item_expand(&tmpKey.publicExponent));
   2571        if (crv != CKR_OK)
   2572            goto loser;
   2573    }
   2574    if (!privateExponent ||
   2575        privateExponent->attrib.pValue != tmpKey.privateExponent.data) {
   2576        crv = sftk_forceAttribute(object, CKA_PRIVATE_EXPONENT,
   2577                                  sftk_item_expand(&tmpKey.privateExponent));
   2578        if (crv != CKR_OK)
   2579            goto loser;
   2580    }
   2581    if (!prime1 || prime1->attrib.pValue != tmpKey.prime1.data) {
   2582        crv = sftk_forceAttribute(object, CKA_PRIME_1,
   2583                                  sftk_item_expand(&tmpKey.prime1));
   2584        if (crv != CKR_OK)
   2585            goto loser;
   2586    }
   2587    if (!prime2 || prime2->attrib.pValue != tmpKey.prime2.data) {
   2588        crv = sftk_forceAttribute(object, CKA_PRIME_2,
   2589                                  sftk_item_expand(&tmpKey.prime2));
   2590        if (crv != CKR_OK)
   2591            goto loser;
   2592    }
   2593    if (!exponent1 || exponent1->attrib.pValue != tmpKey.exponent1.data) {
   2594        crv = sftk_forceAttribute(object, CKA_EXPONENT_1,
   2595                                  sftk_item_expand(&tmpKey.exponent1));
   2596        if (crv != CKR_OK)
   2597            goto loser;
   2598    }
   2599    if (!exponent2 || exponent2->attrib.pValue != tmpKey.exponent2.data) {
   2600        crv = sftk_forceAttribute(object, CKA_EXPONENT_2,
   2601                                  sftk_item_expand(&tmpKey.exponent2));
   2602        if (crv != CKR_OK)
   2603            goto loser;
   2604    }
   2605    if (!coefficient || coefficient->attrib.pValue != tmpKey.coefficient.data) {
   2606        crv = sftk_forceAttribute(object, CKA_COEFFICIENT,
   2607                                  sftk_item_expand(&tmpKey.coefficient));
   2608        if (crv != CKR_OK)
   2609            goto loser;
   2610    }
   2611    rv = SECSuccess;
   2612 
   2613 /* we're done (one way or the other), clean up all our stuff */
   2614 loser:
   2615    if (tmpKey.arena) {
   2616        PORT_FreeArena(tmpKey.arena, PR_TRUE);
   2617    }
   2618    if (modulus) {
   2619        sftk_FreeAttribute(modulus);
   2620    }
   2621    if (prime1) {
   2622        sftk_FreeAttribute(prime1);
   2623    }
   2624    if (prime2) {
   2625        sftk_FreeAttribute(prime2);
   2626    }
   2627    if (privateExponent) {
   2628        sftk_FreeAttribute(privateExponent);
   2629    }
   2630    if (publicExponent) {
   2631        sftk_FreeAttribute(publicExponent);
   2632    }
   2633    if (exponent1) {
   2634        sftk_FreeAttribute(exponent1);
   2635    }
   2636    if (exponent2) {
   2637        sftk_FreeAttribute(exponent2);
   2638    }
   2639    if (coefficient) {
   2640        sftk_FreeAttribute(coefficient);
   2641    }
   2642    return rv;
   2643 }
   2644 
   2645 /* Generate a low private key structure from an object */
   2646 NSSLOWKEYPrivateKey *
   2647 sftk_GetPrivKey(SFTKObject *object, CK_KEY_TYPE key_type, CK_RV *crvp)
   2648 {
   2649    NSSLOWKEYPrivateKey *priv = NULL;
   2650 
   2651    if (object->objclass != CKO_PRIVATE_KEY) {
   2652        *crvp = CKR_KEY_TYPE_INCONSISTENT;
   2653        return NULL;
   2654    }
   2655    if (object->objectInfo) {
   2656        *crvp = CKR_OK;
   2657        return (NSSLOWKEYPrivateKey *)object->objectInfo;
   2658    }
   2659 
   2660    priv = sftk_mkPrivKey(object, key_type, crvp);
   2661    object->objectInfo = priv;
   2662    object->infoFree = SFTKFree_nsslowkey_DestroyPrivateKey;
   2663    return priv;
   2664 }
   2665 
   2666 /* populate a public key object from a lowpublic keys structure */
   2667 CK_RV
   2668 sftk_PutPubKey(SFTKObject *publicKey, SFTKObject *privateKey, CK_KEY_TYPE keyType, NSSLOWKEYPublicKey *pubKey)
   2669 {
   2670    CK_OBJECT_CLASS classType = CKO_PUBLIC_KEY;
   2671    CK_BBOOL cktrue = CK_TRUE;
   2672    CK_RV crv = CKR_OK;
   2673    sftk_DeleteAttributeType(publicKey, CKA_CLASS);
   2674    sftk_DeleteAttributeType(publicKey, CKA_KEY_TYPE);
   2675    sftk_DeleteAttributeType(publicKey, CKA_VALUE);
   2676 
   2677    switch (keyType) {
   2678        case CKK_RSA:
   2679            sftk_DeleteAttributeType(publicKey, CKA_MODULUS);
   2680            sftk_DeleteAttributeType(publicKey, CKA_PUBLIC_EXPONENT);
   2681            /* format the keys */
   2682            /* fill in the RSA dependent paramenters in the public key */
   2683            crv = sftk_AddAttributeType(publicKey, CKA_MODULUS,
   2684                                        sftk_item_expand(&pubKey->u.rsa.modulus));
   2685            if (crv != CKR_OK) {
   2686                break;
   2687            }
   2688            crv = sftk_AddAttributeType(publicKey, CKA_PUBLIC_EXPONENT,
   2689                                        sftk_item_expand(&pubKey->u.rsa.publicExponent));
   2690            break;
   2691        case CKK_DSA:
   2692            sftk_DeleteAttributeType(publicKey, CKA_PRIME);
   2693            sftk_DeleteAttributeType(publicKey, CKA_SUBPRIME);
   2694            sftk_DeleteAttributeType(publicKey, CKA_BASE);
   2695            crv = sftk_AddAttributeType(publicKey, CKA_PRIME,
   2696                                        sftk_item_expand(&pubKey->u.dsa.params.prime));
   2697            if (crv != CKR_OK) {
   2698                break;
   2699            }
   2700            crv = sftk_AddAttributeType(publicKey, CKA_SUBPRIME,
   2701                                        sftk_item_expand(&pubKey->u.dsa.params.subPrime));
   2702            if (crv != CKR_OK) {
   2703                break;
   2704            }
   2705            crv = sftk_AddAttributeType(publicKey, CKA_BASE,
   2706                                        sftk_item_expand(&pubKey->u.dsa.params.base));
   2707            if (crv != CKR_OK) {
   2708                break;
   2709            }
   2710            crv = sftk_AddAttributeType(publicKey, CKA_VALUE,
   2711                                        sftk_item_expand(&pubKey->u.dsa.publicValue));
   2712            break;
   2713        case CKK_ML_DSA:
   2714            sftk_DeleteAttributeType(publicKey, CKA_VALUE);
   2715            sftk_DeleteAttributeType(publicKey, CKA_PARAMETER_SET);
   2716            crv = sftk_AddAttributeType(publicKey, CKA_VALUE,
   2717                                        pubKey->u.mldsa.keyVal,
   2718                                        pubKey->u.mldsa.keyValLen);
   2719            if (crv != CKR_OK) {
   2720                break;
   2721            }
   2722            crv = sftk_AddAttributeType(publicKey, CKA_PARAMETER_SET,
   2723                                        (unsigned char *)&pubKey->u.mldsa.paramSet,
   2724                                        sizeof(pubKey->u.mldsa.paramSet));
   2725            break;
   2726        case CKK_DH:
   2727            sftk_DeleteAttributeType(publicKey, CKA_PRIME);
   2728            sftk_DeleteAttributeType(publicKey, CKA_BASE);
   2729            crv = sftk_AddAttributeType(publicKey, CKA_PRIME,
   2730                                        sftk_item_expand(&pubKey->u.dh.prime));
   2731            if (crv != CKR_OK) {
   2732                break;
   2733            }
   2734            crv = sftk_AddAttributeType(publicKey, CKA_BASE,
   2735                                        sftk_item_expand(&pubKey->u.dh.base));
   2736            if (crv != CKR_OK) {
   2737                break;
   2738            }
   2739            crv = sftk_AddAttributeType(publicKey, CKA_VALUE,
   2740                                        sftk_item_expand(&pubKey->u.dh.publicValue));
   2741            break;
   2742        case CKK_EC:
   2743        case CKK_EC_MONTGOMERY:
   2744        case CKK_EC_EDWARDS:
   2745            sftk_DeleteAttributeType(publicKey, CKA_EC_PARAMS);
   2746            sftk_DeleteAttributeType(publicKey, CKA_EC_POINT);
   2747            crv = sftk_AddAttributeType(publicKey, CKA_EC_PARAMS,
   2748                                        sftk_item_expand(&pubKey->u.ec.ecParams.DEREncoding));
   2749            if (crv != CKR_OK) {
   2750                break;
   2751            }
   2752            crv = sftk_AddAttributeType(publicKey, CKA_EC_POINT,
   2753                                        sftk_item_expand(&pubKey->u.ec.publicValue));
   2754            break;
   2755        default:
   2756            return CKR_KEY_TYPE_INCONSISTENT;
   2757    }
   2758    if (crv != CKR_OK) {
   2759        return crv;
   2760    }
   2761    crv = sftk_AddAttributeType(publicKey, CKA_CLASS, &classType,
   2762                                sizeof(CK_OBJECT_CLASS));
   2763    if (crv != CKR_OK) {
   2764        return crv;
   2765    }
   2766    crv = sftk_AddAttributeType(publicKey, CKA_KEY_TYPE, &keyType,
   2767                                sizeof(CK_KEY_TYPE));
   2768    if (crv != CKR_OK) {
   2769        return crv;
   2770    }
   2771    /* now handle the operator attributes */
   2772    if (sftk_isTrue(privateKey, CKA_DECRYPT)) {
   2773        crv = sftk_forceAttribute(publicKey, CKA_ENCRYPT, &cktrue, sizeof(CK_BBOOL));
   2774        if (crv != CKR_OK) {
   2775            return crv;
   2776        }
   2777    }
   2778    if (sftk_isTrue(privateKey, CKA_SIGN)) {
   2779        crv = sftk_forceAttribute(publicKey, CKA_VERIFY, &cktrue, sizeof(CK_BBOOL));
   2780        if (crv != CKR_OK) {
   2781            return crv;
   2782        }
   2783    }
   2784    if (sftk_isTrue(privateKey, CKA_SIGN_RECOVER)) {
   2785        crv = sftk_forceAttribute(publicKey, CKA_VERIFY_RECOVER, &cktrue, sizeof(CK_BBOOL));
   2786        if (crv != CKR_OK) {
   2787            return crv;
   2788        }
   2789    }
   2790    if (sftk_isTrue(privateKey, CKA_DECAPSULATE)) {
   2791        crv = sftk_forceAttribute(publicKey, CKA_ENCAPSULATE, &cktrue, sizeof(CK_BBOOL));
   2792        if (crv != CKR_OK) {
   2793            return crv;
   2794        }
   2795    }
   2796    if (sftk_isTrue(privateKey, CKA_DERIVE)) {
   2797        crv = sftk_forceAttribute(publicKey, CKA_DERIVE, &cktrue, sizeof(CK_BBOOL));
   2798        if (crv != CKR_OK) {
   2799            return crv;
   2800        }
   2801    }
   2802    return crv;
   2803 }
   2804 
   2805 /*
   2806 **************************** Symetric Key utils ************************
   2807 */
   2808 /*
   2809 * set the DES key with parity bits correctly
   2810 */
   2811 void
   2812 sftk_FormatDESKey(unsigned char *key, int length)
   2813 {
   2814    int i;
   2815 
   2816    /* format the des key */
   2817    for (i = 0; i < length; i++) {
   2818        key[i] = parityTable[key[i] >> 1];
   2819    }
   2820 }
   2821 
   2822 /*
   2823 * check a des key (des2 or des3 subkey) for weak keys.
   2824 */
   2825 PRBool
   2826 sftk_CheckDESKey(unsigned char *key)
   2827 {
   2828    int i;
   2829 
   2830    /* format the des key with parity  */
   2831    sftk_FormatDESKey(key, 8);
   2832 
   2833    for (i = 0; i < sftk_desWeakTableSize; i++) {
   2834        if (PORT_Memcmp(key, sftk_desWeakTable[i], 8) == 0) {
   2835            return PR_TRUE;
   2836        }
   2837    }
   2838    return PR_FALSE;
   2839 }
   2840 
   2841 /*
   2842 * check if a des or triple des key is weak.
   2843 */
   2844 PRBool
   2845 sftk_IsWeakKey(unsigned char *key, CK_KEY_TYPE key_type)
   2846 {
   2847 
   2848    switch (key_type) {
   2849        case CKK_DES:
   2850            return sftk_CheckDESKey(key);
   2851        case CKM_DES2_KEY_GEN:
   2852            if (sftk_CheckDESKey(key))
   2853                return PR_TRUE;
   2854            return sftk_CheckDESKey(&key[8]);
   2855        case CKM_DES3_KEY_GEN:
   2856            if (sftk_CheckDESKey(key))
   2857                return PR_TRUE;
   2858            if (sftk_CheckDESKey(&key[8]))
   2859                return PR_TRUE;
   2860            return sftk_CheckDESKey(&key[16]);
   2861        default:
   2862            break;
   2863    }
   2864    return PR_FALSE;
   2865 }
   2866 
   2867 /**********************************************************************
   2868 *
   2869 *     Start of PKCS 11 functions
   2870 *
   2871 **********************************************************************/
   2872 
   2873 /* return the function list */
   2874 CK_RV
   2875 NSC_GetFunctionList(CK_FUNCTION_LIST_PTR *pFunctionList)
   2876 {
   2877    *pFunctionList = (CK_FUNCTION_LIST_PTR)&sftk_funcList_v2;
   2878    return CKR_OK;
   2879 }
   2880 
   2881 /* return the function list */
   2882 CK_RV
   2883 C_GetFunctionList(CK_FUNCTION_LIST_PTR *pFunctionList)
   2884 {
   2885 #ifdef NSS_FIPS_DISABLED
   2886    return NSC_GetFunctionList(pFunctionList);
   2887 #else
   2888    if (NSS_GetSystemFIPSEnabled()) {
   2889        return FC_GetFunctionList(pFunctionList);
   2890    } else {
   2891        return NSC_GetFunctionList(pFunctionList);
   2892    }
   2893 #endif
   2894 }
   2895 
   2896 CK_RV
   2897 NSC_GetInterfaceList(CK_INTERFACE_PTR interfaces, CK_ULONG_PTR pulCount)
   2898 {
   2899    CK_ULONG count = *pulCount;
   2900    *pulCount = NSS_INTERFACE_COUNT;
   2901    if (interfaces == NULL) {
   2902        return CKR_OK;
   2903    }
   2904    if (count < NSS_INTERFACE_COUNT) {
   2905        return CKR_BUFFER_TOO_SMALL;
   2906    }
   2907    PORT_Memcpy(interfaces, nss_interfaces, sizeof(nss_interfaces));
   2908    return CKR_OK;
   2909 }
   2910 
   2911 CK_RV
   2912 C_GetInterfaceList(CK_INTERFACE_PTR interfaces, CK_ULONG_PTR pulCount)
   2913 {
   2914 #ifdef NSS_FIPS_DISABLED
   2915    return NSC_GetInterfaceList(interfaces, pulCount);
   2916 #else
   2917    if (NSS_GetSystemFIPSEnabled()) {
   2918        return FC_GetInterfaceList(interfaces, pulCount);
   2919    } else {
   2920        return NSC_GetInterfaceList(interfaces, pulCount);
   2921    }
   2922 #endif
   2923 }
   2924 
   2925 /*
   2926 * Get the requested interface, use the nss_interfaces array so we can
   2927 * easily add new interfaces as they occur.
   2928 */
   2929 CK_RV
   2930 NSC_GetInterface(CK_UTF8CHAR_PTR pInterfaceName, CK_VERSION_PTR pVersion,
   2931                 CK_INTERFACE_PTR_PTR ppInterface, CK_FLAGS flags)
   2932 {
   2933    int i;
   2934    for (i = 0; i < NSS_INTERFACE_COUNT; i++) {
   2935        CK_INTERFACE_PTR interface = &nss_interfaces[i];
   2936        if (pInterfaceName && PORT_Strcmp((char *)pInterfaceName, (char *)interface->pInterfaceName) != 0) {
   2937            continue;
   2938        }
   2939        if (pVersion && PORT_Memcmp(pVersion, (CK_VERSION *)interface->pFunctionList, sizeof(CK_VERSION)) != 0) {
   2940            continue;
   2941        }
   2942        if (flags & ((interface->flags & flags) != flags)) {
   2943            continue;
   2944        }
   2945        *ppInterface = interface;
   2946        return CKR_OK;
   2947    }
   2948    return CKR_ARGUMENTS_BAD;
   2949 }
   2950 
   2951 CK_RV
   2952 C_GetInterface(CK_UTF8CHAR_PTR pInterfaceName, CK_VERSION_PTR pVersion,
   2953               CK_INTERFACE_PTR_PTR ppInterface, CK_FLAGS flags)
   2954 {
   2955 #ifdef NSS_FIPS_DISABLED
   2956    return NSC_GetInterface(pInterfaceName, pVersion, ppInterface, flags);
   2957 #else
   2958    if (NSS_GetSystemFIPSEnabled()) {
   2959        return FC_GetInterface(pInterfaceName, pVersion, ppInterface, flags);
   2960    } else {
   2961        return NSC_GetInterface(pInterfaceName, pVersion, ppInterface, flags);
   2962    }
   2963 #endif
   2964 }
   2965 
   2966 static PLHashNumber
   2967 sftk_HashNumber(const void *key)
   2968 {
   2969    return (PLHashNumber)((char *)key - (char *)NULL);
   2970 }
   2971 
   2972 /*
   2973 * eventually I'd like to expunge all occurances of XXX_SLOT_ID and
   2974 * just go with the info in the slot. This is one place, however,
   2975 * where it might be a little difficult.
   2976 */
   2977 const char *
   2978 sftk_getDefTokName(CK_SLOT_ID slotID)
   2979 {
   2980    static char buf[33];
   2981 
   2982    switch (slotID) {
   2983        case NETSCAPE_SLOT_ID:
   2984            return "NSS Generic Crypto Services     ";
   2985        case PRIVATE_KEY_SLOT_ID:
   2986            return "NSS Certificate DB              ";
   2987        case FIPS_SLOT_ID:
   2988            return "NSS FIPS 140-2 Certificate DB   ";
   2989        default:
   2990            break;
   2991    }
   2992    snprintf(buf, sizeof(buf), "NSS Application Token %08x  ", (unsigned int)slotID);
   2993    return buf;
   2994 }
   2995 
   2996 const char *
   2997 sftk_getDefSlotName(CK_SLOT_ID slotID)
   2998 {
   2999    static char buf[65];
   3000 
   3001    switch (slotID) {
   3002        case NETSCAPE_SLOT_ID:
   3003            return "NSS Internal Cryptographic Services                             ";
   3004        case PRIVATE_KEY_SLOT_ID:
   3005            return "NSS User Private Key and Certificate Services                   ";
   3006        case FIPS_SLOT_ID:
   3007            return "NSS FIPS 140-2 User Private Key Services                        ";
   3008        default:
   3009            break;
   3010    }
   3011    snprintf(buf, sizeof(buf),
   3012             "NSS Application Slot %08x                                   ",
   3013             (unsigned int)slotID);
   3014    return buf;
   3015 }
   3016 
   3017 static CK_ULONG nscSlotCount[2] = { 0, 0 };
   3018 static CK_SLOT_ID_PTR nscSlotList[2] = { NULL, NULL };
   3019 static CK_ULONG nscSlotListSize[2] = { 0, 0 };
   3020 static PLHashTable *nscSlotHashTable[2] = { NULL, NULL };
   3021 
   3022 static unsigned int
   3023 sftk_GetModuleIndex(CK_SLOT_ID slotID)
   3024 {
   3025    if (sftk_isFIPS(slotID)) {
   3026        return NSC_FIPS_MODULE;
   3027    }
   3028    return NSC_NON_FIPS_MODULE;
   3029 }
   3030 
   3031 /* look up a slot structure from the ID (used to be a macro when we only
   3032 * had two slots) */
   3033 /* if all is true, return the slot even if it has been 'unloaded' */
   3034 /* if all is false, only return the slots which are present */
   3035 SFTKSlot *
   3036 sftk_SlotFromID(CK_SLOT_ID slotID, PRBool all)
   3037 {
   3038    SFTKSlot *slot;
   3039    unsigned int index = sftk_GetModuleIndex(slotID);
   3040 
   3041    if (nscSlotHashTable[index] == NULL)
   3042        return NULL;
   3043    slot = (SFTKSlot *)PL_HashTableLookupConst(nscSlotHashTable[index],
   3044                                               (void *)(uintptr_t)slotID);
   3045    /* cleared slots shouldn't 'show up' */
   3046    if (slot && !all && !slot->present)
   3047        slot = NULL;
   3048    return slot;
   3049 }
   3050 
   3051 CK_SLOT_ID
   3052 sftk_SlotIDFromSessionHandle(CK_SESSION_HANDLE handle)
   3053 {
   3054    CK_ULONG slotIDIndex = (handle >> 24) & 0x7f;
   3055    CK_ULONG moduleIndex = (handle >> 31) & 1;
   3056 
   3057    if (slotIDIndex >= nscSlotCount[moduleIndex]) {
   3058        return (CK_SLOT_ID)-1;
   3059    }
   3060    return nscSlotList[moduleIndex][slotIDIndex];
   3061 }
   3062 
   3063 SFTKSlot *
   3064 sftk_SlotFromSessionHandle(CK_SESSION_HANDLE handle)
   3065 {
   3066    return sftk_SlotFromID(sftk_SlotIDFromSessionHandle(handle), PR_FALSE);
   3067 }
   3068 
   3069 static CK_RV
   3070 sftk_RegisterSlot(SFTKSlot *slot, unsigned int moduleIndex)
   3071 {
   3072    PLHashEntry *entry;
   3073    unsigned int index;
   3074 
   3075    index = sftk_GetModuleIndex(slot->slotID);
   3076 
   3077    /* make sure the slotID for this module is valid */
   3078    if (moduleIndex != index) {
   3079        return CKR_SLOT_ID_INVALID;
   3080    }
   3081 
   3082    if (nscSlotList[index] == NULL) {
   3083        nscSlotListSize[index] = NSC_SLOT_LIST_BLOCK_SIZE;
   3084        nscSlotList[index] = (CK_SLOT_ID *)
   3085            PORT_ZAlloc(nscSlotListSize[index] * sizeof(CK_SLOT_ID));
   3086        if (nscSlotList[index] == NULL) {
   3087            return CKR_HOST_MEMORY;
   3088        }
   3089    }
   3090    if (nscSlotCount[index] >= nscSlotListSize[index]) {
   3091        CK_SLOT_ID *oldNscSlotList = nscSlotList[index];
   3092        CK_ULONG oldNscSlotListSize = nscSlotListSize[index];
   3093        nscSlotListSize[index] += NSC_SLOT_LIST_BLOCK_SIZE;
   3094        nscSlotList[index] = (CK_SLOT_ID *)PORT_Realloc(oldNscSlotList,
   3095                                                        nscSlotListSize[index] * sizeof(CK_SLOT_ID));
   3096        if (nscSlotList[index] == NULL) {
   3097            /* evidently coverity doesn't know realloc does not
   3098             * free var if it fails ! */
   3099            /* coverity [use_after_free : FALSE] */
   3100            nscSlotList[index] = oldNscSlotList;
   3101            nscSlotListSize[index] = oldNscSlotListSize;
   3102            return CKR_HOST_MEMORY;
   3103        }
   3104    }
   3105 
   3106    if (nscSlotHashTable[index] == NULL) {
   3107        nscSlotHashTable[index] = PL_NewHashTable(64, sftk_HashNumber,
   3108                                                  PL_CompareValues, PL_CompareValues, NULL, 0);
   3109        if (nscSlotHashTable[index] == NULL) {
   3110            return CKR_HOST_MEMORY;
   3111        }
   3112    }
   3113 
   3114    entry = PL_HashTableAdd(nscSlotHashTable[index], (void *)(uintptr_t)slot->slotID, slot);
   3115    if (entry == NULL) {
   3116        return CKR_HOST_MEMORY;
   3117    }
   3118    slot->index = (nscSlotCount[index] & 0x7f) | ((index << 7) & 0x80);
   3119    nscSlotList[index][nscSlotCount[index]++] = slot->slotID;
   3120 
   3121    return CKR_OK;
   3122 }
   3123 
   3124 /*
   3125 * ths function has all the common initialization that happens whenever we
   3126 * create a new slot or repurpose an old slot (only valid for slotID's 4
   3127 * and greater).
   3128 *
   3129 * things that are not reinitialized are:
   3130 *   slotID (can't change)
   3131 *   slotDescription (can't change once defined)
   3132 *   the locks and hash tables (difficult to change in running code, and
   3133 *     unnecessary. hash tables and list are cleared on shutdown, but they
   3134 *     are cleared in a 'friendly' way).
   3135 *   session and object ID counters -- so any old sessions and objects in the
   3136 *     application will get properly notified that the world has changed.
   3137 *
   3138 * things that are reinitialized:
   3139 *   database (otherwise what would the point be;).
   3140 *   state variables related to databases.
   3141 *   session count stat info.
   3142 *   tokenDescription.
   3143 *
   3144 * NOTE: slotID's 4 and greater show up as removable devices.
   3145 *
   3146 */
   3147 CK_RV
   3148 SFTK_SlotReInit(SFTKSlot *slot, char *configdir, char *updatedir,
   3149                char *updateID, sftk_token_parameters *params,
   3150                unsigned int moduleIndex)
   3151 {
   3152    PRBool needLogin = !params->noKeyDB;
   3153    CK_RV crv;
   3154 
   3155    slot->hasTokens = PR_FALSE;
   3156    slot->sessionIDConflict = 0;
   3157    slot->sessionCount = 0;
   3158    slot->rwSessionCount = 0;
   3159    slot->needLogin = PR_FALSE;
   3160    slot->isLoggedIn = PR_FALSE;
   3161    slot->ssoLoggedIn = PR_FALSE;
   3162    slot->DB_loaded = PR_FALSE;
   3163    slot->certDB = NULL;
   3164    slot->keyDB = NULL;
   3165    slot->minimumPinLen = 0;
   3166    slot->readOnly = params->readOnly;
   3167    sftk_setStringName(params->tokdes ? params->tokdes : sftk_getDefTokName(slot->slotID), slot->tokDescription,
   3168                       sizeof(slot->tokDescription), PR_TRUE);
   3169    sftk_setStringName(params->updtokdes ? params->updtokdes : " ",
   3170                       slot->updateTokDescription,
   3171                       sizeof(slot->updateTokDescription), PR_TRUE);
   3172 
   3173    if ((!params->noCertDB) || (!params->noKeyDB)) {
   3174        SFTKDBHandle *certHandle = NULL;
   3175        SFTKDBHandle *keyHandle = NULL;
   3176        crv = sftk_DBInit(params->configdir ? params->configdir : configdir,
   3177                          params->certPrefix, params->keyPrefix,
   3178                          params->updatedir ? params->updatedir : updatedir,
   3179                          params->updCertPrefix, params->updKeyPrefix,
   3180                          params->updateID ? params->updateID : updateID,
   3181                          params->readOnly, params->noCertDB, params->noKeyDB,
   3182                          params->forceOpen,
   3183                          moduleIndex == NSC_FIPS_MODULE,
   3184                          &certHandle, &keyHandle);
   3185        if (crv != CKR_OK) {
   3186            goto loser;
   3187        }
   3188 
   3189        slot->certDB = certHandle;
   3190        slot->keyDB = keyHandle;
   3191    }
   3192    if (needLogin) {
   3193        /* if the data base is initialized with a null password,remember that */
   3194        slot->needLogin =
   3195            (PRBool)!sftk_hasNullPassword(slot, slot->keyDB);
   3196        if ((params->minPW >= 0) && (params->minPW <= SFTK_MAX_PIN)) {
   3197            slot->minimumPinLen = params->minPW;
   3198        }
   3199        if ((slot->minimumPinLen == 0) && (params->pwRequired)) {
   3200            slot->minimumPinLen = 1;
   3201        }
   3202        /* Make sure the pin len is set to the Minimum allowed value for fips
   3203         * when in FIPS mode. NOTE: we don't set it if the database has not
   3204         * been initialized yet so that we can init into level1 mode if needed
   3205         */
   3206        if ((sftkdb_HasPasswordSet(slot->keyDB) == SECSuccess) &&
   3207            (moduleIndex == NSC_FIPS_MODULE) &&
   3208            (slot->minimumPinLen < FIPS_MIN_PIN)) {
   3209            slot->minimumPinLen = FIPS_MIN_PIN;
   3210        }
   3211    }
   3212 
   3213    slot->present = PR_TRUE;
   3214    return CKR_OK;
   3215 
   3216 loser:
   3217    SFTK_ShutdownSlot(slot);
   3218    return crv;
   3219 }
   3220 
   3221 /*
   3222 * initialize one of the slot structures. figure out which by the ID
   3223 */
   3224 CK_RV
   3225 SFTK_SlotInit(char *configdir, char *updatedir, char *updateID,
   3226              sftk_token_parameters *params, unsigned int moduleIndex)
   3227 {
   3228    unsigned int i;
   3229    CK_SLOT_ID slotID = params->slotID;
   3230    SFTKSlot *slot;
   3231    CK_RV crv = CKR_HOST_MEMORY;
   3232 
   3233    /*
   3234     * first we initialize everything that is 'permanent' with this slot.
   3235     * that is everything we aren't going to shutdown if we close this slot
   3236     * and open it up again with different databases */
   3237 
   3238    slot = PORT_ZNew(SFTKSlot);
   3239 
   3240    if (slot == NULL) {
   3241        return CKR_HOST_MEMORY;
   3242    }
   3243 
   3244    slot->optimizeSpace = params->optimizeSpace;
   3245    if (slot->optimizeSpace) {
   3246        slot->sessObjHashSize = SPACE_SESSION_OBJECT_HASH_SIZE;
   3247        slot->sessHashSize = SPACE_SESSION_HASH_SIZE;
   3248        slot->numSessionLocks = 1;
   3249    } else {
   3250        slot->sessObjHashSize = TIME_SESSION_OBJECT_HASH_SIZE;
   3251        slot->sessHashSize = TIME_SESSION_HASH_SIZE;
   3252        slot->numSessionLocks = slot->sessHashSize / BUCKETS_PER_SESSION_LOCK;
   3253    }
   3254    slot->sessionLockMask = slot->numSessionLocks - 1;
   3255 
   3256    slot->slotLock = PZ_NewLock(nssILockSession);
   3257    if (slot->slotLock == NULL)
   3258        goto mem_loser;
   3259    slot->sessionLock = PORT_ZNewArray(PZLock *, slot->numSessionLocks);
   3260    if (slot->sessionLock == NULL)
   3261        goto mem_loser;
   3262    for (i = 0; i < slot->numSessionLocks; i++) {
   3263        slot->sessionLock[i] = PZ_NewLock(nssILockSession);
   3264        if (slot->sessionLock[i] == NULL)
   3265            goto mem_loser;
   3266    }
   3267    slot->objectLock = PZ_NewLock(nssILockObject);
   3268    if (slot->objectLock == NULL)
   3269        goto mem_loser;
   3270    slot->pwCheckLock = PR_NewLock();
   3271    if (slot->pwCheckLock == NULL)
   3272        goto mem_loser;
   3273    slot->head = PORT_ZNewArray(SFTKSession *, slot->sessHashSize);
   3274    if (slot->head == NULL)
   3275        goto mem_loser;
   3276    slot->sessObjHashTable = PORT_ZNewArray(SFTKObject *, slot->sessObjHashSize);
   3277    if (slot->sessObjHashTable == NULL)
   3278        goto mem_loser;
   3279    slot->tokObjHashTable = PL_NewHashTable(64, sftk_HashNumber, PL_CompareValues,
   3280                                            SECITEM_HashCompare, NULL, 0);
   3281    if (slot->tokObjHashTable == NULL)
   3282        goto mem_loser;
   3283 
   3284    slot->sessionIDCount = 0;
   3285    slot->sessionObjectHandleCount = NSC_MIN_SESSION_OBJECT_HANDLE;
   3286    slot->slotID = slotID;
   3287    sftk_setStringName(params->slotdes ? params->slotdes : sftk_getDefSlotName(slotID), slot->slotDescription,
   3288                       sizeof(slot->slotDescription), PR_TRUE);
   3289    crv = sftk_InitSession(&slot->moduleObjects, slot, slotID, NULL, NULL,
   3290                           CKF_SERIAL_SESSION);
   3291    if (crv != CKR_OK) {
   3292        goto loser;
   3293    }
   3294 
   3295    /* call the reinit code to set everything that changes between token
   3296     * init calls */
   3297    crv = SFTK_SlotReInit(slot, configdir, updatedir, updateID,
   3298                          params, moduleIndex);
   3299    if (crv != CKR_OK) {
   3300        goto loser;
   3301    }
   3302    if (sftk_isFIPS(slotID)) {
   3303        crv = sftk_CreateValidationObjects(slot);
   3304        if (crv != CKR_OK) {
   3305            goto loser;
   3306        }
   3307    }
   3308    crv = sftk_RegisterSlot(slot, moduleIndex);
   3309    if (crv != CKR_OK) {
   3310        goto loser;
   3311    }
   3312    return CKR_OK;
   3313 
   3314 mem_loser:
   3315    crv = CKR_HOST_MEMORY;
   3316 loser:
   3317    SFTK_DestroySlotData(slot);
   3318    return crv;
   3319 }
   3320 
   3321 CK_RV
   3322 sftk_CloseAllSessions(SFTKSlot *slot, PRBool logout)
   3323 {
   3324    SFTKSession *session;
   3325    unsigned int i;
   3326    SFTKDBHandle *handle;
   3327 
   3328    /* first log out the card */
   3329    /* special case - if we are in a middle of upgrade, we want to close the
   3330     * sessions to fake a token removal to tell the upper level code we have
   3331     * switched from one database to another, but we don't want to
   3332     * explicity logout in case we can continue the upgrade with the
   3333     * existing password if possible.
   3334     */
   3335    if (logout) {
   3336        handle = sftk_getKeyDB(slot);
   3337        SKIP_AFTER_FORK(PZ_Lock(slot->slotLock));
   3338        slot->isLoggedIn = PR_FALSE;
   3339        if (slot->needLogin && handle) {
   3340            sftkdb_ClearPassword(handle);
   3341        }
   3342        SKIP_AFTER_FORK(PZ_Unlock(slot->slotLock));
   3343        if (handle) {
   3344            sftk_freeDB(handle);
   3345        }
   3346    }
   3347 
   3348    /* now close all the current sessions */
   3349    /* NOTE: If you try to open new sessions before NSC_CloseAllSessions
   3350     * completes, some of those new sessions may or may not be closed by
   3351     * NSC_CloseAllSessions... but any session running when this code starts
   3352     * will guarrenteed be close, and no session will be partially closed */
   3353    for (i = 0; i < slot->sessHashSize; i++) {
   3354        PZLock *lock = SFTK_SESSION_LOCK(slot, i);
   3355        do {
   3356            SKIP_AFTER_FORK(PZ_Lock(lock));
   3357            session = slot->head[i];
   3358            /* hand deque */
   3359            /* this duplicates function of NSC_close session functions, but
   3360             * because we know that we are freeing all the sessions, we can
   3361             * do more efficient processing */
   3362            if (session) {
   3363                slot->head[i] = session->next;
   3364                if (session->next)
   3365                    session->next->prev = NULL;
   3366                session->next = session->prev = NULL;
   3367                SKIP_AFTER_FORK(PZ_Unlock(lock));
   3368                SKIP_AFTER_FORK(PZ_Lock(slot->slotLock));
   3369                --slot->sessionCount;
   3370                SKIP_AFTER_FORK(PZ_Unlock(slot->slotLock));
   3371                if (session->info.flags & CKF_RW_SESSION) {
   3372                    (void)PR_ATOMIC_DECREMENT(&slot->rwSessionCount);
   3373                }
   3374            } else {
   3375                SKIP_AFTER_FORK(PZ_Unlock(lock));
   3376            }
   3377            if (session) {
   3378                sftk_DestroySession(session);
   3379            }
   3380        } while (session != NULL);
   3381    }
   3382    return CKR_OK;
   3383 }
   3384 
   3385 /*
   3386 * shut down the databases.
   3387 * we get the slot lock (which also protects slot->certDB and slot->keyDB)
   3388 * and clear the values so the new users will not find the databases.
   3389 * once things are clear, we can release our references to the databases.
   3390 * The databases will close when the last reference is released.
   3391 *
   3392 * We use reference counts so that we don't crash if someone shuts down
   3393 * a token that another thread is actively using.
   3394 */
   3395 static void
   3396 sftk_DBShutdown(SFTKSlot *slot)
   3397 {
   3398    SFTKDBHandle *certHandle;
   3399    SFTKDBHandle *keyHandle;
   3400    SKIP_AFTER_FORK(PZ_Lock(slot->slotLock));
   3401    certHandle = slot->certDB;
   3402    slot->certDB = NULL;
   3403    keyHandle = slot->keyDB;
   3404    slot->keyDB = NULL;
   3405    SKIP_AFTER_FORK(PZ_Unlock(slot->slotLock));
   3406    if (certHandle) {
   3407        sftk_freeDB(certHandle);
   3408    }
   3409    if (keyHandle) {
   3410        sftk_freeDB(keyHandle);
   3411    }
   3412 }
   3413 
   3414 CK_RV
   3415 SFTK_ShutdownSlot(SFTKSlot *slot)
   3416 {
   3417    /* make sure no new PK11 calls work except C_GetSlotInfo */
   3418    slot->present = PR_FALSE;
   3419 
   3420    /* close all outstanding sessions
   3421     * the sessHashSize variable guarentees we have all the session
   3422     * mechanism set up */
   3423    if (slot->head) {
   3424        sftk_CloseAllSessions(slot, PR_TRUE);
   3425    }
   3426 
   3427    /* clear all objects.. session objects are cleared as a result of
   3428     * closing all the sessions. We just need to clear the token object
   3429     * cache. slot->tokObjHashTable guarentees we have the token
   3430     * infrastructure set up. */
   3431    if (slot->tokObjHashTable) {
   3432        SFTK_ClearTokenKeyHashTable(slot);
   3433    }
   3434 
   3435    /* clear the slot description for the next guy */
   3436    PORT_Memset(slot->tokDescription, 0, sizeof(slot->tokDescription));
   3437 
   3438    /* now shut down the databases. */
   3439    sftk_DBShutdown(slot);
   3440    return CKR_OK;
   3441 }
   3442 
   3443 /*
   3444 * initialize one of the slot structures. figure out which by the ID
   3445 */
   3446 CK_RV
   3447 SFTK_DestroySlotData(SFTKSlot *slot)
   3448 {
   3449    unsigned int i;
   3450 
   3451    SFTK_ShutdownSlot(slot);
   3452 
   3453    sftk_ClearSession(&slot->moduleObjects);
   3454 
   3455    if (slot->tokObjHashTable) {
   3456        PL_HashTableDestroy(slot->tokObjHashTable);
   3457        slot->tokObjHashTable = NULL;
   3458    }
   3459 
   3460    if (slot->sessObjHashTable) {
   3461        PORT_Free(slot->sessObjHashTable);
   3462        slot->sessObjHashTable = NULL;
   3463    }
   3464    slot->sessObjHashSize = 0;
   3465 
   3466    if (slot->head) {
   3467        PORT_Free(slot->head);
   3468        slot->head = NULL;
   3469    }
   3470    slot->sessHashSize = 0;
   3471 
   3472    /* OK everything has been disassembled, now we can finally get rid
   3473     * of the locks */
   3474    SKIP_AFTER_FORK(PZ_DestroyLock(slot->slotLock));
   3475    slot->slotLock = NULL;
   3476    if (slot->sessionLock) {
   3477        for (i = 0; i < slot->numSessionLocks; i++) {
   3478            if (slot->sessionLock[i]) {
   3479                SKIP_AFTER_FORK(PZ_DestroyLock(slot->sessionLock[i]));
   3480                slot->sessionLock[i] = NULL;
   3481            }
   3482        }
   3483        PORT_Free(slot->sessionLock);
   3484        slot->sessionLock = NULL;
   3485    }
   3486    if (slot->objectLock) {
   3487        SKIP_AFTER_FORK(PZ_DestroyLock(slot->objectLock));
   3488        slot->objectLock = NULL;
   3489    }
   3490    if (slot->pwCheckLock) {
   3491        SKIP_AFTER_FORK(PR_DestroyLock(slot->pwCheckLock));
   3492        slot->pwCheckLock = NULL;
   3493    }
   3494    PORT_Free(slot);
   3495    return CKR_OK;
   3496 }
   3497 
   3498 /*
   3499 * handle the SECMOD.db
   3500 */
   3501 char **
   3502 NSC_ModuleDBFunc(unsigned long function, char *parameters, void *args)
   3503 {
   3504 #ifdef NSS_DISABLE_DBM
   3505    return NSSUTIL_DoModuleDBFunction(function, parameters, args);
   3506 #else
   3507    char *secmod = NULL;
   3508    char *appName = NULL;
   3509    char *filename = NULL;
   3510    NSSDBType dbType = NSS_DB_TYPE_NONE;
   3511    PRBool rw;
   3512    static char *success = "Success";
   3513    char **rvstr = NULL;
   3514 
   3515    rvstr = NSSUTIL_DoModuleDBFunction(function, parameters, args);
   3516    if (rvstr != NULL) {
   3517        return rvstr;
   3518    }
   3519 
   3520    if (PORT_GetError() != SEC_ERROR_LEGACY_DATABASE) {
   3521        return NULL;
   3522    }
   3523 
   3524    /* The legacy database uses the old dbm, which is only linked with the
   3525     * legacy DB handler, which is only callable from softoken */
   3526 
   3527    secmod = _NSSUTIL_GetSecmodName(parameters, &dbType, &appName,
   3528                                    &filename, &rw);
   3529 
   3530    switch (function) {
   3531        case SECMOD_MODULE_DB_FUNCTION_FIND:
   3532            if (secmod == NULL) {
   3533                PORT_SetError(SEC_ERROR_INVALID_ARGS);
   3534                goto loser;
   3535            }
   3536            if (rw && (dbType != NSS_DB_TYPE_LEGACY) &&
   3537                (dbType != NSS_DB_TYPE_MULTIACCESS)) {
   3538                /* if we get here, we are trying to update the local database */
   3539                /* force data from the legacy DB */
   3540                char *oldSecmod = NULL;
   3541                char *oldAppName = NULL;
   3542                char *oldFilename = NULL;
   3543                PRBool oldrw;
   3544                char **strings = NULL;
   3545                int i;
   3546 
   3547                dbType = NSS_DB_TYPE_LEGACY;
   3548                oldSecmod = _NSSUTIL_GetSecmodName(parameters, &dbType, &oldAppName,
   3549                                                   &oldFilename, &oldrw);
   3550                strings = sftkdbCall_ReadSecmodDB(appName, oldFilename, oldSecmod,
   3551                                                  (char *)parameters, oldrw);
   3552                if (strings) {
   3553                    /* write out the strings */
   3554                    for (i = 0; strings[i]; i++) {
   3555                        NSSUTIL_DoModuleDBFunction(SECMOD_MODULE_DB_FUNCTION_ADD,
   3556                                                   parameters, strings[i]);
   3557                    }
   3558                    sftkdbCall_ReleaseSecmodDBData(oldAppName, oldFilename, oldSecmod,
   3559                                                   (char **)strings, oldrw);
   3560                } else {
   3561                    /* write out a dummy record */
   3562                    NSSUTIL_DoModuleDBFunction(SECMOD_MODULE_DB_FUNCTION_ADD,
   3563                                               parameters, " ");
   3564                }
   3565                if (oldSecmod) {
   3566                    PR_smprintf_free(oldSecmod);
   3567                }
   3568                if (oldAppName) {
   3569                    PORT_Free(oldAppName);
   3570                }
   3571                if (oldFilename) {
   3572                    PORT_Free(oldFilename);
   3573                }
   3574                rvstr = NSSUTIL_DoModuleDBFunction(function, parameters, args);
   3575                break;
   3576            }
   3577            rvstr = sftkdbCall_ReadSecmodDB(appName, filename, secmod,
   3578                                            (char *)parameters, rw);
   3579            break;
   3580        case SECMOD_MODULE_DB_FUNCTION_ADD:
   3581            if (secmod == NULL) {
   3582                PORT_SetError(SEC_ERROR_INVALID_ARGS);
   3583                goto loser;
   3584            }
   3585            rvstr = (sftkdbCall_AddSecmodDB(appName, filename, secmod,
   3586                                            (char *)args, rw) == SECSuccess)
   3587                        ? &success
   3588                        : NULL;
   3589            break;
   3590        case SECMOD_MODULE_DB_FUNCTION_DEL:
   3591            if (secmod == NULL) {
   3592                PORT_SetError(SEC_ERROR_INVALID_ARGS);
   3593                goto loser;
   3594            }
   3595            rvstr = (sftkdbCall_DeleteSecmodDB(appName, filename, secmod,
   3596                                               (char *)args, rw) == SECSuccess)
   3597                        ? &success
   3598                        : NULL;
   3599            break;
   3600        case SECMOD_MODULE_DB_FUNCTION_RELEASE:
   3601            rvstr = (sftkdbCall_ReleaseSecmodDBData(appName, filename, secmod,
   3602                                                    (char **)args, rw) == SECSuccess)
   3603                        ? &success
   3604                        : NULL;
   3605            break;
   3606    }
   3607 
   3608 loser:
   3609    if (secmod)
   3610        PR_smprintf_free(secmod);
   3611    if (appName)
   3612        PORT_Free(appName);
   3613    if (filename)
   3614        PORT_Free(filename);
   3615    return rvstr;
   3616 #endif /* NSS_DISABLE_DBM */
   3617 }
   3618 
   3619 static void
   3620 nscFreeAllSlots(unsigned int moduleIndex)
   3621 {
   3622    /* free all the slots */
   3623    SFTKSlot *slot = NULL;
   3624    CK_SLOT_ID slotID;
   3625    int i;
   3626 
   3627    if (nscSlotList[moduleIndex]) {
   3628        CK_ULONG tmpSlotCount = nscSlotCount[moduleIndex];
   3629        CK_SLOT_ID_PTR tmpSlotList = nscSlotList[moduleIndex];
   3630        PLHashTable *tmpSlotHashTable = nscSlotHashTable[moduleIndex];
   3631 
   3632        /* first close all the session */
   3633        for (i = 0; i < (int)tmpSlotCount; i++) {
   3634            slotID = tmpSlotList[i];
   3635            (void)NSC_CloseAllSessions(slotID);
   3636        }
   3637 
   3638        /* now clear out the statics */
   3639        nscSlotList[moduleIndex] = NULL;
   3640        nscSlotCount[moduleIndex] = 0;
   3641        nscSlotHashTable[moduleIndex] = NULL;
   3642        nscSlotListSize[moduleIndex] = 0;
   3643 
   3644        for (i = 0; i < (int)tmpSlotCount; i++) {
   3645            slotID = tmpSlotList[i];
   3646            slot = (SFTKSlot *)
   3647                PL_HashTableLookup(tmpSlotHashTable, (void *)(uintptr_t)slotID);
   3648            PORT_Assert(slot);
   3649            if (!slot)
   3650                continue;
   3651            SFTK_DestroySlotData(slot);
   3652            PL_HashTableRemove(tmpSlotHashTable, (void *)(uintptr_t)slotID);
   3653        }
   3654        PORT_Free(tmpSlotList);
   3655        PL_HashTableDestroy(tmpSlotHashTable);
   3656    }
   3657 }
   3658 
   3659 static void
   3660 sftk_closePeer(PRBool isFIPS)
   3661 {
   3662    CK_SLOT_ID slotID = isFIPS ? PRIVATE_KEY_SLOT_ID : FIPS_SLOT_ID;
   3663    SFTKSlot *slot;
   3664    unsigned int moduleIndex = isFIPS ? NSC_NON_FIPS_MODULE : NSC_FIPS_MODULE;
   3665    PLHashTable *tmpSlotHashTable = nscSlotHashTable[moduleIndex];
   3666 
   3667    slot = (SFTKSlot *)PL_HashTableLookup(tmpSlotHashTable, (void *)(uintptr_t)slotID);
   3668    if (slot == NULL) {
   3669        return;
   3670    }
   3671    sftk_DBShutdown(slot);
   3672    return;
   3673 }
   3674 
   3675 extern void sftk_PBELockInit(void);
   3676 extern void sftk_PBELockShutdown(void);
   3677 
   3678 /* Parse the library parameters from the first occurance in the following src.:
   3679 * 1. C_INITIALIZED_ARGS - lib params are included in LibraryParameters field
   3680 * 2. NSS_LIB_PARAMS - env. var. containing the lib. params.
   3681 * 3. NSS_LIB_PARAMS_FILE - env. var. pointion to a file with lib. params.
   3682 * 4. /etc/nss/params.config - default lib. param. file location [Linux only]
   3683 * 5. LIB_PARAM_DEFAULT - string ensureing the pressence at all times
   3684 *    "configdir='' certPrefix='' keyPrefix='' secmod='' flags=noCertDB,noModDB"
   3685 */
   3686 static CK_RV
   3687 sftk_getParameters(CK_C_INITIALIZE_ARGS *init_args, PRBool isFIPS,
   3688                   sftk_parameters *paramStrings)
   3689 {
   3690    CK_RV crv;
   3691    char *libParams;
   3692    const char *filename;
   3693    PRFileDesc *file_dc;
   3694    PRBool free_mem = PR_FALSE;
   3695 
   3696    if (!init_args || !init_args->LibraryParameters) {
   3697        /* Library parameters were not provided via C_Initialize_args*/
   3698 
   3699        /* Enviromental value has precedence to configuration filename */
   3700        libParams = PR_GetEnvSecure("NSS_LIB_PARAMS");
   3701 
   3702        if (!libParams) {
   3703            /* Load from config filename or use default */
   3704            filename = PR_GetEnvSecure("NSS_LIB_PARAMS_FILE");
   3705 #ifdef XP_UNIX
   3706            /* Use default configuration file for Linux only */
   3707            if (!filename)
   3708                filename = LIB_PARAM_DEFAULT_FILE_LOCATION;
   3709 #endif
   3710            if (filename) {
   3711                file_dc = PR_OpenFile(filename, PR_RDONLY, 444);
   3712                if (file_dc) {
   3713                    /* file opened */
   3714                    PRInt32 len = PR_Available(file_dc);
   3715                    libParams = PORT_NewArray(char, len + 1);
   3716                    if (libParams) {
   3717                        /* memory allocated */
   3718                        if (PR_Read(file_dc, libParams, len) == -1) {
   3719                            PORT_Free(libParams);
   3720                            libParams = NULL;
   3721                        } else {
   3722                            free_mem = PR_TRUE;
   3723                            libParams[len] = '\0';
   3724                        }
   3725                    }
   3726 
   3727                    PR_Close(file_dc);
   3728                }
   3729            }
   3730        }
   3731 
   3732        if (libParams == NULL)
   3733            libParams = LIB_PARAM_DEFAULT;
   3734 
   3735    } else {
   3736        /* Use parameters provided with C_Initialize_args */
   3737        libParams = (char *)init_args->LibraryParameters;
   3738    }
   3739 
   3740    crv = sftk_parseParameters(libParams, paramStrings, isFIPS);
   3741    if (crv != CKR_OK) {
   3742        crv = CKR_ARGUMENTS_BAD;
   3743        goto loser;
   3744    }
   3745 
   3746    crv = CKR_OK;
   3747 loser:
   3748    if (free_mem)
   3749        PORT_Free(libParams);
   3750 
   3751    return crv;
   3752 }
   3753 
   3754 /* NSC_Initialize initializes the Cryptoki library. */
   3755 CK_RV
   3756 nsc_CommonInitialize(CK_VOID_PTR pReserved, PRBool isFIPS)
   3757 {
   3758    CK_RV crv = CKR_OK;
   3759    SECStatus rv;
   3760    CK_C_INITIALIZE_ARGS *init_args = (CK_C_INITIALIZE_ARGS *)pReserved;
   3761    PRBool destroy_freelist_on_error = PR_TRUE;
   3762    int i;
   3763    unsigned int moduleIndex = isFIPS ? NSC_FIPS_MODULE : NSC_NON_FIPS_MODULE;
   3764 
   3765    if (isFIPS) {
   3766        loginWaitTime = PR_SecondsToInterval(1);
   3767    }
   3768 
   3769    ENABLE_FORK_CHECK();
   3770 
   3771    sftk_PBELockInit();
   3772 
   3773    rv = SECOID_Init();
   3774    if (rv != SECSuccess) {
   3775        crv = CKR_DEVICE_ERROR;
   3776        return crv;
   3777    }
   3778 
   3779    rv = BL_Init(); /* initialize freebl engine */
   3780    if (rv != SECSuccess) {
   3781        crv = CKR_DEVICE_ERROR;
   3782        return crv;
   3783    }
   3784 
   3785    rv = RNG_RNGInit(); /* initialize random number generator */
   3786    if (rv != SECSuccess) {
   3787        crv = CKR_DEVICE_ERROR;
   3788        return crv;
   3789    }
   3790 
   3791    /* NOTE:
   3792     * we should be getting out mutexes from this list, not statically binding
   3793     * them from NSPR. This should happen before we allow the internal to split
   3794     * off from the rest on NSS.
   3795     */
   3796 
   3797    /* initialize the key and cert db's */
   3798    if (init_args && (!(init_args->flags & CKF_OS_LOCKING_OK))) {
   3799        if (init_args->CreateMutex && init_args->DestroyMutex &&
   3800            init_args->LockMutex && init_args->UnlockMutex) {
   3801            /* softoken always uses NSPR (ie. OS locking), and doesn't know how
   3802             * to use the lock functions provided by the application.
   3803             */
   3804            crv = CKR_CANT_LOCK;
   3805            return crv;
   3806        }
   3807        if (init_args->CreateMutex || init_args->DestroyMutex ||
   3808            init_args->LockMutex || init_args->UnlockMutex) {
   3809            /* only some of the lock functions were provided by the
   3810             * application. This is invalid per PKCS#11 spec.
   3811             */
   3812            crv = CKR_ARGUMENTS_BAD;
   3813            return crv;
   3814        }
   3815    }
   3816 
   3817    sftk_parameters paramStrings;
   3818 
   3819    /* load and parse the library parameters */
   3820    crv = sftk_getParameters(init_args, isFIPS, &paramStrings);
   3821    if (crv != CKR_OK) {
   3822        goto loser;
   3823    }
   3824 
   3825    crv = sftk_configure(paramStrings.man, paramStrings.libdes);
   3826    if (crv != CKR_OK) {
   3827        goto loser;
   3828    }
   3829 
   3830    /* if we have a peer already open, have him close his DB's so we
   3831     * don't clobber each other. */
   3832    if ((isFIPS && nsc_init) || (!isFIPS && nsf_init)) {
   3833        sftk_closePeer(isFIPS);
   3834        if (sftk_audit_enabled) {
   3835            if (isFIPS && nsc_init) {
   3836                sftk_LogAuditMessage(NSS_AUDIT_INFO, NSS_AUDIT_FIPS_STATE,
   3837                                     "enabled FIPS mode");
   3838            } else {
   3839                sftk_LogAuditMessage(NSS_AUDIT_INFO, NSS_AUDIT_FIPS_STATE,
   3840                                     "disabled FIPS mode");
   3841            }
   3842        }
   3843        /* if we have a peer open, we don't want to destroy the freelist
   3844         * from under the peer if we fail, the free list will be
   3845         * destroyed in that case when the C_Finalize is called for
   3846         * the peer */
   3847        destroy_freelist_on_error = PR_FALSE;
   3848    }
   3849    /* allow us to create objects in SFTK_SlotInit */
   3850    sftk_InitFreeLists();
   3851 
   3852    for (i = 0; i < paramStrings.token_count; i++) {
   3853        crv = SFTK_SlotInit(paramStrings.configdir,
   3854                            paramStrings.updatedir, paramStrings.updateID,
   3855                            &paramStrings.tokens[i], moduleIndex);
   3856        if (crv != CKR_OK) {
   3857            nscFreeAllSlots(moduleIndex);
   3858            break;
   3859        }
   3860    }
   3861 
   3862 loser:
   3863 
   3864    sftk_freeParams(&paramStrings);
   3865 
   3866    if (destroy_freelist_on_error && (CKR_OK != crv)) {
   3867        /* idempotent. If the list are already freed, this is a noop */
   3868        sftk_CleanupFreeLists();
   3869    }
   3870 
   3871 #ifndef NO_FORK_CHECK
   3872    if (CKR_OK == crv) {
   3873 #if defined(CHECK_FORK_MIXED)
   3874        /* Before Solaris 10, fork handlers are not unregistered at dlclose()
   3875         * time. So, we only use pthread_atfork on Solaris 10 and later. For
   3876         * earlier versions, we use PID checks.
   3877         */
   3878        char buf[200];
   3879        int major = 0, minor = 0;
   3880 
   3881        long rv = sysinfo(SI_RELEASE, buf, sizeof(buf));
   3882        if (rv > 0 && rv < sizeof(buf)) {
   3883            if (2 == sscanf(buf, "%d.%d", &major, &minor)) {
   3884                /* Are we on Solaris 10 or greater ? */
   3885                if (major > 5 || (5 == major && minor >= 10)) {
   3886                    /* we are safe to use pthread_atfork */
   3887                    usePthread_atfork = PR_TRUE;
   3888                }
   3889            }
   3890        }
   3891        if (usePthread_atfork) {
   3892            pthread_atfork(NULL, NULL, ForkedChild);
   3893        } else {
   3894            myPid = getpid();
   3895        }
   3896 
   3897 #elif defined(CHECK_FORK_PTHREAD)
   3898        pthread_atfork(NULL, NULL, ForkedChild);
   3899 #elif defined(CHECK_FORK_GETPID)
   3900        myPid = getpid();
   3901 #else
   3902 #error Incorrect fork check method.
   3903 #endif
   3904    }
   3905 #endif
   3906    return crv;
   3907 }
   3908 
   3909 CK_RV
   3910 NSC_Initialize(CK_VOID_PTR pReserved)
   3911 {
   3912    CK_RV crv;
   3913 
   3914    sftk_ForkReset(pReserved, &crv);
   3915 
   3916    if (nsc_init) {
   3917        return CKR_CRYPTOKI_ALREADY_INITIALIZED;
   3918    }
   3919    crv = nsc_CommonInitialize(pReserved, PR_FALSE);
   3920    nsc_init = (PRBool)(crv == CKR_OK);
   3921    return crv;
   3922 }
   3923 
   3924 /* NSC_Finalize indicates that an application is done with the
   3925 * Cryptoki library.*/
   3926 CK_RV
   3927 nsc_CommonFinalize(CK_VOID_PTR pReserved, PRBool isFIPS)
   3928 {
   3929    /* propagate the fork status to freebl and util */
   3930    BL_SetForkState(parentForkedAfterC_Initialize);
   3931    UTIL_SetForkState(parentForkedAfterC_Initialize);
   3932 
   3933    nscFreeAllSlots(isFIPS ? NSC_FIPS_MODULE : NSC_NON_FIPS_MODULE);
   3934 
   3935    /* don't muck with the globals if our peer is still initialized */
   3936    if (isFIPS && nsc_init) {
   3937        return CKR_OK;
   3938    }
   3939    if (!isFIPS && nsf_init) {
   3940        return CKR_OK;
   3941    }
   3942 
   3943    sftk_CleanupFreeLists();
   3944    sftkdb_Shutdown();
   3945 
   3946    /* This function does not discard all our previously aquired entropy. */
   3947    RNG_RNGShutdown();
   3948 
   3949    /* tell freeBL to clean up after itself */
   3950    BL_Cleanup();
   3951 
   3952    /* reset fork status in freebl. We must do this before BL_Unload so that
   3953     * this call doesn't force freebl to be reloaded. */
   3954    BL_SetForkState(PR_FALSE);
   3955 
   3956 #ifndef NSS_STATIC_SOFTOKEN
   3957    /* unload freeBL shared library from memory. This may only decrement the
   3958     * OS refcount if it's been loaded multiple times, eg. by libssl */
   3959    BL_Unload();
   3960 #endif
   3961 
   3962    /* clean up the default OID table */
   3963    SECOID_Shutdown();
   3964 
   3965    sftk_PBELockShutdown();
   3966 
   3967    /* reset fork status in util */
   3968    UTIL_SetForkState(PR_FALSE);
   3969 
   3970    nsc_init = PR_FALSE;
   3971 
   3972 #ifndef NO_FORK_CHECK
   3973 #ifdef CHECK_FORK_MIXED
   3974    if (!usePthread_atfork) {
   3975        myPid = 0; /* allow CHECK_FORK in the next softoken initialization to
   3976                    * succeed */
   3977    } else {
   3978        forked = PR_FALSE; /* allow reinitialization */
   3979    }
   3980 #elif defined(CHECK_FORK_GETPID)
   3981    myPid = 0; /* allow reinitialization */
   3982 #elif defined(CHECK_FORK_PTHREAD)
   3983    forked = PR_FALSE; /* allow reinitialization */
   3984 #endif
   3985 #endif
   3986    return CKR_OK;
   3987 }
   3988 
   3989 /* Hard-reset the entire softoken PKCS#11 module if the parent process forked
   3990 * while it was initialized. */
   3991 PRBool
   3992 sftk_ForkReset(CK_VOID_PTR pReserved, CK_RV *crv)
   3993 {
   3994 #ifndef NO_FORK_CHECK
   3995    if (PARENT_FORKED()) {
   3996        parentForkedAfterC_Initialize = PR_TRUE;
   3997        if (nsc_init) {
   3998            /* finalize non-FIPS token */
   3999            *crv = nsc_CommonFinalize(pReserved, PR_FALSE);
   4000            PORT_Assert(CKR_OK == *crv);
   4001            nsc_init = (PRBool) !(*crv == CKR_OK);
   4002        }
   4003        if (nsf_init) {
   4004            /* finalize FIPS token */
   4005            *crv = nsc_CommonFinalize(pReserved, PR_TRUE);
   4006            PORT_Assert(CKR_OK == *crv);
   4007            nsf_init = (PRBool) !(*crv == CKR_OK);
   4008        }
   4009        parentForkedAfterC_Initialize = PR_FALSE;
   4010        return PR_TRUE;
   4011    }
   4012 #endif
   4013    return PR_FALSE;
   4014 }
   4015 
   4016 /* NSC_Finalize indicates that an application is done with the
   4017 * Cryptoki library.*/
   4018 CK_RV
   4019 NSC_Finalize(CK_VOID_PTR pReserved)
   4020 {
   4021    CK_RV crv;
   4022 
   4023    /* reset entire PKCS#11 module upon fork */
   4024    if (sftk_ForkReset(pReserved, &crv)) {
   4025        return crv;
   4026    }
   4027 
   4028    if (!nsc_init) {
   4029        return CKR_OK;
   4030    }
   4031 
   4032    crv = nsc_CommonFinalize(pReserved, PR_FALSE);
   4033 
   4034    nsc_init = (PRBool) !(crv == CKR_OK);
   4035 
   4036    return crv;
   4037 }
   4038 
   4039 extern const char __nss_softokn_version[];
   4040 
   4041 /* NSC_GetInfo returns general information about Cryptoki. */
   4042 CK_RV
   4043 NSC_GetInfo(CK_INFO_PTR pInfo)
   4044 {
   4045 #define NSS_VERSION_VARIABLE __nss_softokn_version
   4046 #include "verref.h"
   4047 
   4048    CHECK_FORK();
   4049 
   4050    pInfo->cryptokiVersion.major = CRYPTOKI_VERSION_MAJOR;
   4051    pInfo->cryptokiVersion.minor = CRYPTOKI_VERSION_MINOR;
   4052    PORT_Memcpy(pInfo->manufacturerID, manufacturerID, 32);
   4053    pInfo->libraryVersion.major = SOFTOKEN_VMAJOR;
   4054    pInfo->libraryVersion.minor = SOFTOKEN_VMINOR;
   4055    PORT_Memcpy(pInfo->libraryDescription, libraryDescription, 32);
   4056    pInfo->flags = 0;
   4057    return CKR_OK;
   4058 }
   4059 
   4060 /* NSC_GetInfo returns general information about Cryptoki. */
   4061 CK_RV
   4062 NSC_GetInfoV2(CK_INFO_PTR pInfo)
   4063 {
   4064    CHECK_FORK();
   4065 
   4066    pInfo->cryptokiVersion.major = 2;
   4067    pInfo->cryptokiVersion.minor = 40;
   4068    PORT_Memcpy(pInfo->manufacturerID, manufacturerID, 32);
   4069    pInfo->libraryVersion.major = SOFTOKEN_VMAJOR;
   4070    pInfo->libraryVersion.minor = SOFTOKEN_VMINOR;
   4071    PORT_Memcpy(pInfo->libraryDescription, libraryDescription, 32);
   4072    pInfo->flags = 0;
   4073    return CKR_OK;
   4074 }
   4075 
   4076 /* NSC_GetSlotList obtains a list of slots in the system. */
   4077 CK_RV
   4078 nsc_CommonGetSlotList(CK_BBOOL tokenPresent,
   4079                      CK_SLOT_ID_PTR pSlotList, CK_ULONG_PTR pulCount,
   4080                      unsigned int moduleIndex)
   4081 {
   4082    *pulCount = nscSlotCount[moduleIndex];
   4083    if (pSlotList != NULL) {
   4084        PORT_Memcpy(pSlotList, nscSlotList[moduleIndex],
   4085                    nscSlotCount[moduleIndex] * sizeof(CK_SLOT_ID));
   4086    }
   4087    return CKR_OK;
   4088 }
   4089 
   4090 /* NSC_GetSlotList obtains a list of slots in the system. */
   4091 CK_RV
   4092 NSC_GetSlotList(CK_BBOOL tokenPresent,
   4093                CK_SLOT_ID_PTR pSlotList, CK_ULONG_PTR pulCount)
   4094 {
   4095    CHECK_FORK();
   4096    return nsc_CommonGetSlotList(tokenPresent, pSlotList, pulCount,
   4097                                 NSC_NON_FIPS_MODULE);
   4098 }
   4099 
   4100 /* NSC_GetSlotInfo obtains information about a particular slot in the system. */
   4101 CK_RV
   4102 NSC_GetSlotInfo(CK_SLOT_ID slotID, CK_SLOT_INFO_PTR pInfo)
   4103 {
   4104    SFTKSlot *slot = sftk_SlotFromID(slotID, PR_TRUE);
   4105 
   4106    CHECK_FORK();
   4107 
   4108    if (slot == NULL)
   4109        return CKR_SLOT_ID_INVALID;
   4110 
   4111    PORT_Memcpy(pInfo->manufacturerID, manufacturerID,
   4112                sizeof(pInfo->manufacturerID));
   4113    PORT_Memcpy(pInfo->slotDescription, slot->slotDescription,
   4114                sizeof(pInfo->slotDescription));
   4115    pInfo->flags = (slot->present) ? CKF_TOKEN_PRESENT : 0;
   4116 
   4117    /* all user defined slots are defined as removable */
   4118    if (slotID >= SFTK_MIN_USER_SLOT_ID) {
   4119        pInfo->flags |= CKF_REMOVABLE_DEVICE;
   4120    } else {
   4121        /* In the case where we are doing a merge update, we need
   4122         * the DB slot to be removable so the token name can change
   4123         * appropriately. */
   4124        SFTKDBHandle *handle = sftk_getKeyDB(slot);
   4125        if (handle) {
   4126            if (sftkdb_InUpdateMerge(handle)) {
   4127                pInfo->flags |= CKF_REMOVABLE_DEVICE;
   4128            }
   4129            sftk_freeDB(handle);
   4130        }
   4131    }
   4132 
   4133    /* If there is no key database, this is for example the case when NSS was
   4134     * initialized with NSS_NoDbInit(), then there won't be any point in
   4135     * requesting a PIN. Set the CKF_USER_PIN_INITIALIZED bit so that
   4136     * PK11_NeedUserInit() doesn't indicate that a PIN is needed.
   4137     */
   4138    if (slot->keyDB == NULL) {
   4139        pInfo->flags |= CKF_USER_PIN_INITIALIZED;
   4140    }
   4141 
   4142    /* ok we really should read it out of the keydb file. */
   4143    /* pInfo->hardwareVersion.major = NSSLOWKEY_DB_FILE_VERSION; */
   4144    pInfo->hardwareVersion.major = SOFTOKEN_VMAJOR;
   4145    pInfo->hardwareVersion.minor = SOFTOKEN_VMINOR;
   4146    pInfo->firmwareVersion.major = SOFTOKEN_VPATCH;
   4147    pInfo->firmwareVersion.minor = SOFTOKEN_VBUILD;
   4148    return CKR_OK;
   4149 }
   4150 
   4151 /*
   4152 * check the current state of the 'needLogin' flag in case the database has
   4153 * been changed underneath us.
   4154 */
   4155 static PRBool
   4156 sftk_checkNeedLogin(SFTKSlot *slot, SFTKDBHandle *keyHandle)
   4157 {
   4158    PRBool needLogin;
   4159    if (sftkdb_PWCached(keyHandle) == SECSuccess) {
   4160        PZ_Lock(slot->slotLock);
   4161        needLogin = slot->needLogin;
   4162        PZ_Unlock(slot->slotLock);
   4163    } else {
   4164        needLogin = (PRBool)!sftk_hasNullPassword(slot, keyHandle);
   4165        PZ_Lock(slot->slotLock);
   4166        slot->needLogin = needLogin;
   4167        PZ_Unlock(slot->slotLock);
   4168    }
   4169    return needLogin;
   4170 }
   4171 
   4172 static PRBool
   4173 sftk_isBlank(const char *s, int len)
   4174 {
   4175    int i;
   4176    for (i = 0; i < len; i++) {
   4177        if (s[i] != ' ') {
   4178            return PR_FALSE;
   4179        }
   4180    }
   4181    return PR_TRUE;
   4182 }
   4183 
   4184 /* NSC_GetTokenInfo obtains information about a particular token in
   4185 * the system. */
   4186 CK_RV
   4187 NSC_GetTokenInfo(CK_SLOT_ID slotID, CK_TOKEN_INFO_PTR pInfo)
   4188 {
   4189    SFTKSlot *slot;
   4190    SFTKDBHandle *handle;
   4191 
   4192    CHECK_FORK();
   4193 
   4194    if (!nsc_init && !nsf_init)
   4195        return CKR_CRYPTOKI_NOT_INITIALIZED;
   4196    slot = sftk_SlotFromID(slotID, PR_FALSE);
   4197    if (slot == NULL)
   4198        return CKR_SLOT_ID_INVALID;
   4199 
   4200    PORT_Memcpy(pInfo->manufacturerID, manufacturerID, 32);
   4201    PORT_Memcpy(pInfo->model, "NSS 3           ", 16);
   4202    PORT_Memcpy(pInfo->serialNumber, "0000000000000000", 16);
   4203    PORT_Memcpy(pInfo->utcTime, "0000000000000000", 16);
   4204    pInfo->ulMaxSessionCount = 0;   /* arbitrarily large */
   4205    pInfo->ulMaxRwSessionCount = 0; /* arbitarily large */
   4206    PZ_Lock(slot->slotLock);        /* Protect sessionCount / rwSessioncount */
   4207    pInfo->ulSessionCount = slot->sessionCount;
   4208    pInfo->ulRwSessionCount = slot->rwSessionCount;
   4209    PZ_Unlock(slot->slotLock); /* Unlock before sftk_getKeyDB */
   4210    pInfo->firmwareVersion.major = 0;
   4211    pInfo->firmwareVersion.minor = 0;
   4212    PORT_Memcpy(pInfo->label, slot->tokDescription, sizeof(pInfo->label));
   4213    handle = sftk_getKeyDB(slot);
   4214    pInfo->flags = CKF_RNG | CKF_DUAL_CRYPTO_OPERATIONS;
   4215    if (handle == NULL) {
   4216        pInfo->flags |= CKF_WRITE_PROTECTED;
   4217        pInfo->ulMaxPinLen = 0;
   4218        pInfo->ulMinPinLen = 0;
   4219        pInfo->ulTotalPublicMemory = 0;
   4220        pInfo->ulFreePublicMemory = 0;
   4221        pInfo->ulTotalPrivateMemory = 0;
   4222        pInfo->ulFreePrivateMemory = 0;
   4223        pInfo->hardwareVersion.major = 4;
   4224        pInfo->hardwareVersion.minor = 0;
   4225    } else {
   4226        /*
   4227         * we have three possible states which we may be in:
   4228         *   (1) No DB password has been initialized. This also means we
   4229         *   have no keys in the key db.
   4230         *   (2) Password initialized to NULL. This means we have keys, but
   4231         *   the user has chosen not use a password.
   4232         *   (3) Finally we have an initialized password whicn is not NULL, and
   4233         *   we will need to prompt for it.
   4234         */
   4235        if (sftkdb_HasPasswordSet(handle) == SECFailure) {
   4236            pInfo->flags |= CKF_LOGIN_REQUIRED;
   4237        } else if (!sftk_checkNeedLogin(slot, handle)) {
   4238            pInfo->flags |= CKF_USER_PIN_INITIALIZED;
   4239        } else {
   4240            pInfo->flags |= CKF_LOGIN_REQUIRED | CKF_USER_PIN_INITIALIZED;
   4241            /*
   4242             * if we are doing a merge style update, and we need to get the password
   4243             * of our source database (the database we are updating from), make sure we
   4244             * return a token name that will match the database we are prompting for.
   4245             */
   4246            if (sftkdb_NeedUpdateDBPassword(handle)) {
   4247                /* if we have an update tok description, use it. otherwise
   4248                 * use the updateID for this database */
   4249                if (!sftk_isBlank(slot->updateTokDescription,
   4250                                  sizeof(pInfo->label))) {
   4251                    PORT_Memcpy(pInfo->label, slot->updateTokDescription,
   4252                                sizeof(pInfo->label));
   4253                } else {
   4254                    /* build from updateID */
   4255                    const char *updateID = sftkdb_GetUpdateID(handle);
   4256                    if (updateID) {
   4257                        sftk_setStringName(updateID, (char *)pInfo->label,
   4258                                           sizeof(pInfo->label), PR_FALSE);
   4259                    }
   4260                }
   4261            }
   4262        }
   4263        pInfo->ulMaxPinLen = SFTK_MAX_PIN;
   4264        pInfo->ulMinPinLen = (CK_ULONG)slot->minimumPinLen;
   4265        pInfo->ulTotalPublicMemory = 1;
   4266        pInfo->ulFreePublicMemory = 1;
   4267        pInfo->ulTotalPrivateMemory = 1;
   4268        pInfo->ulFreePrivateMemory = 1;
   4269 #ifdef SHDB_FIXME
   4270        pInfo->hardwareVersion.major = CERT_DB_FILE_VERSION;
   4271        pInfo->hardwareVersion.minor = handle->version;
   4272 #else
   4273        pInfo->hardwareVersion.major = 0;
   4274        pInfo->hardwareVersion.minor = 0;
   4275 #endif
   4276        sftk_freeDB(handle);
   4277    }
   4278    /*
   4279     * CKF_LOGIN_REQUIRED CKF_USER_PIN_INITIALIZED  how CKF_TOKEN_INITIALIZED
   4280     *                                              should be set
   4281     *         0                   0                           1
   4282     *         1                   0                           0
   4283     *         0                   1                           1
   4284     *         1                   1                           1
   4285     */
   4286    if (!(pInfo->flags & CKF_LOGIN_REQUIRED) ||
   4287        (pInfo->flags & CKF_USER_PIN_INITIALIZED)) {
   4288        pInfo->flags |= CKF_TOKEN_INITIALIZED;
   4289    }
   4290    return CKR_OK;
   4291 }
   4292 
   4293 /* NSC_GetMechanismList obtains a list of mechanism types
   4294 * supported by a token. */
   4295 CK_RV
   4296 NSC_GetMechanismList(CK_SLOT_ID slotID,
   4297                     CK_MECHANISM_TYPE_PTR pMechanismList, CK_ULONG_PTR pulCount)
   4298 {
   4299    CK_ULONG i;
   4300 
   4301    CHECK_FORK();
   4302 
   4303    switch (slotID) {
   4304        /* default: */
   4305        case NETSCAPE_SLOT_ID:
   4306            *pulCount = mechanismCount;
   4307            if (pMechanismList != NULL) {
   4308                for (i = 0; i < mechanismCount; i++) {
   4309                    pMechanismList[i] = mechanisms[i].type;
   4310                }
   4311            }
   4312            break;
   4313        default:
   4314            *pulCount = 0;
   4315            for (i = 0; i < mechanismCount; i++) {
   4316                if (mechanisms[i].privkey) {
   4317                    (*pulCount)++;
   4318                    if (pMechanismList != NULL) {
   4319                        *pMechanismList++ = mechanisms[i].type;
   4320                    }
   4321                }
   4322            }
   4323            break;
   4324    }
   4325    return CKR_OK;
   4326 }
   4327 
   4328 /* NSC_GetMechanismInfo obtains information about a particular mechanism
   4329 * possibly supported by a token. */
   4330 CK_RV
   4331 NSC_GetMechanismInfo(CK_SLOT_ID slotID, CK_MECHANISM_TYPE type,
   4332                     CK_MECHANISM_INFO_PTR pInfo)
   4333 {
   4334    PRBool isPrivateKey;
   4335    CK_ULONG i;
   4336 
   4337    CHECK_FORK();
   4338 
   4339    switch (slotID) {
   4340        case NETSCAPE_SLOT_ID:
   4341            isPrivateKey = PR_FALSE;
   4342            break;
   4343        default:
   4344            isPrivateKey = PR_TRUE;
   4345            break;
   4346    }
   4347    for (i = 0; i < mechanismCount; i++) {
   4348        if (type == mechanisms[i].type) {
   4349            if (isPrivateKey && !mechanisms[i].privkey) {
   4350                return CKR_MECHANISM_INVALID;
   4351            }
   4352            PORT_Memcpy(pInfo, &mechanisms[i].info, sizeof(CK_MECHANISM_INFO));
   4353            return CKR_OK;
   4354        }
   4355    }
   4356    return CKR_MECHANISM_INVALID;
   4357 }
   4358 
   4359 /*
   4360 * If we are using the V2 interface, strip out the message flags
   4361 */
   4362 #define SFTK_MESSAGE_FLAGS (CKF_MESSAGE_ENCRYPT | CKF_MESSAGE_DECRYPT | CKF_MESSAGE_SIGN | CKF_MESSAGE_VERIFY)
   4363 CK_RV
   4364 NSC_GetMechanismInfoV2(CK_SLOT_ID slotID, CK_MECHANISM_TYPE type,
   4365                       CK_MECHANISM_INFO_PTR pInfo)
   4366 {
   4367    CK_RV crv;
   4368    crv = NSC_GetMechanismInfo(slotID, type, pInfo);
   4369    if (crv == CKR_OK) {
   4370        pInfo->flags = pInfo->flags & ~SFTK_MESSAGE_FLAGS;
   4371    }
   4372    return crv;
   4373 }
   4374 
   4375 CK_RV
   4376 sftk_MechAllowsOperation(CK_MECHANISM_TYPE type, CK_ATTRIBUTE_TYPE op)
   4377 {
   4378    CK_ULONG i;
   4379    CK_FLAGS flags = sftk_AttributeToFlags(op);
   4380 
   4381    if (flags == 0) {
   4382        return CKR_ARGUMENTS_BAD;
   4383    }
   4384    for (i = 0; i < mechanismCount; i++) {
   4385        if (type == mechanisms[i].type) {
   4386            return (flags & mechanisms[i].info.flags) ? CKR_OK
   4387                                                      : CKR_MECHANISM_INVALID;
   4388        }
   4389    }
   4390    return CKR_MECHANISM_INVALID;
   4391 }
   4392 
   4393 /* NSC_InitToken initializes a token. */
   4394 CK_RV
   4395 NSC_InitToken(CK_SLOT_ID slotID, CK_CHAR_PTR pPin,
   4396              CK_ULONG ulPinLen, CK_CHAR_PTR pLabel)
   4397 {
   4398    SFTKSlot *slot = sftk_SlotFromID(slotID, PR_FALSE);
   4399    SFTKDBHandle *handle;
   4400    SECStatus rv;
   4401    unsigned int i;
   4402    SFTKObject *object;
   4403 
   4404    CHECK_FORK();
   4405 
   4406    if (slot == NULL)
   4407        return CKR_SLOT_ID_INVALID;
   4408 
   4409    /* don't initialize the database if we aren't talking to a token
   4410     * that uses the key database.
   4411     */
   4412    if (slotID == NETSCAPE_SLOT_ID) {
   4413        return CKR_TOKEN_WRITE_PROTECTED;
   4414    }
   4415 
   4416    /* first, delete all our loaded key and cert objects from our
   4417     * internal list. */
   4418    PZ_Lock(slot->objectLock);
   4419    for (i = 0; i < slot->sessObjHashSize; i++) {
   4420        do {
   4421            object = slot->sessObjHashTable[i];
   4422            /* hand deque */
   4423            /* this duplicates function of NSC_close session functions, but
   4424             * because we know that we are freeing all the sessions, we can
   4425             * do more efficient processing */
   4426            if (object) {
   4427                slot->sessObjHashTable[i] = object->next;
   4428 
   4429                if (object->next)
   4430                    object->next->prev = NULL;
   4431                object->next = object->prev = NULL;
   4432            }
   4433            if (object)
   4434                sftk_FreeObject(object);
   4435        } while (object != NULL);
   4436    }
   4437    slot->DB_loaded = PR_FALSE;
   4438    PZ_Unlock(slot->objectLock);
   4439 
   4440    /* then clear out the key database */
   4441    handle = sftk_getKeyDB(slot);
   4442    if (handle == NULL) {
   4443        return CKR_TOKEN_WRITE_PROTECTED;
   4444    }
   4445 
   4446    rv = sftkdb_ResetKeyDB(handle);
   4447    /* clear the password */
   4448    sftkdb_ClearPassword(handle);
   4449    /* update slot->needLogin (should be true now since no password is set) */
   4450    sftk_checkNeedLogin(slot, handle);
   4451    sftk_freeDB(handle);
   4452    if (rv != SECSuccess) {
   4453        return CKR_DEVICE_ERROR;
   4454    }
   4455 
   4456    return CKR_OK;
   4457 }
   4458 
   4459 /* NSC_InitPIN initializes the normal user's PIN. */
   4460 CK_RV
   4461 NSC_InitPIN(CK_SESSION_HANDLE hSession,
   4462            CK_CHAR_PTR pPin, CK_ULONG ulPinLen)
   4463 {
   4464    SFTKSession *sp = NULL;
   4465    SFTKSlot *slot;
   4466    SFTKDBHandle *handle = NULL;
   4467    char newPinStr[SFTK_MAX_PIN + 1];
   4468    SECStatus rv;
   4469    CK_RV crv = CKR_SESSION_HANDLE_INVALID;
   4470    PRBool tokenRemoved = PR_FALSE;
   4471 
   4472    CHECK_FORK();
   4473 
   4474    sp = sftk_SessionFromHandle(hSession);
   4475    if (sp == NULL) {
   4476        goto loser;
   4477    }
   4478 
   4479    slot = sftk_SlotFromSession(sp);
   4480    if (slot == NULL) {
   4481        goto loser;
   4482    }
   4483 
   4484    handle = sftk_getKeyDB(slot);
   4485    if (handle == NULL) {
   4486        crv = CKR_PIN_LEN_RANGE;
   4487        goto loser;
   4488    }
   4489 
   4490    if (sp->info.state != CKS_RW_SO_FUNCTIONS) {
   4491        crv = CKR_USER_NOT_LOGGED_IN;
   4492        goto loser;
   4493    }
   4494 
   4495    sftk_FreeSession(sp);
   4496    sp = NULL;
   4497 
   4498    /* make sure the pins aren't too long */
   4499    if (ulPinLen > SFTK_MAX_PIN) {
   4500        crv = CKR_PIN_LEN_RANGE;
   4501        goto loser;
   4502    }
   4503    if (ulPinLen < (CK_ULONG)slot->minimumPinLen) {
   4504        crv = CKR_PIN_LEN_RANGE;
   4505        goto loser;
   4506    }
   4507 
   4508    if (sftkdb_HasPasswordSet(handle) != SECFailure) {
   4509        crv = CKR_DEVICE_ERROR;
   4510        goto loser;
   4511    }
   4512 
   4513    /* convert to null terminated string */
   4514    PORT_Memcpy(newPinStr, pPin, ulPinLen);
   4515    newPinStr[ulPinLen] = 0;
   4516 
   4517    /* build the hashed pins which we pass around */
   4518 
   4519    /* change the data base */
   4520    rv = sftkdb_ChangePassword(handle, NULL, newPinStr, &tokenRemoved);
   4521    if (tokenRemoved) {
   4522        sftk_CloseAllSessions(slot, PR_FALSE);
   4523    }
   4524    PORT_Memset(newPinStr, 0, ulPinLen);
   4525    sftk_freeDB(handle);
   4526    handle = NULL;
   4527 
   4528    /* Now update our local copy of the pin */
   4529    if (rv == SECSuccess) {
   4530        if (ulPinLen == 0) {
   4531            PZ_Lock(slot->slotLock);
   4532            slot->needLogin = PR_FALSE;
   4533            PZ_Unlock(slot->slotLock);
   4534        }
   4535        /* database has been initialized, now force min password in FIPS
   4536         * mode. NOTE: if we are in level1, we may not have a password, but
   4537         * forcing it now will prevent an insufficient password from being set.
   4538         */
   4539        if ((sftk_GetModuleIndex(slot->slotID) == NSC_FIPS_MODULE) &&
   4540            (slot->minimumPinLen < FIPS_MIN_PIN)) {
   4541            slot->minimumPinLen = FIPS_MIN_PIN;
   4542        }
   4543        return CKR_OK;
   4544    }
   4545    crv = CKR_PIN_INCORRECT;
   4546 
   4547 loser:
   4548    if (sp) {
   4549        sftk_FreeSession(sp);
   4550    }
   4551    if (handle) {
   4552        sftk_freeDB(handle);
   4553    }
   4554    return crv;
   4555 }
   4556 
   4557 /* NSC_SetPIN modifies the PIN of user that is currently logged in. */
   4558 /* NOTE: This is only valid for the PRIVATE_KEY_SLOT */
   4559 CK_RV
   4560 NSC_SetPIN(CK_SESSION_HANDLE hSession, CK_CHAR_PTR pOldPin,
   4561           CK_ULONG ulOldLen, CK_CHAR_PTR pNewPin, CK_ULONG ulNewLen)
   4562 {
   4563    SFTKSession *sp = NULL;
   4564    SFTKSlot *slot;
   4565    SFTKDBHandle *handle = NULL;
   4566    char newPinStr[SFTK_MAX_PIN + 1], oldPinStr[SFTK_MAX_PIN + 1];
   4567    SECStatus rv;
   4568    CK_RV crv = CKR_SESSION_HANDLE_INVALID;
   4569    PRBool needLogin;
   4570    PRBool tokenRemoved = PR_FALSE;
   4571 
   4572    CHECK_FORK();
   4573 
   4574    sp = sftk_SessionFromHandle(hSession);
   4575    if (sp == NULL) {
   4576        goto loser;
   4577    }
   4578 
   4579    slot = sftk_SlotFromSession(sp);
   4580    if (!slot) {
   4581        goto loser;
   4582    }
   4583 
   4584    handle = sftk_getKeyDB(slot);
   4585    if (handle == NULL) {
   4586        sftk_FreeSession(sp);
   4587        return CKR_PIN_LEN_RANGE; /* XXX FIXME wrong return value */
   4588    }
   4589 
   4590    PZ_Lock(slot->slotLock);
   4591    needLogin = slot->needLogin;
   4592    PZ_Unlock(slot->slotLock);
   4593    if (needLogin && sp->info.state != CKS_RW_USER_FUNCTIONS) {
   4594        crv = CKR_USER_NOT_LOGGED_IN;
   4595        goto loser;
   4596    }
   4597 
   4598    sftk_FreeSession(sp);
   4599    sp = NULL;
   4600 
   4601    /* make sure the pins aren't too long */
   4602    if ((ulNewLen > SFTK_MAX_PIN) || (ulOldLen > SFTK_MAX_PIN)) {
   4603        crv = CKR_PIN_LEN_RANGE;
   4604        goto loser;
   4605    }
   4606    /* check the length of new pin, unless both old and new passwords
   4607     * are empty */
   4608    if ((ulNewLen != 0 || ulOldLen != 0) &&
   4609        ulNewLen < (CK_ULONG)slot->minimumPinLen) {
   4610        crv = CKR_PIN_LEN_RANGE;
   4611        goto loser;
   4612    }
   4613 
   4614    /* convert to null terminated string */
   4615    PORT_Memcpy(newPinStr, pNewPin, ulNewLen);
   4616    newPinStr[ulNewLen] = 0;
   4617    PORT_Memcpy(oldPinStr, pOldPin, ulOldLen);
   4618    oldPinStr[ulOldLen] = 0;
   4619 
   4620    /* change the data base password */
   4621    PR_Lock(slot->pwCheckLock);
   4622    rv = sftkdb_ChangePassword(handle, oldPinStr, newPinStr, &tokenRemoved);
   4623    PORT_Memset(newPinStr, 0, ulNewLen);
   4624    PORT_Memset(oldPinStr, 0, ulOldLen);
   4625    if (tokenRemoved) {
   4626        sftk_CloseAllSessions(slot, PR_FALSE);
   4627    }
   4628    if ((rv != SECSuccess) && (sftk_isFIPS(slot->slotID))) {
   4629        PR_Sleep(loginWaitTime);
   4630    }
   4631    PR_Unlock(slot->pwCheckLock);
   4632 
   4633    /* Now update our local copy of the pin */
   4634    if (rv == SECSuccess) {
   4635        PZ_Lock(slot->slotLock);
   4636        slot->needLogin = (PRBool)(ulNewLen != 0);
   4637        slot->isLoggedIn = (PRBool)(sftkdb_PWCached(handle) == SECSuccess);
   4638        PZ_Unlock(slot->slotLock);
   4639        /* Reset login flags. */
   4640        if (ulNewLen == 0) {
   4641            PZ_Lock(slot->slotLock);
   4642            slot->isLoggedIn = PR_FALSE;
   4643            slot->ssoLoggedIn = PR_FALSE;
   4644            PZ_Unlock(slot->slotLock);
   4645 
   4646            tokenRemoved = PR_FALSE;
   4647            rv = sftkdb_CheckPasswordNull(handle, &tokenRemoved);
   4648            if (tokenRemoved) {
   4649                sftk_CloseAllSessions(slot, PR_FALSE);
   4650            }
   4651        }
   4652        sftk_update_all_states(slot);
   4653        sftk_freeDB(handle);
   4654        return CKR_OK;
   4655    }
   4656    crv = CKR_PIN_INCORRECT;
   4657 loser:
   4658    if (sp) {
   4659        sftk_FreeSession(sp);
   4660    }
   4661    if (handle) {
   4662        sftk_freeDB(handle);
   4663    }
   4664    return crv;
   4665 }
   4666 
   4667 /* NSC_OpenSession opens a session between an application and a token. */
   4668 CK_RV
   4669 NSC_OpenSession(CK_SLOT_ID slotID, CK_FLAGS flags,
   4670                CK_VOID_PTR pApplication, CK_NOTIFY Notify, CK_SESSION_HANDLE_PTR phSession)
   4671 {
   4672    SFTKSlot *slot;
   4673    CK_SESSION_HANDLE sessionID;
   4674    SFTKSession *session;
   4675    SFTKSession *sameID;
   4676 
   4677    CHECK_FORK();
   4678 
   4679    slot = sftk_SlotFromID(slotID, PR_FALSE);
   4680    if (slot == NULL)
   4681        return CKR_SLOT_ID_INVALID;
   4682 
   4683    /* new session (we only have serial sessions) */
   4684    session = sftk_NewSession(slotID, Notify, pApplication,
   4685                              flags | CKF_SERIAL_SESSION);
   4686    if (session == NULL)
   4687        return CKR_HOST_MEMORY;
   4688 
   4689    if (slot->readOnly && (flags & CKF_RW_SESSION)) {
   4690        /* NETSCAPE_SLOT_ID is Read ONLY */
   4691        session->info.flags &= ~CKF_RW_SESSION;
   4692    }
   4693    PZ_Lock(slot->slotLock);
   4694    ++slot->sessionCount;
   4695    PZ_Unlock(slot->slotLock);
   4696    if (session->info.flags & CKF_RW_SESSION) {
   4697        (void)PR_ATOMIC_INCREMENT(&slot->rwSessionCount);
   4698    }
   4699 
   4700    do {
   4701        PZLock *lock;
   4702        do {
   4703            sessionID = (PR_ATOMIC_INCREMENT(&slot->sessionIDCount) & 0xffffff) | (slot->index << 24);
   4704        } while (sessionID == CK_INVALID_HANDLE);
   4705        lock = SFTK_SESSION_LOCK(slot, sessionID);
   4706        PZ_Lock(lock);
   4707        sftkqueue_find(sameID, sessionID, slot->head, slot->sessHashSize);
   4708        if (sameID == NULL) {
   4709            session->handle = sessionID;
   4710            sftk_update_state(slot, session);
   4711            sftkqueue_add(session, sessionID, slot->head, slot->sessHashSize);
   4712        } else {
   4713            slot->sessionIDConflict++; /* for debugging */
   4714        }
   4715        PZ_Unlock(lock);
   4716    } while (sameID != NULL);
   4717 
   4718    *phSession = sessionID;
   4719    return CKR_OK;
   4720 }
   4721 
   4722 /* NSC_CloseSession closes a session between an application and a token. */
   4723 CK_RV
   4724 NSC_CloseSession(CK_SESSION_HANDLE hSession)
   4725 {
   4726    SFTKSlot *slot;
   4727    SFTKSession *session;
   4728    PRBool sessionFound;
   4729    PZLock *lock;
   4730 
   4731    CHECK_FORK();
   4732 
   4733    session = sftk_SessionFromHandle(hSession);
   4734    if (session == NULL)
   4735        return CKR_SESSION_HANDLE_INVALID;
   4736    slot = sftk_SlotFromSession(session);
   4737    sessionFound = PR_FALSE;
   4738 
   4739    /* lock */
   4740    lock = SFTK_SESSION_LOCK(slot, hSession);
   4741    PZ_Lock(lock);
   4742    if (sftkqueue_is_queued(session, hSession, slot->head, slot->sessHashSize)) {
   4743        sessionFound = PR_TRUE;
   4744        sftkqueue_delete(session, hSession, slot->head, slot->sessHashSize);
   4745    }
   4746    PZ_Unlock(lock);
   4747 
   4748    if (sessionFound) {
   4749        SFTKDBHandle *handle;
   4750        handle = sftk_getKeyDB(slot);
   4751        PZ_Lock(slot->slotLock);
   4752        if (--slot->sessionCount == 0) {
   4753            slot->isLoggedIn = PR_FALSE;
   4754            if (slot->needLogin && handle) {
   4755                sftkdb_ClearPassword(handle);
   4756            }
   4757        }
   4758        PZ_Unlock(slot->slotLock);
   4759        if (handle) {
   4760            sftk_freeDB(handle);
   4761        }
   4762        if (session->info.flags & CKF_RW_SESSION) {
   4763            (void)PR_ATOMIC_DECREMENT(&slot->rwSessionCount);
   4764        }
   4765        sftk_DestroySession(session);
   4766        session = NULL;
   4767    }
   4768 
   4769    return CKR_OK;
   4770 }
   4771 
   4772 /* NSC_CloseAllSessions closes all sessions with a token. */
   4773 CK_RV
   4774 NSC_CloseAllSessions(CK_SLOT_ID slotID)
   4775 {
   4776    SFTKSlot *slot;
   4777 
   4778 #ifndef NO_FORK_CHECK
   4779    /* skip fork check if we are being called from C_Initialize or C_Finalize */
   4780    if (!parentForkedAfterC_Initialize) {
   4781        CHECK_FORK();
   4782    }
   4783 #endif
   4784 
   4785    slot = sftk_SlotFromID(slotID, PR_FALSE);
   4786    if (slot == NULL)
   4787        return CKR_SLOT_ID_INVALID;
   4788 
   4789    return sftk_CloseAllSessions(slot, PR_TRUE);
   4790 }
   4791 
   4792 /* NSC_GetSessionInfo obtains information about the session. */
   4793 CK_RV
   4794 NSC_GetSessionInfo(CK_SESSION_HANDLE hSession,
   4795                   CK_SESSION_INFO_PTR pInfo)
   4796 {
   4797    SFTKSession *session;
   4798 
   4799    CHECK_FORK();
   4800 
   4801    session = sftk_SessionFromHandle(hSession);
   4802    if (session == NULL)
   4803        return CKR_SESSION_HANDLE_INVALID;
   4804 
   4805    PORT_Memcpy(pInfo, &session->info, sizeof(CK_SESSION_INFO));
   4806    sftk_FreeSession(session);
   4807    return CKR_OK;
   4808 }
   4809 
   4810 /* NSC_Login logs a user into a token. */
   4811 CK_RV
   4812 NSC_Login(CK_SESSION_HANDLE hSession, CK_USER_TYPE userType,
   4813          CK_CHAR_PTR pPin, CK_ULONG ulPinLen)
   4814 {
   4815    SFTKSlot *slot;
   4816    SFTKSession *session;
   4817    SFTKDBHandle *handle;
   4818    CK_FLAGS sessionFlags;
   4819    SECStatus rv;
   4820    CK_RV crv;
   4821    char pinStr[SFTK_MAX_PIN + 1];
   4822    PRBool tokenRemoved = PR_FALSE;
   4823    PRBool isLoggedIn;
   4824    PRBool needLogin;
   4825 
   4826    CHECK_FORK();
   4827 
   4828    /* get the slot */
   4829    slot = sftk_SlotFromSessionHandle(hSession);
   4830    if (slot == NULL) {
   4831        return CKR_SESSION_HANDLE_INVALID;
   4832    }
   4833 
   4834    /* make sure the session is valid */
   4835    session = sftk_SessionFromHandle(hSession);
   4836    if (session == NULL) {
   4837        return CKR_SESSION_HANDLE_INVALID;
   4838    }
   4839    sessionFlags = session->info.flags;
   4840    sftk_FreeSession(session);
   4841    session = NULL;
   4842 
   4843    /* can't log into the Netscape Slot */
   4844    if (slot->slotID == NETSCAPE_SLOT_ID) {
   4845        return CKR_USER_TYPE_INVALID;
   4846    }
   4847 
   4848    PZ_Lock(slot->slotLock);
   4849    isLoggedIn = slot->isLoggedIn;
   4850    needLogin = slot->needLogin;
   4851    PZ_Unlock(slot->slotLock);
   4852 
   4853    if (isLoggedIn)
   4854        return CKR_USER_ALREADY_LOGGED_IN;
   4855    if (!needLogin) {
   4856        return ulPinLen ? CKR_PIN_INCORRECT : CKR_OK;
   4857    }
   4858    slot->ssoLoggedIn = PR_FALSE;
   4859 
   4860    if (ulPinLen > SFTK_MAX_PIN)
   4861        return CKR_PIN_LEN_RANGE;
   4862 
   4863    /* convert to null terminated string */
   4864    if (ulPinLen) {
   4865        PORT_Memcpy(pinStr, pPin, ulPinLen);
   4866    }
   4867    pinStr[ulPinLen] = 0;
   4868 
   4869    handle = sftk_getKeyDB(slot);
   4870    if (handle == NULL) {
   4871        PORT_Memset(pinStr, 0, ulPinLen);
   4872        return CKR_USER_TYPE_INVALID;
   4873    }
   4874 
   4875    /*
   4876     * Deal with bootstrap. We allow the SSO to login in with a NULL
   4877     * password if and only if we haven't initialized the KEY DB yet.
   4878     * We only allow this on a RW session.
   4879     */
   4880    rv = sftkdb_HasPasswordSet(handle);
   4881    if (rv == SECFailure) {
   4882        /* allow SSO's to log in only if there is not password on the
   4883         * key database */
   4884        if (((userType == CKU_SO) && (sessionFlags & CKF_RW_SESSION))
   4885            /* fips always needs to authenticate, even if there isn't a db */
   4886            || (sftk_isFIPS(slot->slotID))) {
   4887            /* should this be a fixed password? */
   4888            if (ulPinLen == 0) {
   4889                sftkdb_ClearPassword(handle);
   4890                PZ_Lock(slot->slotLock);
   4891                slot->isLoggedIn = PR_TRUE;
   4892                slot->ssoLoggedIn = (PRBool)(userType == CKU_SO);
   4893                PZ_Unlock(slot->slotLock);
   4894                sftk_update_all_states(slot);
   4895                crv = CKR_OK;
   4896                goto done;
   4897            }
   4898            crv = CKR_PIN_INCORRECT;
   4899            goto done;
   4900        }
   4901        crv = CKR_USER_TYPE_INVALID;
   4902        goto done;
   4903    }
   4904 
   4905    /* don't allow the SSO to log in if the user is already initialized */
   4906    if (userType != CKU_USER) {
   4907        crv = CKR_USER_TYPE_INVALID;
   4908        goto done;
   4909    }
   4910 
   4911    /* build the hashed pins which we pass around */
   4912    PR_Lock(slot->pwCheckLock);
   4913    rv = sftkdb_CheckPassword(handle, pinStr, &tokenRemoved);
   4914    if (tokenRemoved) {
   4915        sftk_CloseAllSessions(slot, PR_FALSE);
   4916    }
   4917    if ((rv != SECSuccess) && (sftk_isFIPS(slot->slotID))) {
   4918        PR_Sleep(loginWaitTime);
   4919    }
   4920    PR_Unlock(slot->pwCheckLock);
   4921    if (rv == SECSuccess) {
   4922        PZ_Lock(slot->slotLock);
   4923        /* make sure the login state matches the underlying
   4924         * database state */
   4925        slot->isLoggedIn = sftkdb_PWCached(handle) == SECSuccess ? PR_TRUE : PR_FALSE;
   4926        PZ_Unlock(slot->slotLock);
   4927 
   4928        sftk_freeDB(handle);
   4929        handle = NULL;
   4930 
   4931        /* update all sessions */
   4932        sftk_update_all_states(slot);
   4933        return CKR_OK;
   4934    }
   4935 
   4936    crv = CKR_PIN_INCORRECT;
   4937 done:
   4938    PORT_Memset(pinStr, 0, ulPinLen);
   4939    if (handle) {
   4940        sftk_freeDB(handle);
   4941    }
   4942    return crv;
   4943 }
   4944 
   4945 CK_RV
   4946 NSC_LoginUser(CK_SESSION_HANDLE hSession, CK_USER_TYPE userType,
   4947              CK_CHAR_PTR pPin, CK_ULONG ulPinLen, CK_UTF8CHAR_PTR pUsername,
   4948              CK_ULONG ulUsernameLen)
   4949 {
   4950    /* softoken currently does not support additional users */
   4951    return CKR_OPERATION_NOT_INITIALIZED;
   4952 }
   4953 
   4954 /* NSC_Logout logs a user out from a token. */
   4955 CK_RV
   4956 NSC_Logout(CK_SESSION_HANDLE hSession)
   4957 {
   4958    SFTKSlot *slot = sftk_SlotFromSessionHandle(hSession);
   4959    SFTKSession *session;
   4960    SFTKDBHandle *handle;
   4961 
   4962    CHECK_FORK();
   4963 
   4964    if (slot == NULL) {
   4965        return CKR_SESSION_HANDLE_INVALID;
   4966    }
   4967    session = sftk_SessionFromHandle(hSession);
   4968    if (session == NULL)
   4969        return CKR_SESSION_HANDLE_INVALID;
   4970    sftk_FreeSession(session);
   4971    session = NULL;
   4972 
   4973    if (!slot->isLoggedIn)
   4974        return CKR_USER_NOT_LOGGED_IN;
   4975 
   4976    handle = sftk_getKeyDB(slot);
   4977    PZ_Lock(slot->slotLock);
   4978    slot->isLoggedIn = PR_FALSE;
   4979    slot->ssoLoggedIn = PR_FALSE;
   4980    if (slot->needLogin && handle) {
   4981        sftkdb_ClearPassword(handle);
   4982    }
   4983    PZ_Unlock(slot->slotLock);
   4984    if (handle) {
   4985        sftk_freeDB(handle);
   4986    }
   4987 
   4988    sftk_update_all_states(slot);
   4989    return CKR_OK;
   4990 }
   4991 
   4992 /*
   4993 * Create or remove a new slot on the fly.
   4994 * When creating a slot, "slot" is the slot that the request came from. The
   4995 * resulting slot will live in the same module as "slot".
   4996 * When removing a slot, "slot" is the slot to be removed.
   4997 * "object" is the creation object that specifies the module spec for the slot
   4998 * to add or remove.
   4999 */
   5000 static CK_RV
   5001 sftk_CreateNewSlot(SFTKSlot *slot, CK_OBJECT_CLASS class,
   5002                   SFTKObject *object)
   5003 {
   5004    PRBool isValidUserSlot = PR_FALSE;
   5005    PRBool isValidFIPSUserSlot = PR_FALSE;
   5006    PRBool isValidSlot = PR_FALSE;
   5007    PRBool isFIPS = PR_FALSE;
   5008    unsigned int moduleIndex = NSC_NON_FIPS_MODULE;
   5009    SFTKAttribute *attribute;
   5010    sftk_parameters paramStrings;
   5011    char *paramString;
   5012    CK_SLOT_ID slotID = 0;
   5013    SFTKSlot *newSlot = NULL;
   5014    CK_RV crv = CKR_OK;
   5015 
   5016    if (class != CKO_NSS_DELSLOT && class != CKO_NSS_NEWSLOT) {
   5017        return CKR_ATTRIBUTE_VALUE_INVALID;
   5018    }
   5019    if (class == CKO_NSS_NEWSLOT && slot->slotID == FIPS_SLOT_ID) {
   5020        isFIPS = PR_TRUE;
   5021    }
   5022    attribute = sftk_FindAttribute(object, CKA_NSS_MODULE_SPEC);
   5023    if (attribute == NULL) {
   5024        return CKR_TEMPLATE_INCOMPLETE;
   5025    }
   5026    paramString = (char *)attribute->attrib.pValue;
   5027    crv = sftk_parseParameters(paramString, &paramStrings, isFIPS);
   5028    if (crv != CKR_OK) {
   5029        goto loser;
   5030    }
   5031 
   5032    /* enforce only one at a time */
   5033    if (paramStrings.token_count != 1) {
   5034        crv = CKR_ATTRIBUTE_VALUE_INVALID;
   5035        goto loser;
   5036    }
   5037 
   5038    slotID = paramStrings.tokens[0].slotID;
   5039 
   5040    /* stay within the valid ID space */
   5041    isValidUserSlot = (slotID >= SFTK_MIN_USER_SLOT_ID &&
   5042                       slotID <= SFTK_MAX_USER_SLOT_ID);
   5043    isValidFIPSUserSlot = (slotID >= SFTK_MIN_FIPS_USER_SLOT_ID &&
   5044                           slotID <= SFTK_MAX_FIPS_USER_SLOT_ID);
   5045 
   5046    if (class == CKO_NSS_DELSLOT) {
   5047        if (slot->slotID == slotID) {
   5048            isValidSlot = isValidUserSlot || isValidFIPSUserSlot;
   5049        }
   5050    } else {
   5051        /* only the crypto or FIPS slots can create new slot objects */
   5052        if (slot->slotID == NETSCAPE_SLOT_ID) {
   5053            isValidSlot = isValidUserSlot;
   5054            moduleIndex = NSC_NON_FIPS_MODULE;
   5055        } else if (slot->slotID == FIPS_SLOT_ID) {
   5056            isValidSlot = isValidFIPSUserSlot;
   5057            moduleIndex = NSC_FIPS_MODULE;
   5058        }
   5059    }
   5060 
   5061    if (!isValidSlot) {
   5062        crv = CKR_ATTRIBUTE_VALUE_INVALID;
   5063        goto loser;
   5064    }
   5065 
   5066    /* unload any existing slot at this id */
   5067    newSlot = sftk_SlotFromID(slotID, PR_TRUE);
   5068    if (newSlot && newSlot->present) {
   5069        crv = SFTK_ShutdownSlot(newSlot);
   5070        if (crv != CKR_OK) {
   5071            goto loser;
   5072        }
   5073    }
   5074 
   5075    /* if we were just planning on deleting the slot, then do so now */
   5076    if (class == CKO_NSS_DELSLOT) {
   5077        /* sort of a unconventional use of this error code, be we are
   5078         * overusing CKR_ATTRIBUTE_VALUE_INVALID, and it does apply */
   5079        crv = newSlot ? CKR_OK : CKR_SLOT_ID_INVALID;
   5080        goto loser; /* really exit */
   5081    }
   5082 
   5083    if (newSlot) {
   5084        crv = SFTK_SlotReInit(newSlot, paramStrings.configdir,
   5085                              paramStrings.updatedir, paramStrings.updateID,
   5086                              &paramStrings.tokens[0], moduleIndex);
   5087    } else {
   5088        crv = SFTK_SlotInit(paramStrings.configdir,
   5089                            paramStrings.updatedir, paramStrings.updateID,
   5090                            &paramStrings.tokens[0], moduleIndex);
   5091    }
   5092 
   5093 loser:
   5094    sftk_freeParams(&paramStrings);
   5095    sftk_FreeAttribute(attribute);
   5096 
   5097    return crv;
   5098 }
   5099 
   5100 /* NSC_CreateObject creates a new object. */
   5101 CK_RV
   5102 NSC_CreateObject(CK_SESSION_HANDLE hSession,
   5103                 CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount,
   5104                 CK_OBJECT_HANDLE_PTR phObject)
   5105 {
   5106    SFTKSlot *slot = sftk_SlotFromSessionHandle(hSession);
   5107    SFTKSession *session;
   5108    SFTKObject *object;
   5109    /* make sure class isn't randomly CKO_NSS_NEWSLOT or
   5110     * CKO_NETSCPE_DELSLOT. */
   5111    CK_OBJECT_CLASS class = CKO_VENDOR_DEFINED;
   5112    CK_RV crv;
   5113    int i;
   5114 
   5115    CHECK_FORK();
   5116 
   5117    *phObject = CK_INVALID_HANDLE;
   5118 
   5119    if (slot == NULL) {
   5120        return CKR_SESSION_HANDLE_INVALID;
   5121    }
   5122    /*
   5123     * now lets create an object to hang the attributes off of
   5124     */
   5125    object = sftk_NewObject(slot); /* fill in the handle later */
   5126    if (object == NULL) {
   5127        return CKR_HOST_MEMORY;
   5128    }
   5129 
   5130    /*
   5131     * sftk_NewObject will set object->validation_value to
   5132     * SFTK_VALIDATION_FIPS_FLAG if the slot is FIPS.
   5133     * We don't need to worry about that here, as FC_CreateObject will always
   5134     * disallow the import of secret and private keys, regardless of isFIPS
   5135     * approval status. Therefore, at this point we know that the key is a
   5136     * public key, which is acceptable to be imported in plaintext.
   5137     */
   5138 
   5139    /*
   5140     * load the template values into the object
   5141     */
   5142    for (i = 0; i < (int)ulCount; i++) {
   5143        crv = sftk_AddAttributeType(object, sftk_attr_expand(&pTemplate[i]));
   5144        if (crv != CKR_OK) {
   5145            sftk_FreeObject(object);
   5146            return crv;
   5147        }
   5148        if ((pTemplate[i].type == CKA_CLASS) && pTemplate[i].pValue) {
   5149            class = *(CK_OBJECT_CLASS *)pTemplate[i].pValue;
   5150        }
   5151    }
   5152 
   5153    /* get the session */
   5154    session = sftk_SessionFromHandle(hSession);
   5155    if (session == NULL) {
   5156        sftk_FreeObject(object);
   5157        return CKR_SESSION_HANDLE_INVALID;
   5158    }
   5159 
   5160    /*
   5161     * handle pseudo objects (CKO_NEWSLOT)
   5162     */
   5163    if ((class == CKO_NSS_NEWSLOT) || (class == CKO_NSS_DELSLOT)) {
   5164        crv = sftk_CreateNewSlot(slot, class, object);
   5165        goto done;
   5166    }
   5167 
   5168    /*
   5169     * handle the base object stuff
   5170     */
   5171    crv = sftk_handleObject(object, session);
   5172    *phObject = object->handle;
   5173 done:
   5174    sftk_FreeSession(session);
   5175    sftk_FreeObject(object);
   5176 
   5177    return crv;
   5178 }
   5179 
   5180 /* NSC_CopyObject copies an object, creating a new object for the copy. */
   5181 CK_RV
   5182 NSC_CopyObject(CK_SESSION_HANDLE hSession,
   5183               CK_OBJECT_HANDLE hObject, CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount,
   5184               CK_OBJECT_HANDLE_PTR phNewObject)
   5185 {
   5186    SFTKObject *destObject, *srcObject;
   5187    SFTKSession *session;
   5188    CK_RV crv = CKR_OK;
   5189    SFTKSlot *slot = sftk_SlotFromSessionHandle(hSession);
   5190    int i;
   5191 
   5192    CHECK_FORK();
   5193 
   5194    if (slot == NULL) {
   5195        return CKR_SESSION_HANDLE_INVALID;
   5196    }
   5197    /* Get srcObject so we can find the class */
   5198    session = sftk_SessionFromHandle(hSession);
   5199    if (session == NULL) {
   5200        return CKR_SESSION_HANDLE_INVALID;
   5201    }
   5202    srcObject = sftk_ObjectFromHandle(hObject, session);
   5203    if (srcObject == NULL) {
   5204        sftk_FreeSession(session);
   5205        return CKR_OBJECT_HANDLE_INVALID;
   5206    }
   5207    /*
   5208     * create an object to hang the attributes off of
   5209     */
   5210    destObject = sftk_NewObject(slot); /* fill in the handle later */
   5211    if (destObject == NULL) {
   5212        sftk_FreeSession(session);
   5213        sftk_FreeObject(srcObject);
   5214        return CKR_HOST_MEMORY;
   5215    }
   5216 
   5217    /*
   5218     * load the template values into the object
   5219     */
   5220    for (i = 0; i < (int)ulCount; i++) {
   5221        if (sftk_modifyType(pTemplate[i].type, srcObject->objclass) == SFTK_NEVER) {
   5222            crv = CKR_ATTRIBUTE_READ_ONLY;
   5223            break;
   5224        }
   5225        crv = sftk_AddAttributeType(destObject, sftk_attr_expand(&pTemplate[i]));
   5226        if (crv != CKR_OK) {
   5227            break;
   5228        }
   5229    }
   5230    if (crv != CKR_OK) {
   5231        sftk_FreeSession(session);
   5232        sftk_FreeObject(srcObject);
   5233        sftk_FreeObject(destObject);
   5234        return crv;
   5235    }
   5236 
   5237    /* sensitive can only be changed to CK_TRUE */
   5238    if (sftk_hasAttribute(destObject, CKA_SENSITIVE)) {
   5239        if (!sftk_isTrue(destObject, CKA_SENSITIVE)) {
   5240            sftk_FreeSession(session);
   5241            sftk_FreeObject(srcObject);
   5242            sftk_FreeObject(destObject);
   5243            return CKR_ATTRIBUTE_READ_ONLY;
   5244        }
   5245    }
   5246 
   5247    /*
   5248     * now copy the old attributes from the new attributes
   5249     */
   5250    /* don't create a token object if we aren't in a rw session */
   5251    /* we need to hold the lock to copy a consistant version of
   5252     * the object. */
   5253    crv = sftk_CopyObject(destObject, srcObject);
   5254 
   5255    destObject->objclass = srcObject->objclass;
   5256    sftk_FreeObject(srcObject);
   5257    if (crv != CKR_OK) {
   5258        sftk_FreeObject(destObject);
   5259        sftk_FreeSession(session);
   5260        return crv;
   5261    }
   5262 
   5263    crv = sftk_handleObject(destObject, session);
   5264    *phNewObject = destObject->handle;
   5265    sftk_FreeSession(session);
   5266    sftk_FreeObject(destObject);
   5267 
   5268    return crv;
   5269 }
   5270 
   5271 /* NSC_GetObjectSize gets the size of an object in bytes. */
   5272 CK_RV
   5273 NSC_GetObjectSize(CK_SESSION_HANDLE hSession,
   5274                  CK_OBJECT_HANDLE hObject, CK_ULONG_PTR pulSize)
   5275 {
   5276    CHECK_FORK();
   5277 
   5278    *pulSize = 0;
   5279    return CKR_OK;
   5280 }
   5281 
   5282 static CK_RV
   5283 nsc_GetTokenAttributeValue(SFTKSession *session, CK_OBJECT_HANDLE hObject,
   5284                           CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount)
   5285 {
   5286    SFTKSlot *slot = sftk_SlotFromSession(session);
   5287    SFTKDBHandle *dbHandle = sftk_getDBForTokenObject(slot, hObject);
   5288    SFTKDBHandle *keydb = NULL;
   5289    CK_RV crv;
   5290 
   5291    if (dbHandle == NULL) {
   5292        return CKR_OBJECT_HANDLE_INVALID;
   5293    }
   5294 
   5295    crv = sftkdb_GetAttributeValue(dbHandle, hObject, pTemplate, ulCount);
   5296 
   5297    /* make sure we don't export any sensitive information */
   5298    keydb = sftk_getKeyDB(slot);
   5299    if (dbHandle == keydb) {
   5300        CK_ULONG i;
   5301        for (i = 0; i < ulCount; i++) {
   5302            if (sftk_isSensitive(pTemplate[i].type, CKO_PRIVATE_KEY)) {
   5303                crv = CKR_ATTRIBUTE_SENSITIVE;
   5304                if (pTemplate[i].pValue && (pTemplate[i].ulValueLen != -1)) {
   5305                    PORT_Memset(pTemplate[i].pValue, 0,
   5306                                pTemplate[i].ulValueLen);
   5307                }
   5308                pTemplate[i].ulValueLen = -1;
   5309            }
   5310        }
   5311    }
   5312 
   5313    sftk_freeDB(dbHandle);
   5314    if (keydb) {
   5315        sftk_freeDB(keydb);
   5316    }
   5317    return crv;
   5318 }
   5319 
   5320 PRBool
   5321 sftk_template_hasAttribute(CK_ATTRIBUTE_TYPE type, CK_ATTRIBUTE *pTemplate,
   5322                           CK_ULONG ulCount)
   5323 {
   5324    for (int i = 0; i < ulCount; i++) {
   5325        if (pTemplate[i].type == type) {
   5326            return PR_TRUE;
   5327        }
   5328    }
   5329    return PR_FALSE;
   5330 }
   5331 
   5332 /* NSC_GetAttributeValue obtains the value of one or more object attributes. */
   5333 CK_RV
   5334 NSC_GetAttributeValue(CK_SESSION_HANDLE hSession,
   5335                      CK_OBJECT_HANDLE hObject, CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount)
   5336 {
   5337    SFTKSlot *slot = sftk_SlotFromSessionHandle(hSession);
   5338    SFTKSession *session;
   5339    SFTKObject *object;
   5340    SFTKAttribute *attribute;
   5341    PRBool sensitive, isLoggedIn, needLogin;
   5342    CK_RV crv;
   5343    int i;
   5344 
   5345    CHECK_FORK();
   5346 
   5347    if (slot == NULL) {
   5348        return CKR_SESSION_HANDLE_INVALID;
   5349    }
   5350    /*
   5351     * make sure we're allowed
   5352     */
   5353    session = sftk_SessionFromHandle(hSession);
   5354    if (session == NULL) {
   5355        return CKR_SESSION_HANDLE_INVALID;
   5356    }
   5357 
   5358    /* short circuit everything for token objects */
   5359    if (sftk_isToken(hObject) &&
   5360        /* we we have a CKA_OBJECT_VALIDATION_FLAG, don't do the
   5361         * short circuit. the SDB code doesn't know how to process
   5362         * this attribute */
   5363        !sftk_template_hasAttribute(CKA_OBJECT_VALIDATION_FLAGS, pTemplate,
   5364                                    ulCount)) {
   5365        crv = nsc_GetTokenAttributeValue(session, hObject, pTemplate, ulCount);
   5366        sftk_FreeSession(session);
   5367        return crv;
   5368    }
   5369 
   5370    /* handle the session object */
   5371    object = sftk_ObjectFromHandle(hObject, session);
   5372    sftk_FreeSession(session);
   5373    if (object == NULL) {
   5374        return CKR_OBJECT_HANDLE_INVALID;
   5375    }
   5376 
   5377    PZ_Lock(slot->slotLock);
   5378    isLoggedIn = slot->isLoggedIn;
   5379    needLogin = slot->needLogin;
   5380    PZ_Unlock(slot->slotLock);
   5381 
   5382    /* don't read a private object if we aren't logged in */
   5383    if (!isLoggedIn && needLogin && sftk_isTrue(object, CKA_PRIVATE)) {
   5384        sftk_FreeObject(object);
   5385        return CKR_USER_NOT_LOGGED_IN;
   5386    }
   5387 
   5388    crv = CKR_OK;
   5389    sensitive = sftk_isTrue(object, CKA_SENSITIVE);
   5390    for (i = 0; i < (int)ulCount; i++) {
   5391        /* Make sure that this attribute is retrievable */
   5392        if (sensitive && sftk_isSensitive(pTemplate[i].type, object->objclass)) {
   5393            crv = CKR_ATTRIBUTE_SENSITIVE;
   5394            pTemplate[i].ulValueLen = -1;
   5395            continue;
   5396        }
   5397        attribute = sftk_FindAttribute(object, pTemplate[i].type);
   5398        if (attribute == NULL) {
   5399            crv = CKR_ATTRIBUTE_TYPE_INVALID;
   5400            pTemplate[i].ulValueLen = -1;
   5401            continue;
   5402        }
   5403        if (pTemplate[i].pValue != NULL) {
   5404            PORT_Memcpy(pTemplate[i].pValue, attribute->attrib.pValue,
   5405                        attribute->attrib.ulValueLen);
   5406        }
   5407        pTemplate[i].ulValueLen = attribute->attrib.ulValueLen;
   5408        sftk_FreeAttribute(attribute);
   5409    }
   5410 
   5411    sftk_FreeObject(object);
   5412    return crv;
   5413 }
   5414 
   5415 /* NSC_SetAttributeValue modifies the value of one or more object attributes */
   5416 CK_RV
   5417 NSC_SetAttributeValue(CK_SESSION_HANDLE hSession,
   5418                      CK_OBJECT_HANDLE hObject, CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount)
   5419 {
   5420    SFTKSlot *slot = sftk_SlotFromSessionHandle(hSession);
   5421    SFTKSession *session;
   5422    SFTKAttribute *attribute;
   5423    SFTKObject *object;
   5424    PRBool isToken, isLoggedIn, needLogin;
   5425    CK_RV crv = CKR_OK;
   5426    CK_BBOOL legal;
   5427    int i;
   5428 
   5429    CHECK_FORK();
   5430 
   5431    if (slot == NULL) {
   5432        return CKR_SESSION_HANDLE_INVALID;
   5433    }
   5434    /*
   5435     * make sure we're allowed
   5436     */
   5437    session = sftk_SessionFromHandle(hSession);
   5438    if (session == NULL) {
   5439        return CKR_SESSION_HANDLE_INVALID;
   5440    }
   5441 
   5442    object = sftk_ObjectFromHandle(hObject, session);
   5443    if (object == NULL) {
   5444        sftk_FreeSession(session);
   5445        return CKR_OBJECT_HANDLE_INVALID;
   5446    }
   5447 
   5448    PZ_Lock(slot->slotLock);
   5449    isLoggedIn = slot->isLoggedIn;
   5450    needLogin = slot->needLogin;
   5451    PZ_Unlock(slot->slotLock);
   5452 
   5453    /* don't modify a private object if we aren't logged in */
   5454    if (!isLoggedIn && needLogin && sftk_isTrue(object, CKA_PRIVATE)) {
   5455        sftk_FreeSession(session);
   5456        sftk_FreeObject(object);
   5457        return CKR_USER_NOT_LOGGED_IN;
   5458    }
   5459 
   5460    /* don't modify a token object if we aren't in a rw session */
   5461    isToken = sftk_isTrue(object, CKA_TOKEN);
   5462    if (((session->info.flags & CKF_RW_SESSION) == 0) && isToken) {
   5463        sftk_FreeSession(session);
   5464        sftk_FreeObject(object);
   5465        return CKR_SESSION_READ_ONLY;
   5466    }
   5467    sftk_FreeSession(session);
   5468 
   5469    /* only change modifiable objects */
   5470    if (!sftk_isTrue(object, CKA_MODIFIABLE)) {
   5471        sftk_FreeObject(object);
   5472        return CKR_ATTRIBUTE_READ_ONLY;
   5473    }
   5474 
   5475    for (i = 0; i < (int)ulCount; i++) {
   5476        /* Make sure that this attribute is changeable */
   5477        switch (sftk_modifyType(pTemplate[i].type, object->objclass)) {
   5478            case SFTK_NEVER:
   5479            case SFTK_ONCOPY:
   5480            default:
   5481                crv = CKR_ATTRIBUTE_READ_ONLY;
   5482                break;
   5483 
   5484            case SFTK_SENSITIVE:
   5485                legal = (pTemplate[i].type == CKA_EXTRACTABLE) ? CK_FALSE : CK_TRUE;
   5486                if ((*(CK_BBOOL *)pTemplate[i].pValue) != legal) {
   5487                    crv = CKR_ATTRIBUTE_READ_ONLY;
   5488                }
   5489                break;
   5490            case SFTK_ALWAYS:
   5491                break;
   5492        }
   5493        if (crv != CKR_OK)
   5494            break;
   5495 
   5496        /* find the old attribute */
   5497        attribute = sftk_FindAttribute(object, pTemplate[i].type);
   5498        if (attribute == NULL) {
   5499            crv = CKR_ATTRIBUTE_TYPE_INVALID;
   5500            break;
   5501        }
   5502        sftk_FreeAttribute(attribute);
   5503        crv = sftk_forceAttribute(object, sftk_attr_expand(&pTemplate[i]));
   5504        if (crv != CKR_OK)
   5505            break;
   5506    }
   5507 
   5508    sftk_FreeObject(object);
   5509    return crv;
   5510 }
   5511 
   5512 static CK_RV
   5513 sftk_expandSearchList(SFTKSearchResults *search, int count)
   5514 {
   5515    search->array_size += count;
   5516    search->handles = (CK_OBJECT_HANDLE *)PORT_Realloc(search->handles,
   5517                                                       sizeof(CK_OBJECT_HANDLE) * search->array_size);
   5518    return search->handles ? CKR_OK : CKR_HOST_MEMORY;
   5519 }
   5520 
   5521 static CK_RV
   5522 sftk_searchDatabase(SFTKDBHandle *handle, SFTKSearchResults *search,
   5523                    const CK_ATTRIBUTE *pTemplate, CK_ULONG ulCount)
   5524 {
   5525    CK_RV crv;
   5526    int objectListSize = search->array_size - search->size;
   5527    CK_OBJECT_HANDLE *array = &search->handles[search->size];
   5528    SDBFind *find = NULL;
   5529    CK_ULONG count;
   5530 
   5531    crv = sftkdb_FindObjectsInit(handle, pTemplate, ulCount, &find);
   5532    if (crv != CKR_OK)
   5533        return crv;
   5534    do {
   5535        crv = sftkdb_FindObjects(handle, find, array, objectListSize, &count);
   5536        if ((crv != CKR_OK) || (count == 0))
   5537            break;
   5538        search->size += count;
   5539        objectListSize -= count;
   5540        if (objectListSize > 0)
   5541            break;
   5542        crv = sftk_expandSearchList(search, NSC_SEARCH_BLOCK_SIZE);
   5543        objectListSize = NSC_SEARCH_BLOCK_SIZE;
   5544        array = &search->handles[search->size];
   5545    } while (crv == CKR_OK);
   5546    sftkdb_FindObjectsFinal(handle, find);
   5547 
   5548    return crv;
   5549 }
   5550 
   5551 /* softoken used to search the SMimeEntries automatically instead of
   5552 * doing this in pk11wrap. This code should really be up in
   5553 * pk11wrap so that it will work with other tokens other than softoken.
   5554 */
   5555 CK_RV
   5556 sftk_emailhack(SFTKSlot *slot, SFTKDBHandle *handle,
   5557               SFTKSearchResults *search, CK_ATTRIBUTE *pTemplate, CK_ULONG ulCount)
   5558 {
   5559    PRBool isCert = PR_FALSE;
   5560    int emailIndex = -1;
   5561    unsigned int i;
   5562    SFTKSearchResults smime_search;
   5563    CK_ATTRIBUTE smime_template[2];
   5564    CK_OBJECT_CLASS smime_class = CKO_NSS_SMIME;
   5565    SFTKAttribute *attribute = NULL;
   5566    SFTKObject *object = NULL;
   5567    CK_RV crv = CKR_OK;
   5568 
   5569    smime_search.handles = NULL; /* paranoia, some one is bound to add a goto
   5570                                  * loser before this gets initialized */
   5571 
   5572    /* see if we are looking for email certs */
   5573    for (i = 0; i < ulCount; i++) {
   5574        if (pTemplate[i].type == CKA_CLASS) {
   5575            if ((pTemplate[i].ulValueLen != sizeof(CK_OBJECT_CLASS) ||
   5576                 (*(CK_OBJECT_CLASS *)pTemplate[i].pValue) != CKO_CERTIFICATE)) {
   5577                /* not a cert, skip out */
   5578                break;
   5579            }
   5580            isCert = PR_TRUE;
   5581        } else if (pTemplate[i].type == CKA_NSS_EMAIL) {
   5582            emailIndex = i;
   5583        }
   5584        if (isCert && (emailIndex != -1))
   5585            break;
   5586    }
   5587 
   5588    if (!isCert || (emailIndex == -1)) {
   5589        return CKR_OK;
   5590    }
   5591 
   5592    /* we are doing a cert and email search, find the SMimeEntry */
   5593    smime_template[0].type = CKA_CLASS;
   5594    smime_template[0].pValue = &smime_class;
   5595    smime_template[0].ulValueLen = sizeof(smime_class);
   5596    smime_template[1] = pTemplate[emailIndex];
   5597 
   5598    smime_search.handles = (CK_OBJECT_HANDLE *)
   5599        PORT_Alloc(sizeof(CK_OBJECT_HANDLE) * NSC_SEARCH_BLOCK_SIZE);
   5600    if (smime_search.handles == NULL) {
   5601        crv = CKR_HOST_MEMORY;
   5602        goto loser;
   5603    }
   5604    smime_search.index = 0;
   5605    smime_search.size = 0;
   5606    smime_search.array_size = NSC_SEARCH_BLOCK_SIZE;
   5607 
   5608    crv = sftk_searchDatabase(handle, &smime_search, smime_template, 2);
   5609    if (crv != CKR_OK || smime_search.size == 0) {
   5610        goto loser;
   5611    }
   5612 
   5613    /* get the SMime subject */
   5614    object = sftk_NewTokenObject(slot, NULL, smime_search.handles[0]);
   5615    if (object == NULL) {
   5616        crv = CKR_HOST_MEMORY; /* is there any other reason for this failure? */
   5617        goto loser;
   5618    }
   5619    attribute = sftk_FindAttribute(object, CKA_SUBJECT);
   5620    if (attribute == NULL) {
   5621        crv = CKR_ATTRIBUTE_TYPE_INVALID;
   5622        goto loser;
   5623    }
   5624 
   5625    /* now find the certs with that subject */
   5626    pTemplate[emailIndex] = attribute->attrib;
   5627    /* now add the appropriate certs to the search list */
   5628    crv = sftk_searchDatabase(handle, search, pTemplate, ulCount);
   5629    pTemplate[emailIndex] = smime_template[1]; /* restore the user's template*/
   5630 
   5631 loser:
   5632    if (attribute) {
   5633        sftk_FreeAttribute(attribute);
   5634    }
   5635    if (object) {
   5636        sftk_FreeObject(object);
   5637    }
   5638    if (smime_search.handles) {
   5639        PORT_Free(smime_search.handles);
   5640    }
   5641 
   5642    return crv;
   5643 }
   5644 
   5645 static void
   5646 sftk_pruneSearch(CK_ATTRIBUTE *pTemplate, CK_ULONG ulCount,
   5647                 PRBool *searchCertDB, PRBool *searchKeyDB)
   5648 {
   5649    CK_ULONG i;
   5650 
   5651    *searchCertDB = PR_TRUE;
   5652    *searchKeyDB = PR_TRUE;
   5653    for (i = 0; i < ulCount; i++) {
   5654        if (pTemplate[i].type == CKA_CLASS && pTemplate[i].pValue != NULL) {
   5655            CK_OBJECT_CLASS class = *((CK_OBJECT_CLASS *)pTemplate[i].pValue);
   5656            if (class == CKO_PRIVATE_KEY || class == CKO_SECRET_KEY) {
   5657                *searchCertDB = PR_FALSE;
   5658            } else {
   5659                *searchKeyDB = PR_FALSE;
   5660            }
   5661            break;
   5662        }
   5663    }
   5664 }
   5665 
   5666 static CK_RV
   5667 sftk_searchTokenList(SFTKSlot *slot, SFTKSearchResults *search,
   5668                     CK_ATTRIBUTE *pTemplate, CK_ULONG ulCount,
   5669                     PRBool isLoggedIn)
   5670 {
   5671    CK_RV crv = CKR_OK;
   5672    CK_RV crv2;
   5673    PRBool searchCertDB;
   5674    PRBool searchKeyDB;
   5675 
   5676    sftk_pruneSearch(pTemplate, ulCount, &searchCertDB, &searchKeyDB);
   5677 
   5678    if (searchCertDB) {
   5679        SFTKDBHandle *certHandle = sftk_getCertDB(slot);
   5680        crv = sftk_searchDatabase(certHandle, search, pTemplate, ulCount);
   5681        crv2 = sftk_emailhack(slot, certHandle, search, pTemplate, ulCount);
   5682        if (crv == CKR_OK)
   5683            crv = crv2;
   5684        sftk_freeDB(certHandle);
   5685    }
   5686 
   5687    if (crv == CKR_OK && isLoggedIn && searchKeyDB) {
   5688        SFTKDBHandle *keyHandle = sftk_getKeyDB(slot);
   5689        crv = sftk_searchDatabase(keyHandle, search, pTemplate, ulCount);
   5690        sftk_freeDB(keyHandle);
   5691    }
   5692    return crv;
   5693 }
   5694 
   5695 /* NSC_FindObjectsInit initializes a search for token and session objects
   5696 * that match a template. */
   5697 CK_RV
   5698 NSC_FindObjectsInit(CK_SESSION_HANDLE hSession,
   5699                    CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount)
   5700 {
   5701    SFTKSearchResults *search = NULL, *freeSearch = NULL;
   5702    SFTKSession *session = NULL;
   5703    SFTKSlot *slot = sftk_SlotFromSessionHandle(hSession);
   5704    CK_RV crv = CKR_OK;
   5705    PRBool isLoggedIn;
   5706 
   5707    CHECK_FORK();
   5708 
   5709    if (slot == NULL) {
   5710        return CKR_SESSION_HANDLE_INVALID;
   5711    }
   5712    session = sftk_SessionFromHandle(hSession);
   5713    if (session == NULL) {
   5714        crv = CKR_SESSION_HANDLE_INVALID;
   5715        goto loser;
   5716    }
   5717 
   5718    search = (SFTKSearchResults *)PORT_Alloc(sizeof(SFTKSearchResults));
   5719    if (search == NULL) {
   5720        crv = CKR_HOST_MEMORY;
   5721        goto loser;
   5722    }
   5723    search->handles = (CK_OBJECT_HANDLE *)
   5724        PORT_Alloc(sizeof(CK_OBJECT_HANDLE) * NSC_SEARCH_BLOCK_SIZE);
   5725    if (search->handles == NULL) {
   5726        crv = CKR_HOST_MEMORY;
   5727        goto loser;
   5728    }
   5729    search->index = 0;
   5730    search->size = 0;
   5731    search->array_size = NSC_SEARCH_BLOCK_SIZE;
   5732 
   5733    PZ_Lock(slot->slotLock);
   5734    isLoggedIn = (PRBool)((!slot->needLogin) || slot->isLoggedIn);
   5735    PZ_Unlock(slot->slotLock);
   5736 
   5737    PRBool validTokenAttribute = PR_FALSE;
   5738    PRBool tokenAttributeValue = PR_FALSE;
   5739    for (CK_ULONG i = 0; i < ulCount; i++) {
   5740        CK_ATTRIBUTE_PTR attr = &pTemplate[i];
   5741        if (attr->type == CKA_TOKEN && attr->pValue && attr->ulValueLen == sizeof(CK_BBOOL)) {
   5742            if (*(CK_BBOOL *)attr->pValue == CK_TRUE) {
   5743                validTokenAttribute = PR_TRUE;
   5744                tokenAttributeValue = PR_TRUE;
   5745            } else if (*(CK_BBOOL *)attr->pValue == CK_FALSE) {
   5746                validTokenAttribute = PR_TRUE;
   5747                tokenAttributeValue = PR_FALSE;
   5748            }
   5749            break;
   5750        }
   5751    }
   5752 
   5753    // Search over the token object list if the template's CKA_TOKEN attribute is set to
   5754    // CK_TRUE or if it is not set.
   5755    if (validTokenAttribute == PR_FALSE || tokenAttributeValue == PR_TRUE) {
   5756        crv = sftk_searchTokenList(slot, search, pTemplate, ulCount, isLoggedIn);
   5757        if (crv != CKR_OK) {
   5758            goto loser;
   5759        }
   5760    }
   5761 
   5762    // Search over the session object list if the template's CKA_TOKEN attribute is set to
   5763    // CK_FALSE or if it is not set.
   5764    if (validTokenAttribute == PR_FALSE || tokenAttributeValue == PR_FALSE) {
   5765        crv = sftk_searchObjectList(search, slot->sessObjHashTable,
   5766                                    slot->sessObjHashSize, slot->objectLock,
   5767                                    pTemplate, ulCount, isLoggedIn);
   5768        if (crv != CKR_OK) {
   5769            goto loser;
   5770        }
   5771    }
   5772 
   5773    if ((freeSearch = session->search) != NULL) {
   5774        session->search = NULL;
   5775        sftk_FreeSearch(freeSearch);
   5776    }
   5777    session->search = search;
   5778    sftk_FreeSession(session);
   5779    return CKR_OK;
   5780 
   5781 loser:
   5782    if (search) {
   5783        sftk_FreeSearch(search);
   5784    }
   5785    if (session) {
   5786        sftk_FreeSession(session);
   5787    }
   5788    return crv;
   5789 }
   5790 
   5791 /* NSC_FindObjects continues a search for token and session objects
   5792 * that match a template, obtaining additional object handles. */
   5793 CK_RV
   5794 NSC_FindObjects(CK_SESSION_HANDLE hSession,
   5795                CK_OBJECT_HANDLE_PTR phObject, CK_ULONG ulMaxObjectCount,
   5796                CK_ULONG_PTR pulObjectCount)
   5797 {
   5798    SFTKSession *session;
   5799    SFTKSearchResults *search;
   5800    int transfer;
   5801    int left;
   5802 
   5803    CHECK_FORK();
   5804 
   5805    *pulObjectCount = 0;
   5806    session = sftk_SessionFromHandle(hSession);
   5807    if (session == NULL)
   5808        return CKR_SESSION_HANDLE_INVALID;
   5809    if (session->search == NULL) {
   5810        sftk_FreeSession(session);
   5811        return CKR_OK;
   5812    }
   5813    search = session->search;
   5814    left = session->search->size - session->search->index;
   5815    transfer = ((int)ulMaxObjectCount > left) ? left : ulMaxObjectCount;
   5816    if (transfer > 0) {
   5817        PORT_Memcpy(phObject, &search->handles[search->index],
   5818                    transfer * sizeof(CK_OBJECT_HANDLE));
   5819    } else {
   5820        *phObject = CK_INVALID_HANDLE;
   5821    }
   5822 
   5823    search->index += transfer;
   5824    if (search->index == search->size) {
   5825        session->search = NULL;
   5826        sftk_FreeSearch(search);
   5827    }
   5828    *pulObjectCount = transfer;
   5829    sftk_FreeSession(session);
   5830    return CKR_OK;
   5831 }
   5832 
   5833 /* NSC_FindObjectsFinal finishes a search for token and session objects. */
   5834 CK_RV
   5835 NSC_FindObjectsFinal(CK_SESSION_HANDLE hSession)
   5836 {
   5837    SFTKSession *session;
   5838    SFTKSearchResults *search;
   5839 
   5840    CHECK_FORK();
   5841 
   5842    session = sftk_SessionFromHandle(hSession);
   5843    if (session == NULL)
   5844        return CKR_SESSION_HANDLE_INVALID;
   5845    search = session->search;
   5846    session->search = NULL;
   5847    sftk_FreeSession(session);
   5848    if (search != NULL) {
   5849        sftk_FreeSearch(search);
   5850    }
   5851    return CKR_OK;
   5852 }
   5853 
   5854 CK_RV
   5855 NSC_WaitForSlotEvent(CK_FLAGS flags, CK_SLOT_ID_PTR pSlot,
   5856                     CK_VOID_PTR pReserved)
   5857 {
   5858    CHECK_FORK();
   5859 
   5860    return CKR_FUNCTION_NOT_SUPPORTED;
   5861 }
   5862 
   5863 CK_RV
   5864 NSC_AsyncComplete(CK_SESSION_HANDLE hSession, CK_UTF8CHAR_PTR pFunctionName,
   5865                  CK_ASYNC_DATA_PTR pResult)
   5866 {
   5867    CHECK_FORK();
   5868 
   5869    return CKR_FUNCTION_NOT_SUPPORTED;
   5870 }
   5871 
   5872 CK_RV
   5873 NSC_AsyncGetID(CK_SESSION_HANDLE hSession, CK_UTF8CHAR_PTR pFunctionName,
   5874               CK_ULONG_PTR pulID)
   5875 {
   5876    CHECK_FORK();
   5877 
   5878    return CKR_FUNCTION_NOT_SUPPORTED;
   5879 }
   5880 
   5881 CK_RV
   5882 NSC_AsyncJoin(CK_SESSION_HANDLE hSession, CK_UTF8CHAR_PTR pFunctionName,
   5883              CK_ULONG ulID, CK_BYTE_PTR pData, CK_ULONG ulData)
   5884 {
   5885    CHECK_FORK();
   5886 
   5887    return CKR_FUNCTION_NOT_SUPPORTED;
   5888 }
   5889 
   5890 static CK_RV
   5891 nsc_NSSGetFIPSStatus(CK_SESSION_HANDLE hSession,
   5892                     CK_OBJECT_HANDLE hObject,
   5893                     CK_ULONG ulOperationType,
   5894                     CK_ULONG *pulFIPSStatus)
   5895 {
   5896    CK_ULONG sessionState = CKS_NSS_UNINITIALIZED;
   5897    CK_ULONG objectState = CKS_NSS_UNINITIALIZED;
   5898    PRBool needSession = PR_FALSE;
   5899    PRBool needObject = PR_FALSE;
   5900    SFTKSession *session;
   5901    SFTKObject *object;
   5902 
   5903    *pulFIPSStatus = CKS_NSS_FIPS_NOT_OK;
   5904 
   5905    /* first determine what we need to look up */
   5906    switch (ulOperationType) {
   5907        case CKT_NSS_SESSION_CHECK:
   5908        case CKT_NSS_SESSION_LAST_CHECK:
   5909            needSession = PR_TRUE;
   5910            needObject = PR_FALSE;
   5911            break;
   5912        case CKT_NSS_OBJECT_CHECK:
   5913            needSession = PR_FALSE;
   5914            needObject = PR_TRUE;
   5915            break;
   5916        case CKT_NSS_BOTH_CHECK:
   5917            needSession = PR_TRUE;
   5918            needObject = PR_TRUE;
   5919            break;
   5920        default:
   5921            return CKR_ARGUMENTS_BAD;
   5922    }
   5923 
   5924    /* we always need the session handle, the object handle is only
   5925     * meaningful if there is a session */
   5926    session = sftk_SessionFromHandle(hSession);
   5927    if (!session) {
   5928        return CKR_SESSION_HANDLE_INVALID;
   5929    }
   5930    if (needSession) {
   5931        if (CKT_NSS_SESSION_LAST_CHECK == ulOperationType) {
   5932            sessionState = session->lastOpWasFIPS ? CKS_NSS_FIPS_OK : CKS_NSS_FIPS_NOT_OK;
   5933        } else {
   5934            if (session->enc_context) {
   5935                sessionState = session->enc_context->isFIPS ? CKS_NSS_FIPS_OK : CKS_NSS_FIPS_NOT_OK;
   5936            }
   5937            if (sessionState != CKS_NSS_FIPS_NOT_OK && session->hash_context) {
   5938                sessionState = session->hash_context->isFIPS ? CKS_NSS_FIPS_OK : CKS_NSS_FIPS_NOT_OK;
   5939            }
   5940            /* sessionState is set to CKS_NSS_UNINITIALIZED if neither
   5941             * context exists */
   5942        }
   5943    }
   5944 
   5945    if (needObject) {
   5946        object = sftk_ObjectFromHandle(hObject, session);
   5947        if (!object) {
   5948            sftk_FreeSession(session);
   5949            return CKR_OBJECT_HANDLE_INVALID;
   5950        }
   5951        objectState = sftk_hasFIPS(object) ? CKS_NSS_FIPS_OK : CKS_NSS_FIPS_NOT_OK;
   5952        sftk_FreeObject(object);
   5953    }
   5954 
   5955    sftk_FreeSession(session);
   5956 
   5957    /* If we didn't fetch the state, then it is uninitialized.
   5958     * The session state can also be uninitialized if there are no active
   5959     * crypto operations on the session. Turns out the rules for combining
   5960     * the states are the same whether or not the state was uninitialzed
   5961     * because we didn't fetch it or because there wasn't a state to fetch.
   5962     */
   5963 
   5964    /* if the object State is uninitialized, return the state of the session. */
   5965    if (objectState == CKS_NSS_UNINITIALIZED) {
   5966        /* if they are both uninitalized, return CKS_FIPS_NOT_OK */
   5967        if (sessionState == CKS_NSS_UNINITIALIZED) {
   5968            /* *pulFIPSStatus already set to CKS_FIPS_NOT_OK */
   5969            return CKR_OK;
   5970        }
   5971        *pulFIPSStatus = sessionState;
   5972        return CKR_OK;
   5973    }
   5974    /* objectState is initialized, if sessionState is uninitialized, we can
   5975     * just return objectState */
   5976    if (sessionState == CKS_NSS_UNINITIALIZED) {
   5977        *pulFIPSStatus = objectState;
   5978        return CKR_OK;
   5979    }
   5980 
   5981    /* they are are not equal, one must be CKS_FIPS_NOT_OK, so we return that
   5982     * value CKS_FIPS_NOT_OK */
   5983    if (objectState != sessionState) {
   5984        /* *pulFIPSStatus already set to CKS_FIPS_NOT_OK */
   5985        return CKR_OK;
   5986    }
   5987 
   5988    /* objectState and sessionState or the same, so we can return either */
   5989    *pulFIPSStatus = sessionState;
   5990    return CKR_OK;
   5991 }
   5992 
   5993 CK_RV
   5994 NSC_GetSessionValidationFlags(CK_SESSION_HANDLE hSession,
   5995                              CK_SESSION_VALIDATION_FLAGS_TYPE type,
   5996                              CK_FLAGS_PTR pFlags)
   5997 {
   5998    CK_RV crv;
   5999    CK_ULONG status = CKS_NSS_UNINITIALIZED;
   6000    CK_ULONG status1 = CKS_NSS_UNINITIALIZED;
   6001 
   6002    *pFlags = 0;
   6003 
   6004    crv = nsc_NSSGetFIPSStatus(hSession, CK_INVALID_HANDLE,
   6005                               CKT_NSS_SESSION_LAST_CHECK, &status);
   6006    if (crv != CKR_OK) {
   6007        return crv;
   6008    }
   6009    crv = nsc_NSSGetFIPSStatus(hSession, CK_INVALID_HANDLE,
   6010                               CKT_NSS_SESSION_CHECK, &status1);
   6011    if (crv != CKR_OK) {
   6012        return crv;
   6013    }
   6014    /* PCKS #11 only defines the last operation. For us this includes
   6015     * things in the CKT_NSS_SESSION_CHECK */
   6016    if ((status == CKS_NSS_FIPS_OK) || (status1 == CKS_NSS_FIPS_OK)) {
   6017        *pFlags = SFTK_VALIDATION_FIPS_FLAG;
   6018    }
   6019    return CKR_OK;
   6020 }