tor-browser

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

pk11pars.c (89534B)


      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 * The following handles the loading, unloading and management of
      6 * various PCKS #11 modules
      7 */
      8 
      9 #include <ctype.h>
     10 #include <assert.h>
     11 #include "pkcs11.h"
     12 #include "seccomon.h"
     13 #include "secmod.h"
     14 #include "secmodi.h"
     15 #include "secmodti.h"
     16 #include "pki3hack.h"
     17 #include "secerr.h"
     18 #include "nss.h"
     19 #include "utilpars.h"
     20 #include "pk11pub.h"
     21 
     22 /* create a new module */
     23 static SECMODModule *
     24 secmod_NewModule(void)
     25 {
     26    SECMODModule *newMod;
     27    PLArenaPool *arena;
     28 
     29    /* create an arena in which dllName and commonName can be
     30     * allocated.
     31     */
     32    arena = PORT_NewArena(512);
     33    if (arena == NULL) {
     34        return NULL;
     35    }
     36 
     37    newMod = (SECMODModule *)PORT_ArenaAlloc(arena, sizeof(SECMODModule));
     38    if (newMod == NULL) {
     39        PORT_FreeArena(arena, PR_FALSE);
     40        return NULL;
     41    }
     42 
     43    /*
     44     * initialize of the fields of the module
     45     */
     46    newMod->arena = arena;
     47    newMod->internal = PR_FALSE;
     48    newMod->loaded = PR_FALSE;
     49    newMod->isFIPS = PR_FALSE;
     50    newMod->dllName = NULL;
     51    newMod->commonName = NULL;
     52    newMod->library = NULL;
     53    newMod->functionList = NULL;
     54    newMod->slotCount = 0;
     55    newMod->slots = NULL;
     56    newMod->slotInfo = NULL;
     57    newMod->slotInfoCount = 0;
     58    newMod->refCount = 1;
     59    newMod->ssl[0] = 0;
     60    newMod->ssl[1] = 0;
     61    newMod->libraryParams = NULL;
     62    newMod->moduleDBFunc = NULL;
     63    newMod->parent = NULL;
     64    newMod->isCritical = PR_FALSE;
     65    newMod->isModuleDB = PR_FALSE;
     66    newMod->moduleDBOnly = PR_FALSE;
     67    newMod->trustOrder = 0;
     68    newMod->cipherOrder = 0;
     69    newMod->evControlMask = 0;
     70    newMod->refLock = PZ_NewLock(nssILockRefLock);
     71    if (newMod->refLock == NULL) {
     72        PORT_FreeArena(arena, PR_FALSE);
     73        return NULL;
     74    }
     75    return newMod;
     76 }
     77 
     78 /* private flags for isModuleDB (field in SECMODModule). */
     79 /* The meaing of these flags is as follows:
     80 *
     81 * SECMOD_FLAG_MODULE_DB_IS_MODULE_DB - This is a module that accesses the
     82 *   database of other modules to load. Module DBs are loadable modules that
     83 *   tells NSS which PKCS #11 modules to load and when. These module DBs are
     84 *   chainable. That is, one module DB can load another one. NSS system init
     85 *   design takes advantage of this feature. In system NSS, a fixed system
     86 *   module DB loads the system defined libraries, then chains out to the
     87 *   traditional module DBs to load any system or user configured modules
     88 *   (like smart cards). This bit is the same as the already existing meaning
     89 *   of  isModuleDB = PR_TRUE. None of the other module db flags should be set
     90 *   if this flag isn't on.
     91 *
     92 * SECMOD_FLAG_MODULE_DB_SKIP_FIRST - This flag tells NSS to skip the first
     93 *   PKCS #11 module presented by a module DB. This allows the OS to load a
     94 *   softoken from the system module, then ask the existing module DB code to
     95 *   load the other PKCS #11 modules in that module DB (skipping it's request
     96 *   to load softoken). This gives the system init finer control over the
     97 *   configuration of that softoken module.
     98 *
     99 * SECMOD_FLAG_MODULE_DB_DEFAULT_MODDB - This flag allows system init to mark a
    100 *   different module DB as the 'default' module DB (the one in which
    101 *   'Add module' changes will go). Without this flag NSS takes the first
    102 *   module as the default Module DB, but in system NSS, that first module
    103 *   is the system module, which is likely read only (at least to the user).
    104 *   This  allows system NSS to delegate those changes to the user's module DB,
    105 *   preserving the user's ability to load new PKCS #11 modules (which only
    106 *   affect him), from existing applications like Firefox.
    107 */
    108 #define SECMOD_FLAG_MODULE_DB_IS_MODULE_DB 0x01 /* must be set if any of the \
    109                                                 *other flags are set */
    110 #define SECMOD_FLAG_MODULE_DB_SKIP_FIRST 0x02
    111 #define SECMOD_FLAG_MODULE_DB_DEFAULT_MODDB 0x04
    112 #define SECMOD_FLAG_MODULE_DB_POLICY_ONLY 0x08
    113 
    114 /* private flags for internal (field in SECMODModule). */
    115 /* The meaing of these flags is as follows:
    116 *
    117 * SECMOD_FLAG_INTERNAL_IS_INTERNAL - This is a marks the the module is
    118 *   the internal module (that is, softoken). This bit is the same as the
    119 *   already existing meaning of internal = PR_TRUE. None of the other
    120 *   internal flags should be set if this flag isn't on.
    121 *
    122 * SECMOD_FLAG_MODULE_INTERNAL_KEY_SLOT - This flag allows system init to mark
    123 *   a  different slot returned byt PK11_GetInternalKeySlot(). The 'primary'
    124 *   slot defined by this module will be the new internal key slot.
    125 */
    126 #define SECMOD_FLAG_INTERNAL_IS_INTERNAL 0x01 /* must be set if any of \
    127                                               *the other flags are set */
    128 #define SECMOD_FLAG_INTERNAL_KEY_SLOT 0x02
    129 
    130 /* private flags for policy check. */
    131 #define SECMOD_FLAG_POLICY_CHECK_IDENTIFIER 0x01
    132 #define SECMOD_FLAG_POLICY_CHECK_VALUE 0x02
    133 
    134 /*
    135 * for 3.4 we continue to use the old SECMODModule structure
    136 */
    137 SECMODModule *
    138 SECMOD_CreateModule(const char *library, const char *moduleName,
    139                    const char *parameters, const char *nss)
    140 {
    141    return SECMOD_CreateModuleEx(library, moduleName, parameters, nss, NULL);
    142 }
    143 
    144 /*
    145 * NSS config options format:
    146 *
    147 * The specified ciphers will be allowed by policy, but an application
    148 * may allow more by policy explicitly:
    149 * config="allow=curve1:curve2:hash1:hash2:rsa-1024..."
    150 *
    151 * Only the specified hashes and curves will be allowed:
    152 * config="disallow=all allow=sha1:sha256:secp256r1:secp384r1"
    153 *
    154 * Only the specified hashes and curves will be allowed, and
    155 *  RSA keys of 2048 or more will be accepted, and DH key exchange
    156 *  with 1024-bit primes or more:
    157 * config="disallow=all allow=sha1:sha256:secp256r1:secp384r1:min-rsa=2048:min-dh=1024"
    158 *
    159 * A policy that enables the AES ciphersuites and the SECP256/384 curves:
    160 * config="allow=aes128-cbc:aes128-gcm:TLS1.0:TLS1.2:TLS1.1:HMAC-SHA1:SHA1:SHA256:SHA384:RSA:ECDHE-RSA:SECP256R1:SECP384R1"
    161 *
    162 * Disallow values are parsed first, then allow values, independent of the
    163 * order they appear.
    164 *
    165 * flags: turn on the following flags:
    166 *    policy-lock: turn off the ability for applications to change policy with
    167 *                 the call NSS_SetAlgorithmPolicy or the other system policy
    168 *                 calls (SSL_SetPolicy, etc.)
    169 *    ssl-lock:    turn off the ability to change the ssl defaults.
    170 *
    171 * The following only apply to ssl cipher suites (future smime)
    172 *
    173 * enable: turn on ciphersuites by default.
    174 * disable: turn off ciphersuites by default without disallowing them by policy.
    175 *
    176 *
    177 */
    178 
    179 typedef struct {
    180    const char *name;
    181    unsigned name_size;
    182    SECOidTag oid;
    183    PRUint32 val;
    184 } oidValDef;
    185 
    186 typedef struct {
    187    const char *name;
    188    unsigned name_size;
    189    PRInt32 option;
    190 } optionFreeDef;
    191 
    192 typedef struct {
    193    const char *name;
    194    unsigned name_size;
    195    PRUint32 flag;
    196 } policyFlagDef;
    197 
    198 /*
    199 *  This table should be merged with the SECOID table.
    200 */
    201 #define CIPHER_NAME(x) x, (sizeof(x) - 1)
    202 static const oidValDef curveOptList[] = {
    203    /* Curves */
    204    { CIPHER_NAME("PRIME192V1"), SEC_OID_ANSIX962_EC_PRIME192V1,
    205      NSS_USE_ALG_IN_SSL_KX | NSS_USE_ALG_IN_CERT_SIGNATURE },
    206    { CIPHER_NAME("PRIME192V2"), SEC_OID_ANSIX962_EC_PRIME192V2,
    207      NSS_USE_ALG_IN_SSL_KX | NSS_USE_ALG_IN_CERT_SIGNATURE },
    208    { CIPHER_NAME("PRIME192V3"), SEC_OID_ANSIX962_EC_PRIME192V3,
    209      NSS_USE_ALG_IN_SSL_KX | NSS_USE_ALG_IN_CERT_SIGNATURE },
    210    { CIPHER_NAME("PRIME239V1"), SEC_OID_ANSIX962_EC_PRIME239V1,
    211      NSS_USE_ALG_IN_SSL_KX | NSS_USE_ALG_IN_CERT_SIGNATURE },
    212    { CIPHER_NAME("PRIME239V2"), SEC_OID_ANSIX962_EC_PRIME239V2,
    213      NSS_USE_ALG_IN_SSL_KX | NSS_USE_ALG_IN_CERT_SIGNATURE },
    214    { CIPHER_NAME("PRIME239V3"), SEC_OID_ANSIX962_EC_PRIME239V3,
    215      NSS_USE_ALG_IN_SSL_KX | NSS_USE_ALG_IN_CERT_SIGNATURE },
    216    { CIPHER_NAME("PRIME256V1"), SEC_OID_ANSIX962_EC_PRIME256V1,
    217      NSS_USE_ALG_IN_SSL_KX | NSS_USE_ALG_IN_CERT_SIGNATURE },
    218    { CIPHER_NAME("SECP112R1"), SEC_OID_SECG_EC_SECP112R1,
    219      NSS_USE_ALG_IN_SSL_KX | NSS_USE_ALG_IN_CERT_SIGNATURE },
    220    { CIPHER_NAME("SECP112R2"), SEC_OID_SECG_EC_SECP112R2,
    221      NSS_USE_ALG_IN_SSL_KX | NSS_USE_ALG_IN_CERT_SIGNATURE },
    222    { CIPHER_NAME("SECP128R1"), SEC_OID_SECG_EC_SECP128R1,
    223      NSS_USE_ALG_IN_SSL_KX | NSS_USE_ALG_IN_CERT_SIGNATURE },
    224    { CIPHER_NAME("SECP128R2"), SEC_OID_SECG_EC_SECP128R2,
    225      NSS_USE_ALG_IN_SSL_KX | NSS_USE_ALG_IN_CERT_SIGNATURE },
    226    { CIPHER_NAME("SECP160K1"), SEC_OID_SECG_EC_SECP160K1,
    227      NSS_USE_ALG_IN_SSL_KX | NSS_USE_ALG_IN_CERT_SIGNATURE },
    228    { CIPHER_NAME("SECP160R1"), SEC_OID_SECG_EC_SECP160R1,
    229      NSS_USE_ALG_IN_SSL_KX | NSS_USE_ALG_IN_CERT_SIGNATURE },
    230    { CIPHER_NAME("SECP160R2"), SEC_OID_SECG_EC_SECP160R2,
    231      NSS_USE_ALG_IN_SSL_KX | NSS_USE_ALG_IN_CERT_SIGNATURE },
    232    { CIPHER_NAME("SECP192K1"), SEC_OID_SECG_EC_SECP192K1,
    233      NSS_USE_ALG_IN_SSL_KX | NSS_USE_ALG_IN_CERT_SIGNATURE },
    234    { CIPHER_NAME("SECP192R1"), SEC_OID_ANSIX962_EC_PRIME192V1,
    235      NSS_USE_ALG_IN_SSL_KX | NSS_USE_ALG_IN_CERT_SIGNATURE },
    236    { CIPHER_NAME("SECP224K1"), SEC_OID_SECG_EC_SECP224K1,
    237      NSS_USE_ALG_IN_SSL_KX | NSS_USE_ALG_IN_CERT_SIGNATURE },
    238    { CIPHER_NAME("SECP256K1"), SEC_OID_SECG_EC_SECP256K1,
    239      NSS_USE_ALG_IN_SSL_KX | NSS_USE_ALG_IN_CERT_SIGNATURE },
    240    { CIPHER_NAME("SECP256R1"), SEC_OID_ANSIX962_EC_PRIME256V1,
    241      NSS_USE_ALG_IN_SSL_KX | NSS_USE_ALG_IN_CERT_SIGNATURE },
    242    { CIPHER_NAME("SECP384R1"), SEC_OID_SECG_EC_SECP384R1,
    243      NSS_USE_ALG_IN_SSL_KX | NSS_USE_ALG_IN_CERT_SIGNATURE },
    244    { CIPHER_NAME("SECP521R1"), SEC_OID_SECG_EC_SECP521R1,
    245      NSS_USE_ALG_IN_SSL_KX | NSS_USE_ALG_IN_CERT_SIGNATURE },
    246    { CIPHER_NAME("CURVE25519"), SEC_OID_CURVE25519,
    247      NSS_USE_ALG_IN_SSL_KX | NSS_USE_ALG_IN_CERT_SIGNATURE },
    248    /* NOTE, don't use '0' to indicate default off. Setting '0'
    249     * makes this entry unmanagable by the policy code (including
    250     * turning the entry off. If you want an entry off by default
    251     * simply explictly flip the bits in SECOID_Init()
    252     * (util/secoid.c) */
    253    { CIPHER_NAME("XYBER768D00"), SEC_OID_XYBER768D00,
    254      NSS_USE_ALG_IN_SSL_KX },
    255    { CIPHER_NAME("X25519MLKEM768"), SEC_OID_MLKEM768X25519,
    256      NSS_USE_ALG_IN_SSL_KX },
    257    { CIPHER_NAME("SECP256R1MLKEM768"), SEC_OID_SECP256R1MLKEM768,
    258      NSS_USE_ALG_IN_SSL_KX },
    259    { CIPHER_NAME("SECP384R1MLKEM1024"), SEC_OID_SECP384R1MLKEM1024,
    260      NSS_USE_ALG_IN_SSL_KX },
    261    { CIPHER_NAME("MLKEM768X25519"), SEC_OID_MLKEM768X25519,
    262      NSS_USE_ALG_IN_SSL_KX },
    263    /* ANSI X9.62 named elliptic curves (characteristic two field) */
    264    { CIPHER_NAME("C2PNB163V1"), SEC_OID_ANSIX962_EC_C2PNB163V1,
    265      NSS_USE_ALG_IN_SSL_KX | NSS_USE_ALG_IN_CERT_SIGNATURE },
    266    { CIPHER_NAME("C2PNB163V2"), SEC_OID_ANSIX962_EC_C2PNB163V2,
    267      NSS_USE_ALG_IN_SSL_KX | NSS_USE_ALG_IN_CERT_SIGNATURE },
    268    { CIPHER_NAME("C2PNB163V3"), SEC_OID_ANSIX962_EC_C2PNB163V3,
    269      NSS_USE_ALG_IN_SSL_KX | NSS_USE_ALG_IN_CERT_SIGNATURE },
    270    { CIPHER_NAME("C2PNB176V1"), SEC_OID_ANSIX962_EC_C2PNB176V1,
    271      NSS_USE_ALG_IN_SSL_KX | NSS_USE_ALG_IN_CERT_SIGNATURE },
    272    { CIPHER_NAME("C2TNB191V1"), SEC_OID_ANSIX962_EC_C2TNB191V1,
    273      NSS_USE_ALG_IN_SSL_KX | NSS_USE_ALG_IN_CERT_SIGNATURE },
    274    { CIPHER_NAME("C2TNB191V2"), SEC_OID_ANSIX962_EC_C2TNB191V2,
    275      NSS_USE_ALG_IN_SSL_KX | NSS_USE_ALG_IN_CERT_SIGNATURE },
    276    { CIPHER_NAME("C2TNB191V3"), SEC_OID_ANSIX962_EC_C2TNB191V3,
    277      NSS_USE_ALG_IN_SSL_KX | NSS_USE_ALG_IN_CERT_SIGNATURE },
    278    { CIPHER_NAME("C2ONB191V4"), SEC_OID_ANSIX962_EC_C2ONB191V4,
    279      NSS_USE_ALG_IN_SSL_KX | NSS_USE_ALG_IN_CERT_SIGNATURE },
    280    { CIPHER_NAME("C2ONB191V5"), SEC_OID_ANSIX962_EC_C2ONB191V5,
    281      NSS_USE_ALG_IN_SSL_KX | NSS_USE_ALG_IN_CERT_SIGNATURE },
    282    { CIPHER_NAME("C2PNB208W1"), SEC_OID_ANSIX962_EC_C2PNB208W1,
    283      NSS_USE_ALG_IN_SSL_KX | NSS_USE_ALG_IN_CERT_SIGNATURE },
    284    { CIPHER_NAME("C2TNB239V1"), SEC_OID_ANSIX962_EC_C2TNB239V1,
    285      NSS_USE_ALG_IN_SSL_KX | NSS_USE_ALG_IN_CERT_SIGNATURE },
    286    { CIPHER_NAME("C2TNB239V2"), SEC_OID_ANSIX962_EC_C2TNB239V2,
    287      NSS_USE_ALG_IN_SSL_KX | NSS_USE_ALG_IN_CERT_SIGNATURE },
    288    { CIPHER_NAME("C2TNB239V3"), SEC_OID_ANSIX962_EC_C2TNB239V3,
    289      NSS_USE_ALG_IN_SSL_KX | NSS_USE_ALG_IN_CERT_SIGNATURE },
    290    { CIPHER_NAME("C2ONB239V4"), SEC_OID_ANSIX962_EC_C2ONB239V4,
    291      NSS_USE_ALG_IN_SSL_KX | NSS_USE_ALG_IN_CERT_SIGNATURE },
    292    { CIPHER_NAME("C2ONB239V5"), SEC_OID_ANSIX962_EC_C2ONB239V5,
    293      NSS_USE_ALG_IN_SSL_KX | NSS_USE_ALG_IN_CERT_SIGNATURE },
    294    { CIPHER_NAME("C2PNB272W1"), SEC_OID_ANSIX962_EC_C2PNB272W1,
    295      NSS_USE_ALG_IN_SSL_KX | NSS_USE_ALG_IN_CERT_SIGNATURE },
    296    { CIPHER_NAME("C2PNB304W1"), SEC_OID_ANSIX962_EC_C2PNB304W1,
    297      NSS_USE_ALG_IN_SSL_KX | NSS_USE_ALG_IN_CERT_SIGNATURE },
    298    { CIPHER_NAME("C2TNB359V1"), SEC_OID_ANSIX962_EC_C2TNB359V1,
    299      NSS_USE_ALG_IN_SSL_KX | NSS_USE_ALG_IN_CERT_SIGNATURE },
    300    { CIPHER_NAME("C2PNB368W1"), SEC_OID_ANSIX962_EC_C2PNB368W1,
    301      NSS_USE_ALG_IN_SSL_KX | NSS_USE_ALG_IN_CERT_SIGNATURE },
    302    { CIPHER_NAME("C2TNB431R1"), SEC_OID_ANSIX962_EC_C2TNB431R1,
    303      NSS_USE_ALG_IN_SSL_KX | NSS_USE_ALG_IN_CERT_SIGNATURE },
    304    /* SECG named elliptic curves (characteristic two field) */
    305    { CIPHER_NAME("SECT113R1"), SEC_OID_SECG_EC_SECT113R1,
    306      NSS_USE_ALG_IN_SSL_KX | NSS_USE_ALG_IN_CERT_SIGNATURE },
    307    { CIPHER_NAME("SECT131R1"), SEC_OID_SECG_EC_SECT113R2,
    308      NSS_USE_ALG_IN_SSL_KX | NSS_USE_ALG_IN_CERT_SIGNATURE },
    309    { CIPHER_NAME("SECT131R1"), SEC_OID_SECG_EC_SECT131R1,
    310      NSS_USE_ALG_IN_SSL_KX | NSS_USE_ALG_IN_CERT_SIGNATURE },
    311    { CIPHER_NAME("SECT131R2"), SEC_OID_SECG_EC_SECT131R2,
    312      NSS_USE_ALG_IN_SSL_KX | NSS_USE_ALG_IN_CERT_SIGNATURE },
    313    { CIPHER_NAME("SECT163K1"), SEC_OID_SECG_EC_SECT163K1,
    314      NSS_USE_ALG_IN_SSL_KX | NSS_USE_ALG_IN_CERT_SIGNATURE },
    315    { CIPHER_NAME("SECT163R1"), SEC_OID_SECG_EC_SECT163R1,
    316      NSS_USE_ALG_IN_SSL_KX | NSS_USE_ALG_IN_CERT_SIGNATURE },
    317    { CIPHER_NAME("SECT163R2"), SEC_OID_SECG_EC_SECT163R2,
    318      NSS_USE_ALG_IN_SSL_KX | NSS_USE_ALG_IN_CERT_SIGNATURE },
    319    { CIPHER_NAME("SECT193R1"), SEC_OID_SECG_EC_SECT193R1,
    320      NSS_USE_ALG_IN_SSL_KX | NSS_USE_ALG_IN_CERT_SIGNATURE },
    321    { CIPHER_NAME("SECT193R2"), SEC_OID_SECG_EC_SECT193R2,
    322      NSS_USE_ALG_IN_SSL_KX | NSS_USE_ALG_IN_CERT_SIGNATURE },
    323    { CIPHER_NAME("SECT233K1"), SEC_OID_SECG_EC_SECT233K1,
    324      NSS_USE_ALG_IN_SSL_KX | NSS_USE_ALG_IN_CERT_SIGNATURE },
    325    { CIPHER_NAME("SECT233R1"), SEC_OID_SECG_EC_SECT233R1,
    326      NSS_USE_ALG_IN_SSL_KX | NSS_USE_ALG_IN_CERT_SIGNATURE },
    327    { CIPHER_NAME("SECT239K1"), SEC_OID_SECG_EC_SECT239K1,
    328      NSS_USE_ALG_IN_SSL_KX | NSS_USE_ALG_IN_CERT_SIGNATURE },
    329    { CIPHER_NAME("SECT283K1"), SEC_OID_SECG_EC_SECT283K1,
    330      NSS_USE_ALG_IN_SSL_KX | NSS_USE_ALG_IN_CERT_SIGNATURE },
    331    { CIPHER_NAME("SECT283R1"), SEC_OID_SECG_EC_SECT283R1,
    332      NSS_USE_ALG_IN_SSL_KX | NSS_USE_ALG_IN_CERT_SIGNATURE },
    333    { CIPHER_NAME("SECT409K1"), SEC_OID_SECG_EC_SECT409K1,
    334      NSS_USE_ALG_IN_SSL_KX | NSS_USE_ALG_IN_CERT_SIGNATURE },
    335    { CIPHER_NAME("SECT409R1"), SEC_OID_SECG_EC_SECT409R1,
    336      NSS_USE_ALG_IN_SSL_KX | NSS_USE_ALG_IN_CERT_SIGNATURE },
    337    { CIPHER_NAME("SECT571K1"), SEC_OID_SECG_EC_SECT571K1,
    338      NSS_USE_ALG_IN_SSL_KX | NSS_USE_ALG_IN_CERT_SIGNATURE },
    339    { CIPHER_NAME("SECT571R1"), SEC_OID_SECG_EC_SECT571R1,
    340      NSS_USE_ALG_IN_SSL_KX | NSS_USE_ALG_IN_CERT_SIGNATURE },
    341 };
    342 
    343 static const oidValDef hashOptList[] = {
    344    /* Hashes */
    345    { CIPHER_NAME("MD2"), SEC_OID_MD2,
    346      NSS_USE_ALG_IN_SSL_KX | NSS_USE_ALG_IN_SIGNATURE | NSS_USE_ALG_IN_SMIME |
    347          NSS_USE_ALG_IN_PKCS12 },
    348    { CIPHER_NAME("MD4"), SEC_OID_MD4,
    349      NSS_USE_ALG_IN_SSL_KX | NSS_USE_ALG_IN_SIGNATURE | NSS_USE_ALG_IN_SMIME |
    350          NSS_USE_ALG_IN_PKCS12 },
    351    { CIPHER_NAME("MD5"), SEC_OID_MD5,
    352      NSS_USE_ALG_IN_SSL_KX | NSS_USE_ALG_IN_SIGNATURE | NSS_USE_ALG_IN_SMIME |
    353          NSS_USE_ALG_IN_PKCS12 },
    354    { CIPHER_NAME("SHA1"), SEC_OID_SHA1,
    355      NSS_USE_ALG_IN_SSL_KX | NSS_USE_ALG_IN_SIGNATURE | NSS_USE_ALG_IN_SMIME |
    356          NSS_USE_ALG_IN_PKCS12 },
    357    { CIPHER_NAME("SHA224"), SEC_OID_SHA224,
    358      NSS_USE_ALG_IN_SSL_KX | NSS_USE_ALG_IN_SIGNATURE | NSS_USE_ALG_IN_SMIME |
    359          NSS_USE_ALG_IN_PKCS12 },
    360    { CIPHER_NAME("SHA256"), SEC_OID_SHA256,
    361      NSS_USE_ALG_IN_SSL_KX | NSS_USE_ALG_IN_SIGNATURE | NSS_USE_ALG_IN_SMIME |
    362          NSS_USE_ALG_IN_PKCS12 },
    363    { CIPHER_NAME("SHA384"), SEC_OID_SHA384,
    364      NSS_USE_ALG_IN_SSL_KX | NSS_USE_ALG_IN_SIGNATURE | NSS_USE_ALG_IN_SMIME |
    365          NSS_USE_ALG_IN_PKCS12 },
    366    { CIPHER_NAME("SHA512"), SEC_OID_SHA512,
    367      NSS_USE_ALG_IN_SSL_KX | NSS_USE_ALG_IN_SIGNATURE | NSS_USE_ALG_IN_SMIME |
    368          NSS_USE_ALG_IN_PKCS12 },
    369    { CIPHER_NAME("SHA3-224"), SEC_OID_SHA3_224,
    370      NSS_USE_ALG_IN_SSL_KX | NSS_USE_ALG_IN_SIGNATURE | NSS_USE_ALG_IN_SMIME |
    371          NSS_USE_ALG_IN_PKCS12 },
    372    { CIPHER_NAME("SHA3-256"), SEC_OID_SHA3_256,
    373      NSS_USE_ALG_IN_SSL_KX | NSS_USE_ALG_IN_SIGNATURE | NSS_USE_ALG_IN_SMIME |
    374          NSS_USE_ALG_IN_PKCS12 },
    375    { CIPHER_NAME("SHA3-384"), SEC_OID_SHA3_384,
    376      NSS_USE_ALG_IN_SSL_KX | NSS_USE_ALG_IN_SIGNATURE | NSS_USE_ALG_IN_SMIME |
    377          NSS_USE_ALG_IN_PKCS12 },
    378    { CIPHER_NAME("SHA3-512"), SEC_OID_SHA3_512,
    379      NSS_USE_ALG_IN_SSL_KX | NSS_USE_ALG_IN_SIGNATURE | NSS_USE_ALG_IN_SMIME |
    380          NSS_USE_ALG_IN_PKCS12 }
    381 };
    382 
    383 static const oidValDef macOptList[] = {
    384    /* MACs */
    385    { CIPHER_NAME("HMAC-MD5"), SEC_OID_HMAC_MD5,
    386      NSS_USE_ALG_IN_SSL | NSS_USE_ALG_IN_PKCS12 },
    387    { CIPHER_NAME("HMAC-SHA1"), SEC_OID_HMAC_SHA1,
    388      NSS_USE_ALG_IN_SSL | NSS_USE_ALG_IN_PKCS12 },
    389    { CIPHER_NAME("HMAC-SHA224"), SEC_OID_HMAC_SHA224,
    390      NSS_USE_ALG_IN_SSL | NSS_USE_ALG_IN_PKCS12 },
    391    { CIPHER_NAME("HMAC-SHA256"), SEC_OID_HMAC_SHA256,
    392      NSS_USE_ALG_IN_SSL | NSS_USE_ALG_IN_PKCS12 },
    393    { CIPHER_NAME("HMAC-SHA384"), SEC_OID_HMAC_SHA384,
    394      NSS_USE_ALG_IN_SSL | NSS_USE_ALG_IN_PKCS12 },
    395    { CIPHER_NAME("HMAC-SHA512"), SEC_OID_HMAC_SHA512,
    396      NSS_USE_ALG_IN_SSL | NSS_USE_ALG_IN_PKCS12 },
    397    { CIPHER_NAME("HMAC-SHA3-224"), SEC_OID_HMAC_SHA3_224,
    398      NSS_USE_ALG_IN_SSL | NSS_USE_ALG_IN_PKCS12 },
    399    { CIPHER_NAME("HMAC-SHA3-256"), SEC_OID_HMAC_SHA3_256,
    400      NSS_USE_ALG_IN_SSL | NSS_USE_ALG_IN_PKCS12 },
    401    { CIPHER_NAME("HMAC-SHA3-384"), SEC_OID_HMAC_SHA3_384,
    402      NSS_USE_ALG_IN_SSL | NSS_USE_ALG_IN_PKCS12 },
    403    { CIPHER_NAME("HMAC-SHA3-512"), SEC_OID_HMAC_SHA3_512,
    404      NSS_USE_ALG_IN_SSL | NSS_USE_ALG_IN_PKCS12 },
    405 };
    406 
    407 static const oidValDef cipherOptList[] = {
    408    /* Ciphers */
    409    { CIPHER_NAME("AES128-CBC"), SEC_OID_AES_128_CBC,
    410      NSS_USE_ALG_IN_SSL | NSS_USE_ALG_IN_SMIME | NSS_USE_ALG_IN_PKCS12 },
    411    { CIPHER_NAME("AES192-CBC"), SEC_OID_AES_192_CBC,
    412      NSS_USE_ALG_IN_SSL | NSS_USE_ALG_IN_SMIME | NSS_USE_ALG_IN_PKCS12 },
    413    { CIPHER_NAME("AES256-CBC"), SEC_OID_AES_256_CBC,
    414      NSS_USE_ALG_IN_SSL | NSS_USE_ALG_IN_SMIME | NSS_USE_ALG_IN_PKCS12 },
    415    { CIPHER_NAME("AES128-GCM"), SEC_OID_AES_128_GCM, NSS_USE_ALG_IN_SSL },
    416    { CIPHER_NAME("AES192-GCM"), SEC_OID_AES_192_GCM, NSS_USE_ALG_IN_SSL },
    417    { CIPHER_NAME("AES256-GCM"), SEC_OID_AES_256_GCM, NSS_USE_ALG_IN_SSL },
    418    { CIPHER_NAME("CAMELLIA128-CBC"), SEC_OID_CAMELLIA_128_CBC,
    419      NSS_USE_ALG_IN_SSL | NSS_USE_ALG_IN_SMIME | NSS_USE_ALG_IN_PKCS12 },
    420    { CIPHER_NAME("CAMELLIA192-CBC"), SEC_OID_CAMELLIA_192_CBC,
    421      NSS_USE_ALG_IN_SSL | NSS_USE_ALG_IN_SMIME | NSS_USE_ALG_IN_PKCS12 },
    422    { CIPHER_NAME("CAMELLIA256-CBC"), SEC_OID_CAMELLIA_256_CBC,
    423      NSS_USE_ALG_IN_SSL | NSS_USE_ALG_IN_SMIME | NSS_USE_ALG_IN_PKCS12 },
    424    { CIPHER_NAME("CHACHA20-POLY1305"), SEC_OID_CHACHA20_POLY1305, NSS_USE_ALG_IN_SSL },
    425    { CIPHER_NAME("SEED-CBC"), SEC_OID_SEED_CBC,
    426      NSS_USE_ALG_IN_SSL | NSS_USE_ALG_IN_SMIME | NSS_USE_ALG_IN_PKCS12 },
    427    { CIPHER_NAME("DES-EDE3-CBC"), SEC_OID_DES_EDE3_CBC,
    428      NSS_USE_ALG_IN_SSL | NSS_USE_ALG_IN_SMIME | NSS_USE_ALG_IN_PKCS12 },
    429    { CIPHER_NAME("DES-40-CBC"), SEC_OID_DES_40_CBC,
    430      NSS_USE_ALG_IN_SSL | NSS_USE_ALG_IN_SMIME | NSS_USE_ALG_IN_PKCS12 },
    431    { CIPHER_NAME("DES-CBC"), SEC_OID_DES_CBC, NSS_USE_ALG_IN_SSL },
    432    { CIPHER_NAME("NULL-CIPHER"), SEC_OID_NULL_CIPHER, NSS_USE_ALG_IN_SSL },
    433    { CIPHER_NAME("RC2"), SEC_OID_RC2_CBC, NSS_USE_ALG_IN_SSL | NSS_USE_ALG_IN_PKCS12 },
    434    { CIPHER_NAME("RC2-40-CBC"), SEC_OID_RC2_40_CBC, NSS_USE_ALG_IN_SMIME },
    435    { CIPHER_NAME("RC2-64-CBC"), SEC_OID_RC2_64_CBC, NSS_USE_ALG_IN_SMIME },
    436    { CIPHER_NAME("RC2-128-CBC"), SEC_OID_RC2_128_CBC, NSS_USE_ALG_IN_SMIME },
    437    { CIPHER_NAME("RC4"), SEC_OID_RC4, NSS_USE_ALG_IN_SSL | NSS_USE_ALG_IN_PKCS12 },
    438    { CIPHER_NAME("IDEA"), SEC_OID_IDEA_CBC, NSS_USE_ALG_IN_SSL },
    439 };
    440 
    441 static const oidValDef kxOptList[] = {
    442    /* Key exchange */
    443    { CIPHER_NAME("RSA"), SEC_OID_TLS_RSA, NSS_USE_ALG_IN_SSL_KX },
    444    { CIPHER_NAME("RSA-EXPORT"), SEC_OID_TLS_RSA_EXPORT, NSS_USE_ALG_IN_SSL_KX },
    445    { CIPHER_NAME("DHE-RSA"), SEC_OID_TLS_DHE_RSA, NSS_USE_ALG_IN_SSL_KX },
    446    { CIPHER_NAME("DHE-DSS"), SEC_OID_TLS_DHE_DSS, NSS_USE_ALG_IN_SSL_KX },
    447    { CIPHER_NAME("DH-RSA"), SEC_OID_TLS_DH_RSA, NSS_USE_ALG_IN_SSL_KX },
    448    { CIPHER_NAME("DH-DSS"), SEC_OID_TLS_DH_DSS, NSS_USE_ALG_IN_SSL_KX },
    449    { CIPHER_NAME("ECDHE-ECDSA"), SEC_OID_TLS_ECDHE_ECDSA, NSS_USE_ALG_IN_SSL_KX },
    450    { CIPHER_NAME("ECDHE-RSA"), SEC_OID_TLS_ECDHE_RSA, NSS_USE_ALG_IN_SSL_KX },
    451    { CIPHER_NAME("ECDH-ECDSA"), SEC_OID_TLS_ECDH_ECDSA, NSS_USE_ALG_IN_SSL_KX },
    452    { CIPHER_NAME("ECDH-RSA"), SEC_OID_TLS_ECDH_RSA, NSS_USE_ALG_IN_SSL_KX },
    453    { CIPHER_NAME("TLS-REQUIRE-EMS"), SEC_OID_TLS_REQUIRE_EMS, NSS_USE_ALG_IN_SSL_KX },
    454 
    455 };
    456 
    457 static const oidValDef smimeKxOptList[] = {
    458    /* Key exchange */
    459    { CIPHER_NAME("RSA-PKCS"), SEC_OID_PKCS1_RSA_ENCRYPTION, NSS_USE_ALG_IN_SMIME_KX },
    460    { CIPHER_NAME("RSA-OAEP"), SEC_OID_PKCS1_RSA_OAEP_ENCRYPTION, NSS_USE_ALG_IN_SMIME_KX },
    461    { CIPHER_NAME("ECDH"), SEC_OID_ECDH_KEA, NSS_USE_ALG_IN_SMIME_KX },
    462    { CIPHER_NAME("DH"), SEC_OID_X942_DIFFIE_HELMAN_KEY, NSS_USE_ALG_IN_SMIME_KX },
    463 };
    464 
    465 static const oidValDef signOptList[] = {
    466    /* Signatures */
    467    { CIPHER_NAME("DSA"), SEC_OID_ANSIX9_DSA_SIGNATURE,
    468      NSS_USE_ALG_IN_SSL_KX | NSS_USE_ALG_IN_SIGNATURE },
    469    { CIPHER_NAME("RSA-PKCS"), SEC_OID_PKCS1_RSA_ENCRYPTION,
    470      NSS_USE_ALG_IN_SSL_KX | NSS_USE_ALG_IN_SIGNATURE },
    471    { CIPHER_NAME("RSA-PSS"), SEC_OID_PKCS1_RSA_PSS_SIGNATURE,
    472      NSS_USE_ALG_IN_SSL_KX | NSS_USE_ALG_IN_SIGNATURE },
    473    { CIPHER_NAME("ECDSA"), SEC_OID_ANSIX962_EC_PUBLIC_KEY,
    474      NSS_USE_ALG_IN_SSL_KX | NSS_USE_ALG_IN_SIGNATURE },
    475    { CIPHER_NAME("ED25519"), SEC_OID_ED25519_PUBLIC_KEY,
    476      NSS_USE_ALG_IN_SIGNATURE },
    477    { CIPHER_NAME("ML-DSA-44"), SEC_OID_ML_DSA_44,
    478      NSS_USE_ALG_IN_SIGNATURE },
    479    { CIPHER_NAME("ML-DSA-65"), SEC_OID_ML_DSA_65,
    480      NSS_USE_ALG_IN_SIGNATURE },
    481    { CIPHER_NAME("ML-DSA-87"), SEC_OID_ML_DSA_87,
    482      NSS_USE_ALG_IN_SIGNATURE },
    483 };
    484 
    485 typedef struct {
    486    const oidValDef *list;
    487    PRUint32 entries;
    488    const char *description;
    489    PRBool allowEmpty;
    490 } algListsDef;
    491 
    492 static const algListsDef algOptLists[] = {
    493    { curveOptList, PR_ARRAY_SIZE(curveOptList), "ECC", PR_FALSE },
    494    { hashOptList, PR_ARRAY_SIZE(hashOptList), "HASH", PR_FALSE },
    495    { macOptList, PR_ARRAY_SIZE(macOptList), "MAC", PR_FALSE },
    496    { cipherOptList, PR_ARRAY_SIZE(cipherOptList), "CIPHER", PR_FALSE },
    497    { kxOptList, PR_ARRAY_SIZE(kxOptList), "SSL-KX", PR_FALSE },
    498    { smimeKxOptList, PR_ARRAY_SIZE(smimeKxOptList), "SMIME-KX", PR_TRUE },
    499    { signOptList, PR_ARRAY_SIZE(signOptList), "OTHER-SIGN", PR_FALSE },
    500 };
    501 
    502 static const optionFreeDef sslOptList[] = {
    503    /* Versions */
    504    { CIPHER_NAME("SSL2.0"), 0x002 },
    505    { CIPHER_NAME("SSL3.0"), 0x300 },
    506    { CIPHER_NAME("SSL3.1"), 0x301 },
    507    { CIPHER_NAME("TLS1.0"), 0x301 },
    508    { CIPHER_NAME("TLS1.1"), 0x302 },
    509    { CIPHER_NAME("TLS1.2"), 0x303 },
    510    { CIPHER_NAME("TLS1.3"), 0x304 },
    511    { CIPHER_NAME("DTLS1.0"), 0x302 },
    512    { CIPHER_NAME("DTLS1.1"), 0x302 },
    513    { CIPHER_NAME("DTLS1.2"), 0x303 },
    514    { CIPHER_NAME("DTLS1.3"), 0x304 },
    515 };
    516 
    517 static const optionFreeDef keySizeFlagsList[] = {
    518    { CIPHER_NAME("KEY-SIZE-SSL"), NSS_KEY_SIZE_POLICY_SSL_FLAG },
    519    { CIPHER_NAME("KEY-SIZE-SIGN"), NSS_KEY_SIZE_POLICY_SIGN_FLAG },
    520    { CIPHER_NAME("KEY-SIZE-VERIFY"), NSS_KEY_SIZE_POLICY_VERIFY_FLAG },
    521    { CIPHER_NAME("KEY-SIZE-SMIME"), NSS_KEY_SIZE_POLICY_SMIME_FLAG },
    522    { CIPHER_NAME("KEY-SIZE-ALL"), NSS_KEY_SIZE_POLICY_ALL_FLAGS },
    523 };
    524 
    525 static const optionFreeDef freeOptList[] = {
    526 
    527    /* Restrictions for asymetric keys */
    528    { CIPHER_NAME("RSA-MIN"), NSS_RSA_MIN_KEY_SIZE },
    529    { CIPHER_NAME("DH-MIN"), NSS_DH_MIN_KEY_SIZE },
    530    { CIPHER_NAME("DSA-MIN"), NSS_DSA_MIN_KEY_SIZE },
    531    { CIPHER_NAME("ECC-MIN"), NSS_ECC_MIN_KEY_SIZE },
    532    /* what operations doe the key size apply to */
    533    { CIPHER_NAME("KEY-SIZE-FLAGS"), NSS_KEY_SIZE_POLICY_FLAGS },
    534    /* constraints on SSL Protocols */
    535    { CIPHER_NAME("TLS-VERSION-MIN"), NSS_TLS_VERSION_MIN_POLICY },
    536    { CIPHER_NAME("TLS-VERSION-MAX"), NSS_TLS_VERSION_MAX_POLICY },
    537    /* constraints on DTLS Protocols */
    538    { CIPHER_NAME("DTLS-VERSION-MIN"), NSS_DTLS_VERSION_MIN_POLICY },
    539    { CIPHER_NAME("DTLS-VERSION-MAX"), NSS_DTLS_VERSION_MAX_POLICY }
    540 };
    541 
    542 static const policyFlagDef policyFlagList[] = {
    543    { CIPHER_NAME("SSL"), NSS_USE_ALG_IN_SSL },
    544    { CIPHER_NAME("SSL-KEY-EXCHANGE"), NSS_USE_ALG_IN_SSL_KX },
    545    /* add other key exhanges in the future */
    546    { CIPHER_NAME("KEY-EXCHANGE"), NSS_USE_ALG_IN_KEY_EXCHANGE },
    547    { CIPHER_NAME("CERT-SIGNATURE"), NSS_USE_ALG_IN_CERT_SIGNATURE },
    548    { CIPHER_NAME("CMS-SIGNATURE"), NSS_USE_ALG_IN_SMIME_SIGNATURE },
    549    { CIPHER_NAME("SMIME-SIGNATURE"), NSS_USE_ALG_IN_SMIME_SIGNATURE },
    550    { CIPHER_NAME("ALL-SIGNATURE"), NSS_USE_ALG_IN_SIGNATURE },
    551    { CIPHER_NAME("PKCS12"), NSS_USE_ALG_IN_PKCS12 },
    552    /* only use in allow */
    553    { CIPHER_NAME("PKCS12-LEGACY"), NSS_USE_ALG_IN_PKCS12_DECRYPT },
    554    /* only use in disallow */
    555    { CIPHER_NAME("PKCS12-ENCRYPT"), NSS_USE_ALG_IN_PKCS12_ENCRYPT },
    556    { CIPHER_NAME("SMIME"), NSS_USE_ALG_IN_SMIME },
    557    /* only use in allow, enable */
    558    { CIPHER_NAME("SMIME-LEGACY"), NSS_USE_ALG_IN_SMIME_LEGACY },
    559    /* only use in disallow, disable */
    560    { CIPHER_NAME("SMIME-ENCRYPT"), NSS_USE_ALG_IN_SMIME_ENCRYPT },
    561    { CIPHER_NAME("SMIME-KEY-EXCHANGE"), NSS_USE_ALG_IN_SMIME_KX },
    562    /* only use in allow */
    563    { CIPHER_NAME("SMIME-KEY-EXCHANGE-LEGACY"), NSS_USE_ALG_IN_SMIME_KX_LEGACY },
    564    /* only use in disallow */
    565    { CIPHER_NAME("SMIME-KEY-EXCHANGE-ENCRYPT"), NSS_USE_ALG_IN_SMIME_KX_ENCRYPT },
    566    /* sign turns off all signatures, but doesn't change the
    567     * allowance for specific signatures... for example:
    568     *     disallow=sha256/all allow=sha256/signature
    569     * doesn't allow cert-signatures or sime-signatures, where
    570     *     disallow=sha256/all allow=sha256/all-signature
    571     * does. however,
    572     *     disallow=sha256/signature
    573     * and
    574     *     disallow=sha256/all-signature
    575     * are equivalent in effect */
    576    { CIPHER_NAME("SIGNATURE"), NSS_USE_ALG_IN_ANY_SIGNATURE },
    577    /* enable/allow algorithms for legacy (read/verify)operations */
    578    { CIPHER_NAME("LEGACY"), NSS_USE_ALG_IN_PKCS12_DECRYPT |
    579                                 NSS_USE_ALG_IN_SMIME_LEGACY |
    580                                 NSS_USE_ALG_IN_SMIME_KX_LEGACY },
    581    /* enable/disable everything */
    582    { CIPHER_NAME("ALL"), NSS_USE_ALG_IN_SSL | NSS_USE_ALG_IN_SSL_KX |
    583                              NSS_USE_ALG_IN_PKCS12 | NSS_USE_ALG_IN_SMIME |
    584                              NSS_USE_ALG_IN_SIGNATURE |
    585                              NSS_USE_ALG_IN_SMIME_KX },
    586    { CIPHER_NAME("NONE"), 0 }
    587 };
    588 
    589 /*
    590 *  Get the next cipher on the list. point to the next one in 'next'.
    591 *  return the length;
    592 */
    593 static const char *
    594 secmod_ArgGetSubValue(const char *cipher, char sep1, char sep2,
    595                      int *len, const char **next)
    596 {
    597    const char *start = cipher;
    598 
    599    if (start == NULL) {
    600        *len = 0;
    601        *next = NULL;
    602        return start;
    603    }
    604 
    605    for (; *cipher && *cipher != sep2; cipher++) {
    606        if (*cipher == sep1) {
    607            *next = cipher + 1;
    608            *len = cipher - start;
    609            return start;
    610        }
    611    }
    612    *next = NULL;
    613    *len = cipher - start;
    614    return start;
    615 }
    616 
    617 static PRUint32
    618 secmod_parsePolicyValue(const char *policyFlags, int policyLength,
    619                        PRBool printPolicyFeedback, PRUint32 policyCheckFlags)
    620 {
    621    const char *flag, *currentString;
    622    PRUint32 flags = 0;
    623    int i;
    624 
    625    for (currentString = policyFlags; currentString &&
    626                                      currentString < policyFlags + policyLength;) {
    627        int length;
    628        PRBool unknown = PR_TRUE;
    629        flag = secmod_ArgGetSubValue(currentString, ',', ':', &length,
    630                                     &currentString);
    631        if (length == 0) {
    632            continue;
    633        }
    634        for (i = 0; i < PR_ARRAY_SIZE(policyFlagList); i++) {
    635            const policyFlagDef *policy = &policyFlagList[i];
    636            unsigned name_size = policy->name_size;
    637            if ((policy->name_size == length) &&
    638                PORT_Strncasecmp(policy->name, flag, name_size) == 0) {
    639                flags |= policy->flag;
    640                unknown = PR_FALSE;
    641                break;
    642            }
    643        }
    644        if (unknown && printPolicyFeedback &&
    645            (policyCheckFlags & SECMOD_FLAG_POLICY_CHECK_VALUE)) {
    646            PR_SetEnv("NSS_POLICY_FAIL=1");
    647            fprintf(stderr, "NSS-POLICY-FAIL %.*s: unknown value: %.*s\n",
    648                    policyLength, policyFlags, length, flag);
    649        }
    650    }
    651    return flags;
    652 }
    653 
    654 /* allow symbolic names for values. The only ones currently defines or
    655 * SSL protocol versions. */
    656 static SECStatus
    657 secmod_getPolicyOptValue(const char *policyValue, int policyValueLength,
    658                         PRInt32 *result)
    659 {
    660    PRInt32 val = atoi(policyValue);
    661    int i;
    662 
    663    if ((val != 0) || (*policyValue == '0')) {
    664        *result = val;
    665        return SECSuccess;
    666    }
    667    if (policyValueLength == 0) {
    668        return SECFailure;
    669    }
    670    /* handle any ssl strings */
    671    for (i = 0; i < PR_ARRAY_SIZE(sslOptList); i++) {
    672        if (policyValueLength == sslOptList[i].name_size &&
    673            PORT_Strncasecmp(sslOptList[i].name, policyValue,
    674                             sslOptList[i].name_size) == 0) {
    675            *result = sslOptList[i].option;
    676            return SECSuccess;
    677        }
    678    }
    679    /* handle key_size flags. Each flag represents a bit, which
    680     * gets or'd together. They can be separated by , | or + */
    681    val = 0;
    682    while (policyValueLength > 0) {
    683        PRBool found = PR_FALSE;
    684        for (i = 0; i < PR_ARRAY_SIZE(keySizeFlagsList); i++) {
    685            if (PORT_Strncasecmp(keySizeFlagsList[i].name, policyValue,
    686                                 keySizeFlagsList[i].name_size) == 0) {
    687                val |= keySizeFlagsList[i].option;
    688                found = PR_TRUE;
    689                policyValue += keySizeFlagsList[i].name_size;
    690                policyValueLength -= keySizeFlagsList[i].name_size;
    691                break;
    692            }
    693        }
    694        if (!found) {
    695            return SECFailure;
    696        }
    697        if (*policyValue == ',' || *policyValue == '|' || *policyValue == '+') {
    698            policyValue++;
    699            policyValueLength--;
    700        }
    701    }
    702    *result = val;
    703    return SECSuccess;
    704 }
    705 
    706 /* Policy operations:
    707 *     Disallow: operation is disallowed by policy. Implies disabled.
    708 *     Allow: operation is allowed by policy (but could be disabled).
    709 *     Disable: operation is turned off by default (but could be allowed).
    710 *     Enable: operation is enabled by default. Implies allowed.
    711 */
    712 typedef enum {
    713    NSS_DISALLOW,
    714    NSS_ALLOW,
    715    NSS_DISABLE,
    716    NSS_ENABLE
    717 } NSSPolicyOperation;
    718 
    719 /* Enable/Disable only apply to SSL cipher suites and S/MIME symetric algorithms.
    720 * Enable/Disable is implemented by clearing the DEFAULT_NOT_VALID
    721 * flag, then setting the NSS_USE_DEFAULT_SSL_ENABLE and
    722 * NSS_USE_DEFAULT_SMIME_ENABLE flags to the correct value. The ssl
    723 * policy code will then sort out what to set based on ciphers and
    724 * cipher suite values and the smime policy code will sort
    725 * out which ciphers to include in capabilities based on these values */
    726 static SECStatus
    727 secmod_setDefault(SECOidTag oid, NSSPolicyOperation operation,
    728                  PRUint32 value)
    729 {
    730    SECStatus rv = SECSuccess;
    731    PRUint32 policy;
    732    PRUint32 useDefault = 0;
    733    PRUint32 set = 0;
    734    /* we always clear the default not valid flag as this operation will
    735     * make the defaults valid */
    736    PRUint32 clear = NSS_USE_DEFAULT_NOT_VALID;
    737 
    738    /* what values are we trying to change */
    739    /* if either SSL or SSL_KX is set, enable SSL */
    740    if (value & (NSS_USE_ALG_IN_SSL | NSS_USE_ALG_IN_SSL_KX)) {
    741        useDefault |= NSS_USE_DEFAULT_SSL_ENABLE;
    742    }
    743    /* only bulk ciphers are configured as enable in S/MIME, only
    744     * enable them if both SMIME bits are set */
    745    if ((value & NSS_USE_ALG_IN_SMIME) == NSS_USE_ALG_IN_SMIME) {
    746        useDefault |= NSS_USE_DEFAULT_SMIME_ENABLE;
    747    }
    748 
    749    /* on disable we clear, on enable we set */
    750    if (operation == NSS_DISABLE) {
    751        clear |= useDefault;
    752    } else {
    753        /* we also turn the cipher on by policy if we enable it,
    754         * so include the policy bits */
    755        set |= value | useDefault;
    756    }
    757 
    758    /* if we haven't set the not valid flag yet, then we need to
    759     * clear any of the other bits we aren't actually setting as well.
    760     */
    761    rv = NSS_GetAlgorithmPolicy(oid, &policy);
    762    if (rv != SECSuccess) {
    763        return rv;
    764    }
    765    if (policy & NSS_USE_DEFAULT_NOT_VALID) {
    766        clear |= ((NSS_USE_DEFAULT_SSL_ENABLE | NSS_USE_DEFAULT_SMIME_ENABLE) &
    767                  ~set);
    768    }
    769    return NSS_SetAlgorithmPolicy(oid, set, clear);
    770 }
    771 
    772 /* apply the operator specific policy */
    773 SECStatus
    774 secmod_setPolicyOperation(SECOidTag oid, NSSPolicyOperation operation,
    775                          PRUint32 value)
    776 {
    777    SECStatus rv = SECSuccess;
    778    switch (operation) {
    779        case NSS_DISALLOW:
    780            /* clear the requested policy bits */
    781            rv = NSS_SetAlgorithmPolicy(oid, 0, value);
    782            break;
    783        case NSS_ALLOW:
    784            /* set the requested policy bits */
    785            rv = NSS_SetAlgorithmPolicy(oid, value, 0);
    786            break;
    787        case NSS_DISABLE:
    788        case NSS_ENABLE:
    789            rv = secmod_setDefault(oid, operation, value);
    790            break;
    791        default:
    792            PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
    793            rv = SECFailure;
    794            break;
    795    }
    796    return rv;
    797 }
    798 
    799 const char *
    800 secmod_getOperationString(NSSPolicyOperation operation)
    801 {
    802    switch (operation) {
    803        case NSS_DISALLOW:
    804            return "disallow";
    805        case NSS_ALLOW:
    806            return "allow";
    807        case NSS_DISABLE:
    808            return "disable";
    809        case NSS_ENABLE:
    810            return "enable";
    811        default:
    812            break;
    813    }
    814    return "invalid";
    815 }
    816 
    817 /* Allow external applications fetch the policy oid based on the internal
    818 * string mapping used by the configuration system. The search can be
    819 * narrowed by supplying the name of the table (list) that the policy
    820 * is on. The value 'Any' allows the policy to be searched on all lists */
    821 SECOidTag
    822 SECMOD_PolicyStringToOid(const char *policy, const char *list)
    823 {
    824    PRBool any = (PORT_Strcasecmp(list, "Any") == 0) ? PR_TRUE : PR_FALSE;
    825    int len = PORT_Strlen(policy);
    826    int i, j;
    827 
    828    for (i = 0; i < PR_ARRAY_SIZE(algOptLists); i++) {
    829        const algListsDef *algOptList = &algOptLists[i];
    830        if (any || (PORT_Strcasecmp(algOptList->description, list) == 0)) {
    831            for (j = 0; j < algOptList->entries; j++) {
    832                const oidValDef *algOpt = &algOptList->list[j];
    833                unsigned name_size = algOpt->name_size;
    834                if (len == name_size &&
    835                    PORT_Strcasecmp(algOpt->name, policy) == 0) {
    836                    return algOpt->oid;
    837                }
    838            }
    839        }
    840    }
    841    return SEC_OID_UNKNOWN;
    842 }
    843 
    844 /* Allow external applications fetch the NSS option based on the internal
    845 * string mapping used by the configuration system. */
    846 PRUint32
    847 SECMOD_PolicyStringToOpt(const char *policy)
    848 {
    849    int len = PORT_Strlen(policy);
    850    int i;
    851 
    852    for (i = 0; i < PR_ARRAY_SIZE(freeOptList); i++) {
    853        const optionFreeDef *freeOpt = &freeOptList[i];
    854        unsigned name_size = freeOpt->name_size;
    855        if (len == name_size &&
    856            PORT_Strcasecmp(freeOpt->name, policy) == 0) {
    857            return freeOpt->option;
    858        }
    859    }
    860    return 0;
    861 }
    862 
    863 /* Allow external applications map policy flags to their string equivalance.
    864 * Some strings represent more than one flag. If more than one flag is included
    865 * the returned string is the string that contains any of the
    866 * supplied flags unless exact is specified. If exact is specified, then the
    867 * returned value matches all the included flags and only those flags. For
    868 * Example: 'ALL-SIGNATURE' has the bits NSS_USE_ALG_IN_CERTSIGNATURE|
    869 * NSS_USE_ALG_IN_SMIME_SIGNATURE|NSS_USE_ALG_IN_ANY_SIGNATURE. If you ask for
    870 * NSS_USE_ALG_IN_CERT_SIGNATURE|NSS_USE_ALG_IN_SMIME_SIGNATURE and don't set
    871 * exact, this function will return 'ALL-SIGNATURE' if you do set exact, you must
    872 * include all three bits in value to get 'All-SIGNATURE'*/
    873 const char *
    874 SECMOD_FlagsToPolicyString(PRUint32 val, PRBool exact)
    875 {
    876    int i;
    877 
    878    for (i = 0; i < PR_ARRAY_SIZE(policyFlagList); i++) {
    879        const policyFlagDef *policy = &policyFlagList[i];
    880        if (exact && (policy->flag == val)) {
    881            return policy->name;
    882        }
    883        if (!exact && ((policy->flag & val) == policy->flag)) {
    884            return policy->name;
    885        }
    886    }
    887    return NULL;
    888 }
    889 
    890 static SECStatus
    891 secmod_applyCryptoPolicy(const char *policyString, NSSPolicyOperation operation,
    892                         PRBool printPolicyFeedback, PRUint32 policyCheckFlags)
    893 {
    894    const char *cipher, *currentString;
    895    unsigned i, j;
    896    SECStatus rv = SECSuccess;
    897    PRBool unknown;
    898 
    899    if (policyString == NULL || policyString[0] == 0) {
    900        return SECSuccess; /* do nothing */
    901    }
    902 
    903    /* if we change any of these, make sure it gets applied in ssl as well */
    904    NSS_SetAlgorithmPolicy(SEC_OID_APPLY_SSL_POLICY, NSS_USE_POLICY_IN_SSL, 0);
    905 
    906    for (currentString = policyString; currentString;) {
    907        int length;
    908        PRBool newValue = PR_FALSE;
    909 
    910        cipher = secmod_ArgGetSubValue(currentString, ':', 0, &length,
    911                                       &currentString);
    912        unknown = PR_TRUE;
    913        if (length >= 3 && cipher[3] == '/') {
    914            newValue = PR_TRUE;
    915        }
    916        if ((newValue || (length == 3)) && PORT_Strncasecmp(cipher, "all", 3) == 0) {
    917            /* disable or enable all options by default */
    918            PRUint32 value = 0;
    919            if (newValue) {
    920                value = secmod_parsePolicyValue(&cipher[3] + 1, length - 3 - 1, printPolicyFeedback, policyCheckFlags);
    921            }
    922            for (i = 0; i < PR_ARRAY_SIZE(algOptLists); i++) {
    923                const algListsDef *algOptList = &algOptLists[i];
    924                for (j = 0; j < algOptList->entries; j++) {
    925                    if (!newValue) {
    926                        value = algOptList->list[j].val;
    927                    }
    928                    secmod_setPolicyOperation(algOptList->list[j].oid, operation, value);
    929                }
    930            }
    931            continue;
    932        }
    933 
    934        for (i = 0; i < PR_ARRAY_SIZE(algOptLists); i++) {
    935            const algListsDef *algOptList = &algOptLists[i];
    936            for (j = 0; j < algOptList->entries; j++) {
    937                const oidValDef *algOpt = &algOptList->list[j];
    938                unsigned name_size = algOpt->name_size;
    939                PRBool newOption = PR_FALSE;
    940 
    941                if ((length >= name_size) && (cipher[name_size] == '/')) {
    942                    newOption = PR_TRUE;
    943                }
    944                if ((newOption || algOpt->name_size == length) &&
    945                    PORT_Strncasecmp(algOpt->name, cipher, name_size) == 0) {
    946                    PRUint32 value = algOpt->val;
    947                    if (newOption) {
    948                        value = secmod_parsePolicyValue(&cipher[name_size] + 1,
    949                                                        length - name_size - 1,
    950                                                        printPolicyFeedback,
    951                                                        policyCheckFlags);
    952                    }
    953                    rv = secmod_setPolicyOperation(algOptList->list[j].oid, operation, value);
    954                    if (rv != SECSuccess) {
    955                        /* could not enable option */
    956                        /* NSS_SetAlgorithPolicy should have set the error code */
    957                        return SECFailure;
    958                    }
    959                    unknown = PR_FALSE;
    960                    break;
    961                }
    962            }
    963        }
    964        if (!unknown) {
    965            continue;
    966        }
    967 
    968        for (i = 0; i < PR_ARRAY_SIZE(freeOptList); i++) {
    969            const optionFreeDef *freeOpt = &freeOptList[i];
    970            unsigned name_size = freeOpt->name_size;
    971 
    972            if ((length > name_size) && cipher[name_size] == '=' &&
    973                PORT_Strncasecmp(freeOpt->name, cipher, name_size) == 0) {
    974                PRInt32 val;
    975                const char *policyValue = &cipher[name_size + 1];
    976                int policyValueLength = length - name_size - 1;
    977                rv = secmod_getPolicyOptValue(policyValue, policyValueLength,
    978                                              &val);
    979                if (rv != SECSuccess) {
    980                    if (printPolicyFeedback &&
    981                        (policyCheckFlags & SECMOD_FLAG_POLICY_CHECK_VALUE)) {
    982                        PR_SetEnv("NSS_POLICY_FAIL=1");
    983                        fprintf(stderr, "NSS-POLICY-FAIL %.*s: unknown value: %.*s\n",
    984                                length, cipher, policyValueLength, policyValue);
    985                    }
    986                    return SECFailure;
    987                }
    988                rv = NSS_OptionSet(freeOpt->option, val);
    989                if (rv != SECSuccess) {
    990                    /* could not enable option */
    991                    /* NSS_OptionSet should have set the error code */
    992                    return SECFailure;
    993                }
    994                /* to allow the policy to expand in the future. ignore ciphers
    995                 * we don't understand */
    996                unknown = PR_FALSE;
    997                break;
    998            }
    999        }
   1000 
   1001        if (unknown && printPolicyFeedback &&
   1002            (policyCheckFlags & SECMOD_FLAG_POLICY_CHECK_IDENTIFIER)) {
   1003            PR_SetEnv("NSS_POLICY_FAIL=1");
   1004            fprintf(stderr, "NSS-POLICY-FAIL %s: unknown identifier: %.*s\n",
   1005                    secmod_getOperationString(operation), length, cipher);
   1006        }
   1007    }
   1008    return rv;
   1009 }
   1010 
   1011 static void
   1012 secmod_sanityCheckCryptoPolicy(void)
   1013 {
   1014    unsigned i, j;
   1015    SECStatus rv = SECSuccess;
   1016    unsigned num_kx_enabled = 0;
   1017    unsigned num_ssl_enabled = 0;
   1018    unsigned num_sig_enabled = 0;
   1019    unsigned enabledCount[PR_ARRAY_SIZE(algOptLists)];
   1020    const char *sWarn = "WARN";
   1021    const char *sInfo = "INFO";
   1022    PRBool haveWarning = PR_FALSE;
   1023 
   1024    for (i = 0; i < PR_ARRAY_SIZE(algOptLists); i++) {
   1025        const algListsDef *algOptList = &algOptLists[i];
   1026        enabledCount[i] = 0;
   1027        for (j = 0; j < algOptList->entries; j++) {
   1028            const oidValDef *algOpt = &algOptList->list[j];
   1029            PRUint32 value;
   1030            PRBool anyEnabled = PR_FALSE;
   1031            rv = NSS_GetAlgorithmPolicy(algOpt->oid, &value);
   1032            if (rv != SECSuccess) {
   1033                PR_SetEnv("NSS_POLICY_FAIL=1");
   1034                fprintf(stderr, "NSS-POLICY-FAIL: internal failure with NSS_GetAlgorithmPolicy at %u\n", i);
   1035                return;
   1036            }
   1037 
   1038            if ((algOpt->val & NSS_USE_ALG_IN_SSL_KX) && (value & NSS_USE_ALG_IN_SSL_KX)) {
   1039                ++num_kx_enabled;
   1040                anyEnabled = PR_TRUE;
   1041                fprintf(stderr, "NSS-POLICY-INFO: %s is enabled for SSL-KX\n", algOpt->name);
   1042            }
   1043            if ((algOpt->val & NSS_USE_ALG_IN_SSL) && (value & NSS_USE_ALG_IN_SSL)) {
   1044                ++num_ssl_enabled;
   1045                anyEnabled = PR_TRUE;
   1046                fprintf(stderr, "NSS-POLICY-INFO: %s is enabled for SSL\n", algOpt->name);
   1047            }
   1048            if ((algOpt->val & NSS_USE_ALG_IN_CERT_SIGNATURE) &&
   1049                ((value & NSS_USE_CERT_SIGNATURE_OK) == NSS_USE_CERT_SIGNATURE_OK)) {
   1050                ++num_sig_enabled;
   1051                anyEnabled = PR_TRUE;
   1052                fprintf(stderr, "NSS-POLICY-INFO: %s is enabled for CERT-SIGNATURE\n", algOpt->name);
   1053            }
   1054            if (anyEnabled) {
   1055                ++enabledCount[i];
   1056            }
   1057        }
   1058    }
   1059    fprintf(stderr, "NSS-POLICY-%s: NUMBER-OF-SSL-ALG-KX: %u\n", num_kx_enabled ? sInfo : sWarn, num_kx_enabled);
   1060    fprintf(stderr, "NSS-POLICY-%s: NUMBER-OF-SSL-ALG: %u\n", num_ssl_enabled ? sInfo : sWarn, num_ssl_enabled);
   1061    fprintf(stderr, "NSS-POLICY-%s: NUMBER-OF-CERT-SIG: %u\n", num_sig_enabled ? sInfo : sWarn, num_sig_enabled);
   1062    if (!num_kx_enabled || !num_ssl_enabled || !num_sig_enabled) {
   1063        haveWarning = PR_TRUE;
   1064    }
   1065    for (i = 0; i < PR_ARRAY_SIZE(algOptLists); i++) {
   1066        const algListsDef *algOptList = &algOptLists[i];
   1067        fprintf(stderr, "NSS-POLICY-%s: NUMBER-OF-%s: %u\n", enabledCount[i] ? sInfo : sWarn, algOptList->description, enabledCount[i]);
   1068        if (!enabledCount[i] && !algOptList->allowEmpty) {
   1069            haveWarning = PR_TRUE;
   1070        }
   1071    }
   1072    if (haveWarning) {
   1073        PR_SetEnv("NSS_POLICY_WARN=1");
   1074    }
   1075 }
   1076 
   1077 static SECStatus
   1078 secmod_parseCryptoPolicy(const char *policyConfig, PRBool printPolicyFeedback,
   1079                         PRUint32 policyCheckFlags)
   1080 {
   1081    char *args;
   1082    SECStatus rv;
   1083 
   1084    if (policyConfig == NULL) {
   1085        return SECSuccess; /* no policy given */
   1086    }
   1087    /* make sure we initialize the oid table and set all the default policy
   1088     * values first so we can override them here */
   1089    rv = SECOID_Init();
   1090    if (rv != SECSuccess) {
   1091        return rv;
   1092    }
   1093    args = NSSUTIL_ArgGetParamValue("disallow", policyConfig);
   1094    rv = secmod_applyCryptoPolicy(args, NSS_DISALLOW, printPolicyFeedback,
   1095                                  policyCheckFlags);
   1096    if (args)
   1097        PORT_Free(args);
   1098    if (rv != SECSuccess) {
   1099        return rv;
   1100    }
   1101    args = NSSUTIL_ArgGetParamValue("allow", policyConfig);
   1102    rv = secmod_applyCryptoPolicy(args, NSS_ALLOW, printPolicyFeedback,
   1103                                  policyCheckFlags);
   1104    if (args)
   1105        PORT_Free(args);
   1106    if (rv != SECSuccess) {
   1107        return rv;
   1108    }
   1109    args = NSSUTIL_ArgGetParamValue("disable", policyConfig);
   1110    rv = secmod_applyCryptoPolicy(args, NSS_DISABLE, printPolicyFeedback,
   1111                                  policyCheckFlags);
   1112    if (args)
   1113        PORT_Free(args);
   1114    if (rv != SECSuccess) {
   1115        return rv;
   1116    }
   1117    args = NSSUTIL_ArgGetParamValue("enable", policyConfig);
   1118    rv = secmod_applyCryptoPolicy(args, NSS_ENABLE, printPolicyFeedback,
   1119                                  policyCheckFlags);
   1120    if (args)
   1121        PORT_Free(args);
   1122    if (rv != SECSuccess) {
   1123        return rv;
   1124    }
   1125    /* this has to be last. Everything after this will be a noop */
   1126    if (NSSUTIL_ArgHasFlag("flags", "ssl-lock", policyConfig)) {
   1127        PRInt32 locks;
   1128        /* don't overwrite other (future) lock flags */
   1129        rv = NSS_OptionGet(NSS_DEFAULT_LOCKS, &locks);
   1130        if (rv == SECSuccess) {
   1131            rv = NSS_OptionSet(NSS_DEFAULT_LOCKS, locks | NSS_DEFAULT_SSL_LOCK);
   1132        }
   1133        if (rv != SECSuccess) {
   1134            return rv;
   1135        }
   1136    }
   1137    if (NSSUTIL_ArgHasFlag("flags", "policy-lock", policyConfig)) {
   1138        NSS_LockPolicy();
   1139    }
   1140    if (printPolicyFeedback) {
   1141        /* This helps to distinguish configurations that don't contain any
   1142         * policy config= statement. */
   1143        PR_SetEnv("NSS_POLICY_LOADED=1");
   1144        fprintf(stderr, "NSS-POLICY-INFO: LOADED-SUCCESSFULLY\n");
   1145        secmod_sanityCheckCryptoPolicy();
   1146    }
   1147    return rv;
   1148 }
   1149 
   1150 static PRUint32
   1151 secmod_parsePolicyCheckFlags(const char *nss)
   1152 {
   1153    PRUint32 policyCheckFlags = 0;
   1154 
   1155    if (NSSUTIL_ArgHasFlag("flags", "policyCheckIdentifier", nss)) {
   1156        policyCheckFlags |= SECMOD_FLAG_POLICY_CHECK_IDENTIFIER;
   1157    }
   1158 
   1159    if (NSSUTIL_ArgHasFlag("flags", "policyCheckValue", nss)) {
   1160        policyCheckFlags |= SECMOD_FLAG_POLICY_CHECK_VALUE;
   1161    }
   1162 
   1163    return policyCheckFlags;
   1164 }
   1165 
   1166 /*
   1167 * for 3.4 we continue to use the old SECMODModule structure
   1168 */
   1169 SECMODModule *
   1170 SECMOD_CreateModuleEx(const char *library, const char *moduleName,
   1171                      const char *parameters, const char *nss,
   1172                      const char *config)
   1173 {
   1174    SECMODModule *mod;
   1175    SECStatus rv;
   1176    char *slotParams, *ciphers;
   1177    PRBool printPolicyFeedback = NSSUTIL_ArgHasFlag("flags", "printPolicyFeedback", nss);
   1178    PRUint32 policyCheckFlags = secmod_parsePolicyCheckFlags(nss);
   1179 
   1180    rv = secmod_parseCryptoPolicy(config, printPolicyFeedback, policyCheckFlags);
   1181 
   1182    /* do not load the module if policy parsing fails */
   1183    if (rv != SECSuccess) {
   1184        if (printPolicyFeedback) {
   1185            PR_SetEnv("NSS_POLICY_FAIL=1");
   1186            fprintf(stderr, "NSS-POLICY-FAIL: policy config parsing failed, not loading module %s\n", moduleName);
   1187        }
   1188        return NULL;
   1189    }
   1190 
   1191    mod = secmod_NewModule();
   1192    if (mod == NULL)
   1193        return NULL;
   1194 
   1195    mod->commonName = PORT_ArenaStrdup(mod->arena, moduleName ? moduleName : "");
   1196    if (library) {
   1197        mod->dllName = PORT_ArenaStrdup(mod->arena, library);
   1198    }
   1199    /* new field */
   1200    if (parameters) {
   1201        mod->libraryParams = PORT_ArenaStrdup(mod->arena, parameters);
   1202    }
   1203 
   1204    mod->internal = NSSUTIL_ArgHasFlag("flags", "internal", nss);
   1205    mod->isFIPS = NSSUTIL_ArgHasFlag("flags", "FIPS", nss);
   1206    /* if the system FIPS mode is enabled, force FIPS to be on */
   1207    if (SECMOD_GetSystemFIPSEnabled()) {
   1208        mod->isFIPS = PR_TRUE;
   1209    }
   1210    mod->isCritical = NSSUTIL_ArgHasFlag("flags", "critical", nss);
   1211    slotParams = NSSUTIL_ArgGetParamValue("slotParams", nss);
   1212    mod->slotInfo = NSSUTIL_ArgParseSlotInfo(mod->arena, slotParams,
   1213                                             &mod->slotInfoCount);
   1214    if (slotParams)
   1215        PORT_Free(slotParams);
   1216    /* new field */
   1217    mod->trustOrder = NSSUTIL_ArgReadLong("trustOrder", nss,
   1218                                          NSSUTIL_DEFAULT_TRUST_ORDER, NULL);
   1219    /* new field */
   1220    mod->cipherOrder = NSSUTIL_ArgReadLong("cipherOrder", nss,
   1221                                           NSSUTIL_DEFAULT_CIPHER_ORDER, NULL);
   1222    /* new field */
   1223    mod->isModuleDB = NSSUTIL_ArgHasFlag("flags", "moduleDB", nss);
   1224    mod->moduleDBOnly = NSSUTIL_ArgHasFlag("flags", "moduleDBOnly", nss);
   1225    if (mod->moduleDBOnly)
   1226        mod->isModuleDB = PR_TRUE;
   1227 
   1228    /* we need more bits, but we also want to preserve binary compatibility
   1229     * so we overload the isModuleDB PRBool with additional flags.
   1230     * These flags are only valid if mod->isModuleDB is already set.
   1231     * NOTE: this depends on the fact that PRBool is at least a char on
   1232     * all platforms. These flags are only valid if moduleDB is set, so
   1233     * code checking if (mod->isModuleDB) will continue to work correctly. */
   1234    if (mod->isModuleDB) {
   1235        char flags = SECMOD_FLAG_MODULE_DB_IS_MODULE_DB;
   1236        if (NSSUTIL_ArgHasFlag("flags", "skipFirst", nss)) {
   1237            flags |= SECMOD_FLAG_MODULE_DB_SKIP_FIRST;
   1238        }
   1239        if (NSSUTIL_ArgHasFlag("flags", "defaultModDB", nss)) {
   1240            flags |= SECMOD_FLAG_MODULE_DB_DEFAULT_MODDB;
   1241        }
   1242        if (NSSUTIL_ArgHasFlag("flags", "policyOnly", nss)) {
   1243            flags |= SECMOD_FLAG_MODULE_DB_POLICY_ONLY;
   1244        }
   1245        /* additional moduleDB flags could be added here in the future */
   1246        mod->isModuleDB = (PRBool)flags;
   1247    }
   1248 
   1249    if (mod->internal) {
   1250        char flags = SECMOD_FLAG_INTERNAL_IS_INTERNAL;
   1251 
   1252        if (NSSUTIL_ArgHasFlag("flags", "internalKeySlot", nss)) {
   1253            flags |= SECMOD_FLAG_INTERNAL_KEY_SLOT;
   1254        }
   1255        mod->internal = (PRBool)flags;
   1256    }
   1257 
   1258    ciphers = NSSUTIL_ArgGetParamValue("ciphers", nss);
   1259    NSSUTIL_ArgParseCipherFlags(&mod->ssl[0], ciphers);
   1260    if (ciphers)
   1261        PORT_Free(ciphers);
   1262 
   1263    secmod_PrivateModuleCount++;
   1264 
   1265    return mod;
   1266 }
   1267 
   1268 PRBool
   1269 SECMOD_GetSkipFirstFlag(SECMODModule *mod)
   1270 {
   1271    char flags = (char)mod->isModuleDB;
   1272 
   1273    return (flags & SECMOD_FLAG_MODULE_DB_SKIP_FIRST) ? PR_TRUE : PR_FALSE;
   1274 }
   1275 
   1276 PRBool
   1277 SECMOD_GetDefaultModDBFlag(SECMODModule *mod)
   1278 {
   1279    char flags = (char)mod->isModuleDB;
   1280 
   1281    return (flags & SECMOD_FLAG_MODULE_DB_DEFAULT_MODDB) ? PR_TRUE : PR_FALSE;
   1282 }
   1283 
   1284 PRBool
   1285 secmod_PolicyOnly(SECMODModule *mod)
   1286 {
   1287    char flags = (char)mod->isModuleDB;
   1288 
   1289    return (flags & SECMOD_FLAG_MODULE_DB_POLICY_ONLY) ? PR_TRUE : PR_FALSE;
   1290 }
   1291 
   1292 PRBool
   1293 secmod_IsInternalKeySlot(SECMODModule *mod)
   1294 {
   1295    char flags = (char)mod->internal;
   1296 
   1297    return (flags & SECMOD_FLAG_INTERNAL_KEY_SLOT) ? PR_TRUE : PR_FALSE;
   1298 }
   1299 
   1300 void
   1301 secmod_SetInternalKeySlotFlag(SECMODModule *mod, PRBool val)
   1302 {
   1303    char flags = (char)mod->internal;
   1304 
   1305    if (val) {
   1306        flags |= SECMOD_FLAG_INTERNAL_KEY_SLOT;
   1307    } else {
   1308        flags &= ~SECMOD_FLAG_INTERNAL_KEY_SLOT;
   1309    }
   1310    mod->internal = flags;
   1311 }
   1312 
   1313 /*
   1314 * copy desc and value into target. Target is known to be big enough to
   1315 * hold desc +2 +value, which is good because the result of this will be
   1316 * *desc"*value". We may, however, have to add some escapes for special
   1317 * characters imbedded into value (rare). This string potentially comes from
   1318 * a user, so we don't want the user overflowing the target buffer by using
   1319 * excessive escapes. To prevent this we count the escapes we need to add and
   1320 * try to expand the buffer with Realloc.
   1321 */
   1322 static char *
   1323 secmod_doDescCopy(char *target, char **base, int *baseLen,
   1324                  const char *desc, int descLen, char *value)
   1325 {
   1326    int diff, esc_len;
   1327 
   1328    esc_len = NSSUTIL_EscapeSize(value, '\"') - 1;
   1329    diff = esc_len - strlen(value);
   1330    if (diff > 0) {
   1331        /* we need to escape... expand newSpecPtr as well to make sure
   1332         * we don't overflow it */
   1333        int offset = target - *base;
   1334        char *newPtr = PORT_Realloc(*base, *baseLen + diff);
   1335        if (!newPtr) {
   1336            return target; /* not enough space, just drop the whole copy */
   1337        }
   1338        *baseLen += diff;
   1339        target = newPtr + offset;
   1340        *base = newPtr;
   1341        value = NSSUTIL_Escape(value, '\"');
   1342        if (value == NULL) {
   1343            return target; /* couldn't escape value, just drop the copy */
   1344        }
   1345    }
   1346    PORT_Memcpy(target, desc, descLen);
   1347    target += descLen;
   1348    *target++ = '\"';
   1349    PORT_Memcpy(target, value, esc_len);
   1350    target += esc_len;
   1351    *target++ = '\"';
   1352    if (diff > 0) {
   1353        PORT_Free(value);
   1354    }
   1355    return target;
   1356 }
   1357 
   1358 #define SECMOD_SPEC_COPY(new, start, end) \
   1359    if (end > start) {                    \
   1360        int _cnt = end - start;           \
   1361        PORT_Memcpy(new, start, _cnt);    \
   1362        new += _cnt;                      \
   1363    }
   1364 #define SECMOD_TOKEN_DESCRIPTION "tokenDescription="
   1365 #define SECMOD_SLOT_DESCRIPTION "slotDescription="
   1366 
   1367 /*
   1368 * Find any tokens= values in the module spec.
   1369 * Always return a new spec which does not have any tokens= arguments.
   1370 * If tokens= arguments are found, Split the the various tokens defined into
   1371 * an array of child specs to return.
   1372 *
   1373 * Caller is responsible for freeing the child spec and the new token
   1374 * spec.
   1375 */
   1376 char *
   1377 secmod_ParseModuleSpecForTokens(PRBool convert, PRBool isFIPS,
   1378                                const char *moduleSpec, char ***children,
   1379                                CK_SLOT_ID **ids)
   1380 {
   1381    int newSpecLen = PORT_Strlen(moduleSpec) + 2;
   1382    char *newSpec = PORT_Alloc(newSpecLen);
   1383    char *newSpecPtr = newSpec;
   1384    const char *modulePrev = moduleSpec;
   1385    char *target = NULL;
   1386    char *tmp = NULL;
   1387    char **childArray = NULL;
   1388    const char *tokenIndex;
   1389    CK_SLOT_ID *idArray = NULL;
   1390    int tokenCount = 0;
   1391    int i;
   1392 
   1393    if (newSpec == NULL) {
   1394        return NULL;
   1395    }
   1396 
   1397    *children = NULL;
   1398    if (ids) {
   1399        *ids = NULL;
   1400    }
   1401    moduleSpec = NSSUTIL_ArgStrip(moduleSpec);
   1402    SECMOD_SPEC_COPY(newSpecPtr, modulePrev, moduleSpec);
   1403 
   1404    /* Notes on 'convert' and 'isFIPS' flags: The base parameters for opening
   1405     * a new softoken module takes the following parameters to name the
   1406     * various tokens:
   1407     *
   1408     *  cryptoTokenDescription: name of the non-fips crypto token.
   1409     *  cryptoSlotDescription: name of the non-fips crypto slot.
   1410     *  dbTokenDescription: name of the non-fips db token.
   1411     *  dbSlotDescription: name of the non-fips db slot.
   1412     *  FIPSTokenDescription: name of the fips db/crypto token.
   1413     *  FIPSSlotDescription: name of the fips db/crypto slot.
   1414     *
   1415     * if we are opening a new slot, we need to have the following
   1416     * parameters:
   1417     *  tokenDescription: name of the token.
   1418     *  slotDescription: name of the slot.
   1419     *
   1420     *
   1421     * The convert flag tells us to drop the unnecessary *TokenDescription
   1422     * and *SlotDescription arguments and convert the appropriate pair
   1423     * (either db or FIPS based on the isFIPS flag) to tokenDescription and
   1424     * slotDescription).
   1425     */
   1426    /*
   1427     * walk down the list. if we find a tokens= argument, save it,
   1428     * otherise copy the argument.
   1429     */
   1430    while (*moduleSpec) {
   1431        int next;
   1432        modulePrev = moduleSpec;
   1433        NSSUTIL_HANDLE_STRING_ARG(moduleSpec, target, "tokens=",
   1434                                  modulePrev = moduleSpec;
   1435                                  /* skip copying */)
   1436        NSSUTIL_HANDLE_STRING_ARG(
   1437            moduleSpec, tmp, "cryptoTokenDescription=",
   1438            if (convert) { modulePrev = moduleSpec; })
   1439        NSSUTIL_HANDLE_STRING_ARG(
   1440            moduleSpec, tmp, "cryptoSlotDescription=",
   1441            if (convert) { modulePrev = moduleSpec; })
   1442        NSSUTIL_HANDLE_STRING_ARG(
   1443            moduleSpec, tmp, "dbTokenDescription=",
   1444            if (convert) {
   1445                modulePrev = moduleSpec;
   1446                if (!isFIPS) {
   1447                    newSpecPtr = secmod_doDescCopy(newSpecPtr,
   1448                                                   &newSpec, &newSpecLen,
   1449                                                   SECMOD_TOKEN_DESCRIPTION,
   1450                                                   sizeof(SECMOD_TOKEN_DESCRIPTION) - 1,
   1451                                                   tmp);
   1452                }
   1453            })
   1454        NSSUTIL_HANDLE_STRING_ARG(
   1455            moduleSpec, tmp, "dbSlotDescription=",
   1456            if (convert) {
   1457                modulePrev = moduleSpec; /* skip copying */
   1458                if (!isFIPS) {
   1459                    newSpecPtr = secmod_doDescCopy(newSpecPtr,
   1460                                                   &newSpec, &newSpecLen,
   1461                                                   SECMOD_SLOT_DESCRIPTION,
   1462                                                   sizeof(SECMOD_SLOT_DESCRIPTION) - 1,
   1463                                                   tmp);
   1464                }
   1465            })
   1466        NSSUTIL_HANDLE_STRING_ARG(
   1467            moduleSpec, tmp, "FIPSTokenDescription=",
   1468            if (convert) {
   1469                modulePrev = moduleSpec; /* skip copying */
   1470                if (isFIPS) {
   1471                    newSpecPtr = secmod_doDescCopy(newSpecPtr,
   1472                                                   &newSpec, &newSpecLen,
   1473                                                   SECMOD_TOKEN_DESCRIPTION,
   1474                                                   sizeof(SECMOD_TOKEN_DESCRIPTION) - 1,
   1475                                                   tmp);
   1476                }
   1477            })
   1478        NSSUTIL_HANDLE_STRING_ARG(
   1479            moduleSpec, tmp, "FIPSSlotDescription=",
   1480            if (convert) {
   1481                modulePrev = moduleSpec; /* skip copying */
   1482                if (isFIPS) {
   1483                    newSpecPtr = secmod_doDescCopy(newSpecPtr,
   1484                                                   &newSpec, &newSpecLen,
   1485                                                   SECMOD_SLOT_DESCRIPTION,
   1486                                                   sizeof(SECMOD_SLOT_DESCRIPTION) - 1,
   1487                                                   tmp);
   1488                }
   1489            })
   1490        NSSUTIL_HANDLE_FINAL_ARG(moduleSpec)
   1491        SECMOD_SPEC_COPY(newSpecPtr, modulePrev, moduleSpec);
   1492    }
   1493    if (tmp) {
   1494        PORT_Free(tmp);
   1495        tmp = NULL;
   1496    }
   1497    *newSpecPtr = 0;
   1498 
   1499    /* no target found, return the newSpec */
   1500    if (target == NULL) {
   1501        return newSpec;
   1502    }
   1503 
   1504    /* now build the child array from target */
   1505    /*first count them */
   1506    for (tokenIndex = NSSUTIL_ArgStrip(target); *tokenIndex;
   1507         tokenIndex = NSSUTIL_ArgStrip(NSSUTIL_ArgSkipParameter(tokenIndex))) {
   1508        tokenCount++;
   1509    }
   1510 
   1511    childArray = PORT_NewArray(char *, tokenCount + 1);
   1512    if (childArray == NULL) {
   1513        /* just return the spec as is then */
   1514        PORT_Free(target);
   1515        return newSpec;
   1516    }
   1517    if (ids) {
   1518        idArray = PORT_NewArray(CK_SLOT_ID, tokenCount + 1);
   1519        if (idArray == NULL) {
   1520            PORT_Free(childArray);
   1521            PORT_Free(target);
   1522            return newSpec;
   1523        }
   1524    }
   1525 
   1526    /* now fill them in */
   1527    for (tokenIndex = NSSUTIL_ArgStrip(target), i = 0;
   1528         *tokenIndex && (i < tokenCount);
   1529         tokenIndex = NSSUTIL_ArgStrip(tokenIndex)) {
   1530        int next;
   1531        char *name = NSSUTIL_ArgGetLabel(tokenIndex, &next);
   1532        tokenIndex += next;
   1533 
   1534        if (idArray) {
   1535            idArray[i] = NSSUTIL_ArgDecodeNumber(name);
   1536        }
   1537 
   1538        PORT_Free(name); /* drop the explicit number */
   1539 
   1540        /* if anything is left, copy the args to the child array */
   1541        if (!NSSUTIL_ArgIsBlank(*tokenIndex)) {
   1542            childArray[i++] = NSSUTIL_ArgFetchValue(tokenIndex, &next);
   1543            tokenIndex += next;
   1544        }
   1545    }
   1546 
   1547    PORT_Free(target);
   1548    childArray[i] = 0;
   1549    if (idArray) {
   1550        idArray[i] = 0;
   1551    }
   1552 
   1553    /* return it */
   1554    *children = childArray;
   1555    if (ids) {
   1556        *ids = idArray;
   1557    }
   1558    return newSpec;
   1559 }
   1560 
   1561 /* get the database and flags from the spec */
   1562 static char *
   1563 secmod_getConfigDir(const char *spec, char **certPrefix, char **keyPrefix,
   1564                    PRBool *readOnly)
   1565 {
   1566    char *config = NULL;
   1567 
   1568    *certPrefix = NULL;
   1569    *keyPrefix = NULL;
   1570    *readOnly = NSSUTIL_ArgHasFlag("flags", "readOnly", spec);
   1571    if (NSSUTIL_ArgHasFlag("flags", "nocertdb", spec) ||
   1572        NSSUTIL_ArgHasFlag("flags", "nokeydb", spec)) {
   1573        return NULL;
   1574    }
   1575 
   1576    spec = NSSUTIL_ArgStrip(spec);
   1577    while (*spec) {
   1578        int next;
   1579        NSSUTIL_HANDLE_STRING_ARG(spec, config, "configdir=", ;)
   1580        NSSUTIL_HANDLE_STRING_ARG(spec, *certPrefix, "certPrefix=", ;)
   1581        NSSUTIL_HANDLE_STRING_ARG(spec, *keyPrefix, "keyPrefix=", ;)
   1582        NSSUTIL_HANDLE_FINAL_ARG(spec)
   1583    }
   1584    return config;
   1585 }
   1586 
   1587 struct SECMODConfigListStr {
   1588    char *config;
   1589    char *certPrefix;
   1590    char *keyPrefix;
   1591    PRBool isReadOnly;
   1592 };
   1593 
   1594 /*
   1595 * return an array of already openned databases from a spec list.
   1596 */
   1597 SECMODConfigList *
   1598 secmod_GetConfigList(PRBool isFIPS, char *spec, int *count)
   1599 {
   1600    char **children;
   1601    CK_SLOT_ID *ids;
   1602    char *strippedSpec;
   1603    int childCount;
   1604    SECMODConfigList *conflist = NULL;
   1605    int i;
   1606 
   1607    strippedSpec = secmod_ParseModuleSpecForTokens(PR_TRUE, isFIPS,
   1608                                                   spec, &children, &ids);
   1609    if (strippedSpec == NULL) {
   1610        return NULL;
   1611    }
   1612 
   1613    for (childCount = 0; children && children[childCount]; childCount++)
   1614        ;
   1615    *count = childCount + 1; /* include strippedSpec */
   1616    conflist = PORT_NewArray(SECMODConfigList, *count);
   1617    if (conflist == NULL) {
   1618        *count = 0;
   1619        goto loser;
   1620    }
   1621 
   1622    conflist[0].config = secmod_getConfigDir(strippedSpec,
   1623                                             &conflist[0].certPrefix,
   1624                                             &conflist[0].keyPrefix,
   1625                                             &conflist[0].isReadOnly);
   1626    for (i = 0; i < childCount; i++) {
   1627        conflist[i + 1].config = secmod_getConfigDir(children[i],
   1628                                                     &conflist[i + 1].certPrefix,
   1629                                                     &conflist[i + 1].keyPrefix,
   1630                                                     &conflist[i + 1].isReadOnly);
   1631    }
   1632 
   1633 loser:
   1634    secmod_FreeChildren(children, ids);
   1635    PORT_Free(strippedSpec);
   1636    return conflist;
   1637 }
   1638 
   1639 /*
   1640 * determine if we are trying to open an old dbm database. For this test
   1641 * RDB databases should return PR_FALSE.
   1642 */
   1643 static PRBool
   1644 secmod_configIsDBM(char *configDir)
   1645 {
   1646    char *env;
   1647 
   1648    /* explicit dbm open */
   1649    if (strncmp(configDir, "dbm:", 4) == 0) {
   1650        return PR_TRUE;
   1651    }
   1652    /* explicit open of a non-dbm database */
   1653    if ((strncmp(configDir, "sql:", 4) == 0) ||
   1654        (strncmp(configDir, "rdb:", 4) == 0) ||
   1655        (strncmp(configDir, "extern:", 7) == 0)) {
   1656        return PR_FALSE;
   1657    }
   1658    env = PR_GetEnvSecure("NSS_DEFAULT_DB_TYPE");
   1659    /* implicit dbm open */
   1660    if ((env == NULL) || (strcmp(env, "dbm") == 0)) {
   1661        return PR_TRUE;
   1662    }
   1663    /* implicit non-dbm open */
   1664    return PR_FALSE;
   1665 }
   1666 
   1667 /*
   1668 * match two prefixes. prefix may be NULL. NULL patches '\0'
   1669 */
   1670 static PRBool
   1671 secmod_matchPrefix(char *prefix1, char *prefix2)
   1672 {
   1673    if ((prefix1 == NULL) || (*prefix1 == 0)) {
   1674        if ((prefix2 == NULL) || (*prefix2 == 0)) {
   1675            return PR_TRUE;
   1676        }
   1677        return PR_FALSE;
   1678    }
   1679    if (strcmp(prefix1, prefix2) == 0) {
   1680        return PR_TRUE;
   1681    }
   1682    return PR_FALSE;
   1683 }
   1684 
   1685 /* do two config paramters match? Not all callers are compariing
   1686 * SECMODConfigLists directly, so this function breaks them out to their
   1687 * components. */
   1688 static PRBool
   1689 secmod_matchConfig(char *configDir1, char *configDir2,
   1690                   char *certPrefix1, char *certPrefix2,
   1691                   char *keyPrefix1, char *keyPrefix2,
   1692                   PRBool isReadOnly1, PRBool isReadOnly2)
   1693 {
   1694    /* TODO: Document the answer to the question:
   1695     *       "Why not allow them to match if they are both NULL?"
   1696     * See: https://bugzilla.mozilla.org/show_bug.cgi?id=1318633#c1
   1697     */
   1698    if ((configDir1 == NULL) || (configDir2 == NULL)) {
   1699        return PR_FALSE;
   1700    }
   1701    if (strcmp(configDir1, configDir2) != 0) {
   1702        return PR_FALSE;
   1703    }
   1704    if (!secmod_matchPrefix(certPrefix1, certPrefix2)) {
   1705        return PR_FALSE;
   1706    }
   1707    if (!secmod_matchPrefix(keyPrefix1, keyPrefix2)) {
   1708        return PR_FALSE;
   1709    }
   1710    /* these last test -- if we just need the DB open read only,
   1711     * than any open will suffice, but if we requested it read/write
   1712     * and it's only open read only, we need to open it again */
   1713    if (isReadOnly1) {
   1714        return PR_TRUE;
   1715    }
   1716    if (isReadOnly2) { /* isReadonly1 == PR_FALSE */
   1717        return PR_FALSE;
   1718    }
   1719    return PR_TRUE;
   1720 }
   1721 
   1722 /*
   1723 * return true if we are requesting a database that is already openned.
   1724 */
   1725 PRBool
   1726 secmod_MatchConfigList(const char *spec, SECMODConfigList *conflist, int count)
   1727 {
   1728    char *config;
   1729    char *certPrefix;
   1730    char *keyPrefix;
   1731    PRBool isReadOnly;
   1732    PRBool ret = PR_FALSE;
   1733    int i;
   1734 
   1735    config = secmod_getConfigDir(spec, &certPrefix, &keyPrefix, &isReadOnly);
   1736    if (!config) {
   1737        goto done;
   1738    }
   1739 
   1740    /* NOTE: we dbm isn't multiple open safe. If we open the same database
   1741     * twice from two different locations, then we can corrupt our database
   1742     * (the cache will be inconsistent). Protect against this by claiming
   1743     * for comparison only that we are always openning dbm databases read only.
   1744     */
   1745    if (secmod_configIsDBM(config)) {
   1746        isReadOnly = 1;
   1747    }
   1748    for (i = 0; i < count; i++) {
   1749        if (secmod_matchConfig(config, conflist[i].config, certPrefix,
   1750                               conflist[i].certPrefix, keyPrefix,
   1751                               conflist[i].keyPrefix, isReadOnly,
   1752                               conflist[i].isReadOnly)) {
   1753            ret = PR_TRUE;
   1754            goto done;
   1755        }
   1756    }
   1757 
   1758    ret = PR_FALSE;
   1759 done:
   1760    PORT_Free(config);
   1761    PORT_Free(certPrefix);
   1762    PORT_Free(keyPrefix);
   1763    return ret;
   1764 }
   1765 
   1766 /*
   1767 * Find the slot id from the module spec. If the slot is the database slot, we
   1768 * can get the slot id from the default database slot.
   1769 */
   1770 CK_SLOT_ID
   1771 secmod_GetSlotIDFromModuleSpec(const char *moduleSpec, SECMODModule *module)
   1772 {
   1773    char *tmp_spec = NULL;
   1774    char **children, **thisChild;
   1775    CK_SLOT_ID *ids, *thisID, slotID = -1;
   1776    char *inConfig = NULL, *thisConfig = NULL;
   1777    char *inCertPrefix = NULL, *thisCertPrefix = NULL;
   1778    char *inKeyPrefix = NULL, *thisKeyPrefix = NULL;
   1779    PRBool inReadOnly, thisReadOnly;
   1780 
   1781    inConfig = secmod_getConfigDir(moduleSpec, &inCertPrefix, &inKeyPrefix,
   1782                                   &inReadOnly);
   1783    if (!inConfig) {
   1784        goto done;
   1785    }
   1786 
   1787    if (secmod_configIsDBM(inConfig)) {
   1788        inReadOnly = 1;
   1789    }
   1790 
   1791    tmp_spec = secmod_ParseModuleSpecForTokens(PR_TRUE, module->isFIPS,
   1792                                               module->libraryParams, &children, &ids);
   1793    if (tmp_spec == NULL) {
   1794        goto done;
   1795    }
   1796 
   1797    /* first check to see if the parent is the database */
   1798    thisConfig = secmod_getConfigDir(tmp_spec, &thisCertPrefix, &thisKeyPrefix,
   1799                                     &thisReadOnly);
   1800    if (!thisConfig) {
   1801        goto done;
   1802    }
   1803    if (secmod_matchConfig(inConfig, thisConfig, inCertPrefix, thisCertPrefix,
   1804                           inKeyPrefix, thisKeyPrefix, inReadOnly, thisReadOnly)) {
   1805        /* yup it's the default key slot, get the id for it */
   1806        PK11SlotInfo *slot = PK11_GetInternalKeySlot();
   1807        if (slot) {
   1808            slotID = slot->slotID;
   1809            PK11_FreeSlot(slot);
   1810        }
   1811        goto done;
   1812    }
   1813 
   1814    /* find id of the token */
   1815    for (thisChild = children, thisID = ids; thisChild && *thisChild; thisChild++, thisID++) {
   1816        PORT_Free(thisConfig);
   1817        PORT_Free(thisCertPrefix);
   1818        PORT_Free(thisKeyPrefix);
   1819        thisConfig = secmod_getConfigDir(*thisChild, &thisCertPrefix,
   1820                                         &thisKeyPrefix, &thisReadOnly);
   1821        if (thisConfig == NULL) {
   1822            continue;
   1823        }
   1824        if (secmod_matchConfig(inConfig, thisConfig, inCertPrefix, thisCertPrefix,
   1825                               inKeyPrefix, thisKeyPrefix, inReadOnly, thisReadOnly)) {
   1826            slotID = *thisID;
   1827            break;
   1828        }
   1829    }
   1830 
   1831 done:
   1832    PORT_Free(inConfig);
   1833    PORT_Free(inCertPrefix);
   1834    PORT_Free(inKeyPrefix);
   1835    PORT_Free(thisConfig);
   1836    PORT_Free(thisCertPrefix);
   1837    PORT_Free(thisKeyPrefix);
   1838    if (tmp_spec) {
   1839        secmod_FreeChildren(children, ids);
   1840        PORT_Free(tmp_spec);
   1841    }
   1842    return slotID;
   1843 }
   1844 
   1845 void
   1846 secmod_FreeConfigList(SECMODConfigList *conflist, int count)
   1847 {
   1848    int i;
   1849    for (i = 0; i < count; i++) {
   1850        PORT_Free(conflist[i].config);
   1851        PORT_Free(conflist[i].certPrefix);
   1852        PORT_Free(conflist[i].keyPrefix);
   1853    }
   1854    PORT_Free(conflist);
   1855 }
   1856 
   1857 void
   1858 secmod_FreeChildren(char **children, CK_SLOT_ID *ids)
   1859 {
   1860    char **thisChild;
   1861 
   1862    if (!children) {
   1863        return;
   1864    }
   1865 
   1866    for (thisChild = children; thisChild && *thisChild; thisChild++) {
   1867        PORT_Free(*thisChild);
   1868    }
   1869    PORT_Free(children);
   1870    if (ids) {
   1871        PORT_Free(ids);
   1872    }
   1873    return;
   1874 }
   1875 
   1876 /*
   1877 * caclulate the length of each child record:
   1878 * " 0x{id}=<{escaped_child}>"
   1879 */
   1880 static int
   1881 secmod_getChildLength(char *child, CK_SLOT_ID id)
   1882 {
   1883    int length = NSSUTIL_DoubleEscapeSize(child, '>', ']');
   1884    if (id == 0) {
   1885        length++;
   1886    }
   1887    while (id) {
   1888        length++;
   1889        id = id >> 4;
   1890    }
   1891    length += 6; /* {sp}0x[id]=<{child}> */
   1892    return length;
   1893 }
   1894 
   1895 /*
   1896 * Build a child record:
   1897 * " 0x{id}=<{escaped_child}>"
   1898 */
   1899 static SECStatus
   1900 secmod_mkTokenChild(char **next, int *length, char *child, CK_SLOT_ID id)
   1901 {
   1902    int len;
   1903    char *escSpec;
   1904 
   1905    len = PR_snprintf(*next, *length, " 0x%x=<", id);
   1906    if (len < 0) {
   1907        return SECFailure;
   1908    }
   1909    *next += len;
   1910    *length -= len;
   1911    escSpec = NSSUTIL_DoubleEscape(child, '>', ']');
   1912    if (escSpec == NULL) {
   1913        return SECFailure;
   1914    }
   1915    if (*child && (*escSpec == 0)) {
   1916        PORT_Free(escSpec);
   1917        return SECFailure;
   1918    }
   1919    len = strlen(escSpec);
   1920    if (len + 1 > *length) {
   1921        PORT_Free(escSpec);
   1922        return SECFailure;
   1923    }
   1924    PORT_Memcpy(*next, escSpec, len);
   1925    *next += len;
   1926    *length -= len;
   1927    PORT_Free(escSpec);
   1928    **next = '>';
   1929    (*next)++;
   1930    (*length)--;
   1931    return SECSuccess;
   1932 }
   1933 
   1934 #define TOKEN_STRING " tokens=["
   1935 
   1936 char *
   1937 secmod_MkAppendTokensList(PLArenaPool *arena, char *oldParam, char *newToken,
   1938                          CK_SLOT_ID newID, char **children, CK_SLOT_ID *ids)
   1939 {
   1940    char *rawParam = NULL;  /* oldParam with tokens stripped off */
   1941    char *newParam = NULL;  /* space for the return parameter */
   1942    char *nextParam = NULL; /* current end of the new parameter */
   1943    char **oldChildren = NULL;
   1944    CK_SLOT_ID *oldIds = NULL;
   1945    void *mark = NULL; /* mark the arena pool in case we need
   1946                        * to release it */
   1947    int length, i, tmpLen;
   1948    SECStatus rv;
   1949 
   1950    /* first strip out and save the old tokenlist */
   1951    rawParam = secmod_ParseModuleSpecForTokens(PR_FALSE, PR_FALSE,
   1952                                               oldParam, &oldChildren, &oldIds);
   1953    if (!rawParam) {
   1954        goto loser;
   1955    }
   1956 
   1957    /* now calculate the total length of the new buffer */
   1958    /* First the 'fixed stuff', length of rawparam (does not include a NULL),
   1959     * length of the token string (does include the NULL), closing bracket */
   1960    length = strlen(rawParam) + sizeof(TOKEN_STRING) + 1;
   1961    /* now add then length of all the old children */
   1962    for (i = 0; oldChildren && oldChildren[i]; i++) {
   1963        length += secmod_getChildLength(oldChildren[i], oldIds[i]);
   1964    }
   1965 
   1966    /* add the new token */
   1967    length += secmod_getChildLength(newToken, newID);
   1968 
   1969    /* and it's new children */
   1970    for (i = 0; children && children[i]; i++) {
   1971        if (ids[i] == -1) {
   1972            continue;
   1973        }
   1974        length += secmod_getChildLength(children[i], ids[i]);
   1975    }
   1976 
   1977    /* now allocate and build the string */
   1978    mark = PORT_ArenaMark(arena);
   1979    if (!mark) {
   1980        goto loser;
   1981    }
   1982    newParam = PORT_ArenaAlloc(arena, length);
   1983    if (!newParam) {
   1984        goto loser;
   1985    }
   1986 
   1987    PORT_Strcpy(newParam, oldParam);
   1988    tmpLen = strlen(oldParam);
   1989    nextParam = newParam + tmpLen;
   1990    length -= tmpLen;
   1991    PORT_Memcpy(nextParam, TOKEN_STRING, sizeof(TOKEN_STRING) - 1);
   1992    nextParam += sizeof(TOKEN_STRING) - 1;
   1993    length -= sizeof(TOKEN_STRING) - 1;
   1994 
   1995    for (i = 0; oldChildren && oldChildren[i]; i++) {
   1996        rv = secmod_mkTokenChild(&nextParam, &length, oldChildren[i], oldIds[i]);
   1997        if (rv != SECSuccess) {
   1998            goto loser;
   1999        }
   2000    }
   2001 
   2002    rv = secmod_mkTokenChild(&nextParam, &length, newToken, newID);
   2003    if (rv != SECSuccess) {
   2004        goto loser;
   2005    }
   2006 
   2007    for (i = 0; children && children[i]; i++) {
   2008        if (ids[i] == -1) {
   2009            continue;
   2010        }
   2011        rv = secmod_mkTokenChild(&nextParam, &length, children[i], ids[i]);
   2012        if (rv != SECSuccess) {
   2013            goto loser;
   2014        }
   2015    }
   2016 
   2017    if (length < 2) {
   2018        goto loser;
   2019    }
   2020 
   2021    *nextParam++ = ']';
   2022    *nextParam++ = 0;
   2023 
   2024    /* we are going to return newParam now, don't release the mark */
   2025    PORT_ArenaUnmark(arena, mark);
   2026    mark = NULL;
   2027 
   2028 loser:
   2029    if (mark) {
   2030        PORT_ArenaRelease(arena, mark);
   2031        newParam = NULL; /* if the mark is still active,
   2032                          * don't return the param */
   2033    }
   2034    if (rawParam) {
   2035        PORT_Free(rawParam);
   2036    }
   2037    if (oldChildren) {
   2038        secmod_FreeChildren(oldChildren, oldIds);
   2039    }
   2040    return newParam;
   2041 }
   2042 
   2043 static char *
   2044 secmod_mkModuleSpec(SECMODModule *module)
   2045 {
   2046    char *nss = NULL, *modSpec = NULL, **slotStrings = NULL;
   2047    int slotCount, i, si;
   2048    SECMODListLock *moduleLock = SECMOD_GetDefaultModuleListLock();
   2049 
   2050    /* allocate target slot info strings */
   2051    slotCount = 0;
   2052 
   2053    SECMOD_GetReadLock(moduleLock);
   2054    if (module->slotCount) {
   2055        for (i = 0; i < module->slotCount; i++) {
   2056            if (module->slots[i]->defaultFlags != 0) {
   2057                slotCount++;
   2058            }
   2059        }
   2060    } else {
   2061        slotCount = module->slotInfoCount;
   2062    }
   2063 
   2064    slotStrings = (char **)PORT_ZAlloc(slotCount * sizeof(char *));
   2065    if (slotStrings == NULL) {
   2066        SECMOD_ReleaseReadLock(moduleLock);
   2067        goto loser;
   2068    }
   2069 
   2070    /* build the slot info strings */
   2071    if (module->slotCount) {
   2072        for (i = 0, si = 0; i < module->slotCount; i++) {
   2073            if (module->slots[i]->defaultFlags) {
   2074                PORT_Assert(si < slotCount);
   2075                if (si >= slotCount)
   2076                    break;
   2077                slotStrings[si] = NSSUTIL_MkSlotString(module->slots[i]->slotID,
   2078                                                       module->slots[i]->defaultFlags,
   2079                                                       module->slots[i]->timeout,
   2080                                                       module->slots[i]->askpw,
   2081                                                       module->slots[i]->hasRootCerts,
   2082                                                       module->slots[i]->hasRootTrust);
   2083                si++;
   2084            }
   2085        }
   2086    } else {
   2087        for (i = 0; i < slotCount; i++) {
   2088            slotStrings[i] = NSSUTIL_MkSlotString(
   2089                module->slotInfo[i].slotID,
   2090                module->slotInfo[i].defaultFlags,
   2091                module->slotInfo[i].timeout,
   2092                module->slotInfo[i].askpw,
   2093                module->slotInfo[i].hasRootCerts,
   2094                module->slotInfo[i].hasRootTrust);
   2095        }
   2096    }
   2097 
   2098    SECMOD_ReleaseReadLock(moduleLock);
   2099    nss = NSSUTIL_MkNSSString(slotStrings, slotCount, module->internal,
   2100                              module->isFIPS, module->isModuleDB,
   2101                              module->moduleDBOnly, module->isCritical,
   2102                              module->trustOrder, module->cipherOrder,
   2103                              module->ssl[0], module->ssl[1]);
   2104    modSpec = NSSUTIL_MkModuleSpec(module->dllName, module->commonName,
   2105                                   module->libraryParams, nss);
   2106    PORT_Free(slotStrings);
   2107    PR_smprintf_free(nss);
   2108 loser:
   2109    return (modSpec);
   2110 }
   2111 
   2112 char **
   2113 SECMOD_GetModuleSpecList(SECMODModule *module)
   2114 {
   2115    SECMODModuleDBFunc func = (SECMODModuleDBFunc)module->moduleDBFunc;
   2116    if (func) {
   2117        return (*func)(SECMOD_MODULE_DB_FUNCTION_FIND,
   2118                       module->libraryParams, NULL);
   2119    }
   2120    return NULL;
   2121 }
   2122 
   2123 SECStatus
   2124 SECMOD_AddPermDB(SECMODModule *module)
   2125 {
   2126    SECMODModuleDBFunc func;
   2127    char *moduleSpec;
   2128    char **retString;
   2129 
   2130    if (module->parent == NULL)
   2131        return SECFailure;
   2132 
   2133    func = (SECMODModuleDBFunc)module->parent->moduleDBFunc;
   2134    if (func) {
   2135        moduleSpec = secmod_mkModuleSpec(module);
   2136        retString = (*func)(SECMOD_MODULE_DB_FUNCTION_ADD,
   2137                            module->parent->libraryParams, moduleSpec);
   2138        PORT_Free(moduleSpec);
   2139        if (retString != NULL)
   2140            return SECSuccess;
   2141    }
   2142    return SECFailure;
   2143 }
   2144 
   2145 SECStatus
   2146 SECMOD_DeletePermDB(SECMODModule *module)
   2147 {
   2148    SECMODModuleDBFunc func;
   2149    char *moduleSpec;
   2150    char **retString;
   2151 
   2152    if (module->parent == NULL)
   2153        return SECFailure;
   2154 
   2155    func = (SECMODModuleDBFunc)module->parent->moduleDBFunc;
   2156    if (func) {
   2157        moduleSpec = secmod_mkModuleSpec(module);
   2158        retString = (*func)(SECMOD_MODULE_DB_FUNCTION_DEL,
   2159                            module->parent->libraryParams, moduleSpec);
   2160        PORT_Free(moduleSpec);
   2161        if (retString != NULL)
   2162            return SECSuccess;
   2163    }
   2164    return SECFailure;
   2165 }
   2166 
   2167 SECStatus
   2168 SECMOD_FreeModuleSpecList(SECMODModule *module, char **moduleSpecList)
   2169 {
   2170    SECMODModuleDBFunc func = (SECMODModuleDBFunc)module->moduleDBFunc;
   2171    char **retString;
   2172    if (func) {
   2173        retString = (*func)(SECMOD_MODULE_DB_FUNCTION_RELEASE,
   2174                            module->libraryParams, moduleSpecList);
   2175        if (retString != NULL)
   2176            return SECSuccess;
   2177    }
   2178    return SECFailure;
   2179 }
   2180 
   2181 /*
   2182 * load a PKCS#11 module but do not add it to the default NSS trust domain
   2183 */
   2184 SECMODModule *
   2185 SECMOD_LoadModule(char *modulespec, SECMODModule *parent, PRBool recurse)
   2186 {
   2187    char *library = NULL, *moduleName = NULL, *parameters = NULL, *nss = NULL;
   2188    char *config = NULL;
   2189    SECStatus status;
   2190    SECMODModule *module = NULL;
   2191    SECMODModule *oldModule = NULL;
   2192    SECStatus rv;
   2193    PRBool forwardPolicyFeedback = PR_FALSE;
   2194    PRUint32 forwardPolicyCheckFlags;
   2195 
   2196    /* initialize the underlying module structures */
   2197    SECMOD_Init();
   2198 
   2199    status = NSSUTIL_ArgParseModuleSpecEx(modulespec, &library, &moduleName,
   2200                                          &parameters, &nss,
   2201                                          &config);
   2202    if (status != SECSuccess) {
   2203        goto loser;
   2204    }
   2205 
   2206    module = SECMOD_CreateModuleEx(library, moduleName, parameters, nss, config);
   2207    forwardPolicyFeedback = NSSUTIL_ArgHasFlag("flags", "printPolicyFeedback", nss);
   2208    forwardPolicyCheckFlags = secmod_parsePolicyCheckFlags(nss);
   2209 
   2210    if (library)
   2211        PORT_Free(library);
   2212    if (moduleName)
   2213        PORT_Free(moduleName);
   2214    if (parameters)
   2215        PORT_Free(parameters);
   2216    if (nss)
   2217        PORT_Free(nss);
   2218    if (config)
   2219        PORT_Free(config);
   2220    if (!module) {
   2221        goto loser;
   2222    }
   2223 
   2224    /* a policy only stanza doesn't actually get 'loaded'. policy has already
   2225     * been parsed as a side effect of the CreateModuleEx call */
   2226    if (secmod_PolicyOnly(module)) {
   2227        return module;
   2228    }
   2229    if (parent) {
   2230        module->parent = SECMOD_ReferenceModule(parent);
   2231        if (module->internal && secmod_IsInternalKeySlot(parent)) {
   2232            module->internal = parent->internal;
   2233        }
   2234    }
   2235 
   2236    /* load it */
   2237    rv = secmod_LoadPKCS11Module(module, &oldModule);
   2238    if (rv != SECSuccess) {
   2239        goto loser;
   2240    }
   2241 
   2242    /* if we just reload an old module, no need to add it to any lists.
   2243     * we simple release all our references */
   2244    if (oldModule) {
   2245        /* This module already exists, don't link it anywhere. This
   2246         * will probably destroy this module */
   2247        SECMOD_DestroyModule(module);
   2248        return oldModule;
   2249    }
   2250 
   2251    if (recurse && module->isModuleDB) {
   2252        char **moduleSpecList;
   2253        PORT_SetError(0);
   2254 
   2255        moduleSpecList = SECMOD_GetModuleSpecList(module);
   2256        if (moduleSpecList) {
   2257            char **index;
   2258 
   2259            index = moduleSpecList;
   2260            if (*index && SECMOD_GetSkipFirstFlag(module)) {
   2261                index++;
   2262            }
   2263 
   2264            for (; *index; index++) {
   2265                SECMODModule *child;
   2266                if (0 == PORT_Strcmp(*index, modulespec)) {
   2267                    /* avoid trivial infinite recursion */
   2268                    PORT_SetError(SEC_ERROR_NO_MODULE);
   2269                    rv = SECFailure;
   2270                    break;
   2271                }
   2272                if (!forwardPolicyFeedback) {
   2273                    child = SECMOD_LoadModule(*index, module, PR_TRUE);
   2274                } else {
   2275                    /* Add printPolicyFeedback to the nss flags */
   2276                    char *specWithForwards =
   2277                        NSSUTIL_AddNSSFlagToModuleSpec(*index, "printPolicyFeedback");
   2278                    char *tmp;
   2279                    if (forwardPolicyCheckFlags & SECMOD_FLAG_POLICY_CHECK_IDENTIFIER) {
   2280                        tmp = NSSUTIL_AddNSSFlagToModuleSpec(specWithForwards, "policyCheckIdentifier");
   2281                        PORT_Free(specWithForwards);
   2282                        specWithForwards = tmp;
   2283                    }
   2284                    if (forwardPolicyCheckFlags & SECMOD_FLAG_POLICY_CHECK_VALUE) {
   2285                        tmp = NSSUTIL_AddNSSFlagToModuleSpec(specWithForwards, "policyCheckValue");
   2286                        PORT_Free(specWithForwards);
   2287                        specWithForwards = tmp;
   2288                    }
   2289                    child = SECMOD_LoadModule(specWithForwards, module, PR_TRUE);
   2290                    PORT_Free(specWithForwards);
   2291                }
   2292                if (!child)
   2293                    break;
   2294                if (child->isCritical && !child->loaded) {
   2295                    int err = PORT_GetError();
   2296                    if (!err)
   2297                        err = SEC_ERROR_NO_MODULE;
   2298                    SECMOD_DestroyModule(child);
   2299                    PORT_SetError(err);
   2300                    rv = SECFailure;
   2301                    break;
   2302                }
   2303                SECMOD_DestroyModule(child);
   2304            }
   2305            SECMOD_FreeModuleSpecList(module, moduleSpecList);
   2306        } else {
   2307            if (!PORT_GetError())
   2308                PORT_SetError(SEC_ERROR_NO_MODULE);
   2309            rv = SECFailure;
   2310        }
   2311    }
   2312 
   2313    if (rv != SECSuccess) {
   2314        goto loser;
   2315    }
   2316 
   2317    /* inherit the reference */
   2318    if (!module->moduleDBOnly) {
   2319        SECMOD_AddModuleToList(module);
   2320    } else {
   2321        SECMOD_AddModuleToDBOnlyList(module);
   2322    }
   2323 
   2324    /* handle any additional work here */
   2325    return module;
   2326 
   2327 loser:
   2328    if (module) {
   2329        if (module->loaded) {
   2330            SECMOD_UnloadModule(module);
   2331        }
   2332        SECMOD_AddModuleToUnloadList(module);
   2333    }
   2334    return module;
   2335 }
   2336 
   2337 SECMODModule *
   2338 SECMOD_LoadModuleWithFunction(const char *moduleName, CK_C_GetFunctionList fentry)
   2339 {
   2340    SECMODModule *module = NULL;
   2341    SECMODModule *oldModule = NULL;
   2342    SECStatus rv;
   2343 
   2344    /* initialize the underlying module structures */
   2345    SECMOD_Init();
   2346 
   2347    module = secmod_NewModule();
   2348    if (module == NULL) {
   2349        goto loser;
   2350    }
   2351 
   2352    module->commonName = PORT_ArenaStrdup(module->arena, moduleName ? moduleName : "");
   2353    module->internal = PR_FALSE;
   2354    module->isFIPS = PR_FALSE;
   2355    /* if the system FIPS mode is enabled, force FIPS to be on */
   2356    if (SECMOD_GetSystemFIPSEnabled()) {
   2357        module->isFIPS = PR_TRUE;
   2358    }
   2359 
   2360    module->isCritical = PR_FALSE;
   2361    /* new field */
   2362    module->trustOrder = NSSUTIL_DEFAULT_TRUST_ORDER;
   2363    /* new field */
   2364    module->cipherOrder = NSSUTIL_DEFAULT_CIPHER_ORDER;
   2365    /* new field */
   2366    module->isModuleDB = PR_FALSE;
   2367    module->moduleDBOnly = PR_FALSE;
   2368 
   2369    module->ssl[0] = 0;
   2370    module->ssl[1] = 0;
   2371 
   2372    secmod_PrivateModuleCount++;
   2373 
   2374    /* load it */
   2375    rv = secmod_LoadPKCS11ModuleFromFunction(module, &oldModule, fentry);
   2376    if (rv != SECSuccess) {
   2377        goto loser;
   2378    }
   2379 
   2380    /* if we just reload an old module, no need to add it to any lists.
   2381     * we simple release all our references */
   2382    if (oldModule) {
   2383        /* This module already exists, don't link it anywhere. This
   2384         * will probably destroy this module */
   2385        SECMOD_DestroyModule(module);
   2386        return oldModule;
   2387    }
   2388 
   2389    SECMOD_AddModuleToList(module);
   2390    /* handle any additional work here */
   2391    return module;
   2392 
   2393 loser:
   2394    if (module) {
   2395        if (module->loaded) {
   2396            SECMOD_UnloadModule(module);
   2397        }
   2398        SECMOD_AddModuleToUnloadList(module);
   2399    }
   2400    return module;
   2401 }
   2402 
   2403 /*
   2404 * load a PKCS#11 module and add it to the default NSS trust domain
   2405 */
   2406 SECMODModule *
   2407 SECMOD_LoadUserModule(char *modulespec, SECMODModule *parent, PRBool recurse)
   2408 {
   2409    SECStatus rv = SECSuccess;
   2410    SECMODModule *newmod = SECMOD_LoadModule(modulespec, parent, recurse);
   2411    SECMODListLock *moduleLock = SECMOD_GetDefaultModuleListLock();
   2412 
   2413    if (newmod) {
   2414        SECMOD_GetReadLock(moduleLock);
   2415        rv = STAN_AddModuleToDefaultTrustDomain(newmod);
   2416        SECMOD_ReleaseReadLock(moduleLock);
   2417        if (SECSuccess != rv) {
   2418            SECMOD_DestroyModule(newmod);
   2419            return NULL;
   2420        }
   2421    }
   2422    return newmod;
   2423 }
   2424 
   2425 SECMODModule *
   2426 SECMOD_LoadUserModuleWithFunction(const char *moduleName, CK_C_GetFunctionList fentry)
   2427 {
   2428    SECStatus rv = SECSuccess;
   2429    SECMODModule *newmod = SECMOD_LoadModuleWithFunction(moduleName, fentry);
   2430    SECMODListLock *moduleLock = SECMOD_GetDefaultModuleListLock();
   2431 
   2432    if (newmod) {
   2433        SECMOD_GetReadLock(moduleLock);
   2434        rv = STAN_AddModuleToDefaultTrustDomain(newmod);
   2435        SECMOD_ReleaseReadLock(moduleLock);
   2436        if (SECSuccess != rv) {
   2437            SECMOD_DestroyModule(newmod);
   2438            return NULL;
   2439        }
   2440    }
   2441    return newmod;
   2442 }
   2443 
   2444 /*
   2445 * remove the PKCS#11 module from the default NSS trust domain, call
   2446 * C_Finalize, and destroy the module structure
   2447 */
   2448 SECStatus
   2449 SECMOD_UnloadUserModule(SECMODModule *mod)
   2450 {
   2451    SECStatus rv = SECSuccess;
   2452    int atype = 0;
   2453    SECMODListLock *moduleLock = SECMOD_GetDefaultModuleListLock();
   2454    if (!mod) {
   2455        return SECFailure;
   2456    }
   2457 
   2458    SECMOD_GetReadLock(moduleLock);
   2459    rv = STAN_RemoveModuleFromDefaultTrustDomain(mod);
   2460    SECMOD_ReleaseReadLock(moduleLock);
   2461    if (SECSuccess != rv) {
   2462        return SECFailure;
   2463    }
   2464    return SECMOD_DeleteModuleEx(NULL, mod, &atype, PR_FALSE);
   2465 }