Mercurial > trustbridge > nss-cmake-static
diff nss/lib/pk11wrap/pk11pars.c @ 0:1e5118fa0cb1
This is NSS with a Cmake Buildsyste
To compile a static NSS library for Windows we've used the
Chromium-NSS fork and added a Cmake buildsystem to compile
it statically for Windows. See README.chromium for chromium
changes and README.trustbridge for our modifications.
author | Andre Heinecke <andre.heinecke@intevation.de> |
---|---|
date | Mon, 28 Jul 2014 10:47:06 +0200 |
parents | |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/nss/lib/pk11wrap/pk11pars.c Mon Jul 28 10:47:06 2014 +0200 @@ -0,0 +1,1134 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +/* + * The following handles the loading, unloading and management of + * various PCKS #11 modules + */ + +#include <ctype.h> +#include "pkcs11.h" +#include "seccomon.h" +#include "secmod.h" +#include "secmodi.h" +#include "secmodti.h" +#include "pki3hack.h" +#include "secerr.h" + +#include "utilpars.h" + +/* create a new module */ +static SECMODModule * +secmod_NewModule(void) +{ + SECMODModule *newMod; + PLArenaPool *arena; + + + /* create an arena in which dllName and commonName can be + * allocated. + */ + arena = PORT_NewArena(512); + if (arena == NULL) { + return NULL; + } + + newMod = (SECMODModule *)PORT_ArenaAlloc(arena,sizeof (SECMODModule)); + if (newMod == NULL) { + PORT_FreeArena(arena,PR_FALSE); + return NULL; + } + + /* + * initialize of the fields of the module + */ + newMod->arena = arena; + newMod->internal = PR_FALSE; + newMod->loaded = PR_FALSE; + newMod->isFIPS = PR_FALSE; + newMod->dllName = NULL; + newMod->commonName = NULL; + newMod->library = NULL; + newMod->functionList = NULL; + newMod->slotCount = 0; + newMod->slots = NULL; + newMod->slotInfo = NULL; + newMod->slotInfoCount = 0; + newMod->refCount = 1; + newMod->ssl[0] = 0; + newMod->ssl[1] = 0; + newMod->libraryParams = NULL; + newMod->moduleDBFunc = NULL; + newMod->parent = NULL; + newMod->isCritical = PR_FALSE; + newMod->isModuleDB = PR_FALSE; + newMod->moduleDBOnly = PR_FALSE; + newMod->trustOrder = 0; + newMod->cipherOrder = 0; + newMod->evControlMask = 0; + newMod->refLock = PZ_NewLock(nssILockRefLock); + if (newMod->refLock == NULL) { + PORT_FreeArena(arena,PR_FALSE); + return NULL; + } + return newMod; + +} + +/* private flags for isModuleDB (field in SECMODModule). */ +/* The meaing of these flags is as follows: + * + * SECMOD_FLAG_MODULE_DB_IS_MODULE_DB - This is a module that accesses the + * database of other modules to load. Module DBs are loadable modules that + * tells NSS which PKCS #11 modules to load and when. These module DBs are + * chainable. That is, one module DB can load another one. NSS system init + * design takes advantage of this feature. In system NSS, a fixed system + * module DB loads the system defined libraries, then chains out to the + * traditional module DBs to load any system or user configured modules + * (like smart cards). This bit is the same as the already existing meaning + * of isModuleDB = PR_TRUE. None of the other module db flags should be set + * if this flag isn't on. + * + * SECMOD_FLAG_MODULE_DB_SKIP_FIRST - This flag tells NSS to skip the first + * PKCS #11 module presented by a module DB. This allows the OS to load a + * softoken from the system module, then ask the existing module DB code to + * load the other PKCS #11 modules in that module DB (skipping it's request + * to load softoken). This gives the system init finer control over the + * configuration of that softoken module. + * + * SECMOD_FLAG_MODULE_DB_DEFAULT_MODDB - This flag allows system init to mark a + * different module DB as the 'default' module DB (the one in which + * 'Add module' changes will go). Without this flag NSS takes the first + * module as the default Module DB, but in system NSS, that first module + * is the system module, which is likely read only (at least to the user). + * This allows system NSS to delegate those changes to the user's module DB, + * preserving the user's ability to load new PKCS #11 modules (which only + * affect him), from existing applications like Firefox. + */ +#define SECMOD_FLAG_MODULE_DB_IS_MODULE_DB 0x01 /* must be set if any of the + *other flags are set */ +#define SECMOD_FLAG_MODULE_DB_SKIP_FIRST 0x02 +#define SECMOD_FLAG_MODULE_DB_DEFAULT_MODDB 0x04 + + +/* private flags for internal (field in SECMODModule). */ +/* The meaing of these flags is as follows: + * + * SECMOD_FLAG_INTERNAL_IS_INTERNAL - This is a marks the the module is + * the internal module (that is, softoken). This bit is the same as the + * already existing meaning of internal = PR_TRUE. None of the other + * internal flags should be set if this flag isn't on. + * + * SECMOD_FLAG_MODULE_INTERNAL_KEY_SLOT - This flag allows system init to mark + * a different slot returned byt PK11_GetInternalKeySlot(). The 'primary' + * slot defined by this module will be the new internal key slot. + */ +#define SECMOD_FLAG_INTERNAL_IS_INTERNAL 0x01 /* must be set if any of + *the other flags are set */ +#define SECMOD_FLAG_INTERNAL_KEY_SLOT 0x02 + +/* + * for 3.4 we continue to use the old SECMODModule structure + */ +SECMODModule * +SECMOD_CreateModule(const char *library, const char *moduleName, + const char *parameters, const char *nss) +{ + SECMODModule *mod = secmod_NewModule(); + char *slotParams,*ciphers; + /* pk11pars.h still does not have const char * interfaces */ + char *nssc = (char *)nss; + if (mod == NULL) return NULL; + + mod->commonName = PORT_ArenaStrdup(mod->arena,moduleName ? moduleName : ""); + if (library) { + mod->dllName = PORT_ArenaStrdup(mod->arena,library); + } + /* new field */ + if (parameters) { + mod->libraryParams = PORT_ArenaStrdup(mod->arena,parameters); + } + mod->internal = NSSUTIL_ArgHasFlag("flags","internal",nssc); + mod->isFIPS = NSSUTIL_ArgHasFlag("flags","FIPS",nssc); + mod->isCritical = NSSUTIL_ArgHasFlag("flags","critical",nssc); + slotParams = NSSUTIL_ArgGetParamValue("slotParams",nssc); + mod->slotInfo = NSSUTIL_ArgParseSlotInfo(mod->arena,slotParams, + &mod->slotInfoCount); + if (slotParams) PORT_Free(slotParams); + /* new field */ + mod->trustOrder = NSSUTIL_ArgReadLong("trustOrder",nssc, + NSSUTIL_DEFAULT_TRUST_ORDER,NULL); + /* new field */ + mod->cipherOrder = NSSUTIL_ArgReadLong("cipherOrder",nssc, + NSSUTIL_DEFAULT_CIPHER_ORDER,NULL); + /* new field */ + mod->isModuleDB = NSSUTIL_ArgHasFlag("flags","moduleDB",nssc); + mod->moduleDBOnly = NSSUTIL_ArgHasFlag("flags","moduleDBOnly",nssc); + if (mod->moduleDBOnly) mod->isModuleDB = PR_TRUE; + + /* we need more bits, but we also want to preserve binary compatibility + * so we overload the isModuleDB PRBool with additional flags. + * These flags are only valid if mod->isModuleDB is already set. + * NOTE: this depends on the fact that PRBool is at least a char on + * all platforms. These flags are only valid if moduleDB is set, so + * code checking if (mod->isModuleDB) will continue to work correctly. */ + if (mod->isModuleDB) { + char flags = SECMOD_FLAG_MODULE_DB_IS_MODULE_DB; + if (NSSUTIL_ArgHasFlag("flags","skipFirst",nssc)) { + flags |= SECMOD_FLAG_MODULE_DB_SKIP_FIRST; + } + if (NSSUTIL_ArgHasFlag("flags","defaultModDB",nssc)) { + flags |= SECMOD_FLAG_MODULE_DB_DEFAULT_MODDB; + } + /* additional moduleDB flags could be added here in the future */ + mod->isModuleDB = (PRBool) flags; + } + + if (mod->internal) { + char flags = SECMOD_FLAG_INTERNAL_IS_INTERNAL; + + if (NSSUTIL_ArgHasFlag("flags", "internalKeySlot", nssc)) { + flags |= SECMOD_FLAG_INTERNAL_KEY_SLOT; + } + mod->internal = (PRBool) flags; + } + + ciphers = NSSUTIL_ArgGetParamValue("ciphers",nssc); + NSSUTIL_ArgParseCipherFlags(&mod->ssl[0],ciphers); + if (ciphers) PORT_Free(ciphers); + + secmod_PrivateModuleCount++; + + return mod; +} + +PRBool +SECMOD_GetSkipFirstFlag(SECMODModule *mod) +{ + char flags = (char) mod->isModuleDB; + + return (flags & SECMOD_FLAG_MODULE_DB_SKIP_FIRST) ? PR_TRUE : PR_FALSE; +} + +PRBool +SECMOD_GetDefaultModDBFlag(SECMODModule *mod) +{ + char flags = (char) mod->isModuleDB; + + return (flags & SECMOD_FLAG_MODULE_DB_DEFAULT_MODDB) ? PR_TRUE : PR_FALSE; +} + +PRBool +secmod_IsInternalKeySlot(SECMODModule *mod) +{ + char flags = (char) mod->internal; + + return (flags & SECMOD_FLAG_INTERNAL_KEY_SLOT) ? PR_TRUE : PR_FALSE; +} + +void +secmod_SetInternalKeySlotFlag(SECMODModule *mod, PRBool val) +{ + char flags = (char) mod->internal; + + if (val) { + flags |= SECMOD_FLAG_INTERNAL_KEY_SLOT; + } else { + flags &= ~SECMOD_FLAG_INTERNAL_KEY_SLOT; + } + mod->internal = flags; +} + +/* + * copy desc and value into target. Target is known to be big enough to + * hold desc +2 +value, which is good because the result of this will be + * *desc"*value". We may, however, have to add some escapes for special + * characters imbedded into value (rare). This string potentially comes from + * a user, so we don't want the user overflowing the target buffer by using + * excessive escapes. To prevent this we count the escapes we need to add and + * try to expand the buffer with Realloc. + */ +static char * +secmod_doDescCopy(char *target, int *targetLen, const char *desc, + int descLen, char *value) +{ + int diff, esc_len; + + esc_len = NSSUTIL_EscapeSize(value, '\"') - 1; + diff = esc_len - strlen(value); + if (diff > 0) { + /* we need to escape... expand newSpecPtr as well to make sure + * we don't overflow it */ + char *newPtr = PORT_Realloc(target, *targetLen * diff); + if (!newPtr) { + return target; /* not enough space, just drop the whole copy */ + } + *targetLen += diff; + target = newPtr; + value = NSSUTIL_Escape(value, '\"'); + if (value == NULL) { + return target; /* couldn't escape value, just drop the copy */ + } + } + PORT_Memcpy(target, desc, descLen); + target += descLen; + *target++='\"'; + PORT_Memcpy(target, value, esc_len); + target += esc_len; + *target++='\"'; + if (diff > 0) { + PORT_Free(value); + } + return target; +} + +#define SECMOD_SPEC_COPY(new, start, end) \ + if (end > start) { \ + int _cnt = end - start; \ + PORT_Memcpy(new, start, _cnt); \ + new += _cnt; \ + } +#define SECMOD_TOKEN_DESCRIPTION "tokenDescription=" +#define SECMOD_SLOT_DESCRIPTION "slotDescription=" + + +/* + * Find any tokens= values in the module spec. + * Always return a new spec which does not have any tokens= arguments. + * If tokens= arguments are found, Split the the various tokens defined into + * an array of child specs to return. + * + * Caller is responsible for freeing the child spec and the new token + * spec. + */ +char * +secmod_ParseModuleSpecForTokens(PRBool convert, PRBool isFIPS, + char *moduleSpec, char ***children, + CK_SLOT_ID **ids) +{ + int newSpecLen = PORT_Strlen(moduleSpec)+2; + char *newSpec = PORT_Alloc(newSpecLen); + char *newSpecPtr = newSpec; + char *modulePrev = moduleSpec; + char *target = NULL; + char *tmp = NULL; + char **childArray = NULL; + char *tokenIndex; + CK_SLOT_ID *idArray = NULL; + int tokenCount = 0; + int i; + + if (newSpec == NULL) { + return NULL; + } + + *children = NULL; + if (ids) { + *ids = NULL; + } + moduleSpec = NSSUTIL_ArgStrip(moduleSpec); + SECMOD_SPEC_COPY(newSpecPtr, modulePrev, moduleSpec); + + /* Notes on 'convert' and 'isFIPS' flags: The base parameters for opening + * a new softoken module takes the following parameters to name the + * various tokens: + * + * cryptoTokenDescription: name of the non-fips crypto token. + * cryptoSlotDescription: name of the non-fips crypto slot. + * dbTokenDescription: name of the non-fips db token. + * dbSlotDescription: name of the non-fips db slot. + * FIPSTokenDescription: name of the fips db/crypto token. + * FIPSSlotDescription: name of the fips db/crypto slot. + * + * if we are opening a new slot, we need to have the following + * parameters: + * tokenDescription: name of the token. + * slotDescription: name of the slot. + * + * + * The convert flag tells us to drop the unnecessary *TokenDescription + * and *SlotDescription arguments and convert the appropriate pair + * (either db or FIPS based on the isFIPS flag) to tokenDescription and + * slotDescription). + */ + /* + * walk down the list. if we find a tokens= argument, save it, + * otherise copy the argument. + */ + while (*moduleSpec) { + int next; + modulePrev = moduleSpec; + NSSUTIL_HANDLE_STRING_ARG(moduleSpec, target, "tokens=", + modulePrev = moduleSpec; /* skip copying */ ) + NSSUTIL_HANDLE_STRING_ARG(moduleSpec, tmp, "cryptoTokenDescription=", + if (convert) { modulePrev = moduleSpec; } ); + NSSUTIL_HANDLE_STRING_ARG(moduleSpec, tmp, "cryptoSlotDescription=", + if (convert) { modulePrev = moduleSpec; } ); + NSSUTIL_HANDLE_STRING_ARG(moduleSpec, tmp, "dbTokenDescription=", + if (convert) { + modulePrev = moduleSpec; + if (!isFIPS) { + newSpecPtr = secmod_doDescCopy(newSpecPtr, + &newSpecLen, SECMOD_TOKEN_DESCRIPTION, + sizeof(SECMOD_TOKEN_DESCRIPTION)-1, tmp); + } + }); + NSSUTIL_HANDLE_STRING_ARG(moduleSpec, tmp, "dbSlotDescription=", + if (convert) { + modulePrev = moduleSpec; /* skip copying */ + if (!isFIPS) { + newSpecPtr = secmod_doDescCopy(newSpecPtr, + &newSpecLen, SECMOD_SLOT_DESCRIPTION, + sizeof(SECMOD_SLOT_DESCRIPTION)-1, tmp); + } + } ); + NSSUTIL_HANDLE_STRING_ARG(moduleSpec, tmp, "FIPSTokenDescription=", + if (convert) { + modulePrev = moduleSpec; /* skip copying */ + if (isFIPS) { + newSpecPtr = secmod_doDescCopy(newSpecPtr, + &newSpecLen, SECMOD_TOKEN_DESCRIPTION, + sizeof(SECMOD_TOKEN_DESCRIPTION)-1, tmp); + } + } ); + NSSUTIL_HANDLE_STRING_ARG(moduleSpec, tmp, "FIPSSlotDescription=", + if (convert) { + modulePrev = moduleSpec; /* skip copying */ + if (isFIPS) { + newSpecPtr = secmod_doDescCopy(newSpecPtr, + &newSpecLen, SECMOD_SLOT_DESCRIPTION, + sizeof(SECMOD_SLOT_DESCRIPTION)-1, tmp); + } + } ); + NSSUTIL_HANDLE_FINAL_ARG(moduleSpec) + SECMOD_SPEC_COPY(newSpecPtr, modulePrev, moduleSpec); + } + if (tmp) { + PORT_Free(tmp); + tmp = NULL; + } + *newSpecPtr = 0; + + /* no target found, return the newSpec */ + if (target == NULL) { + return newSpec; + } + + /* now build the child array from target */ + /*first count them */ + for (tokenIndex = NSSUTIL_ArgStrip(target); *tokenIndex; + tokenIndex = NSSUTIL_ArgStrip(NSSUTIL_ArgSkipParameter(tokenIndex))) { + tokenCount++; + } + + childArray = PORT_NewArray(char *, tokenCount+1); + if (childArray == NULL) { + /* just return the spec as is then */ + PORT_Free(target); + return newSpec; + } + if (ids) { + idArray = PORT_NewArray(CK_SLOT_ID, tokenCount+1); + if (idArray == NULL) { + PORT_Free(childArray); + PORT_Free(target); + return newSpec; + } + } + + /* now fill them in */ + for (tokenIndex = NSSUTIL_ArgStrip(target), i=0 ; + *tokenIndex && (i < tokenCount); + tokenIndex=NSSUTIL_ArgStrip(tokenIndex)) { + int next; + char *name = NSSUTIL_ArgGetLabel(tokenIndex, &next); + tokenIndex += next; + + if (idArray) { + idArray[i] = NSSUTIL_ArgDecodeNumber(name); + } + + PORT_Free(name); /* drop the explicit number */ + + /* if anything is left, copy the args to the child array */ + if (!NSSUTIL_ArgIsBlank(*tokenIndex)) { + childArray[i++] = NSSUTIL_ArgFetchValue(tokenIndex, &next); + tokenIndex += next; + } + } + + PORT_Free(target); + childArray[i] = 0; + if (idArray) { + idArray[i] = 0; + } + + /* return it */ + *children = childArray; + if (ids) { + *ids = idArray; + } + return newSpec; +} + +/* get the database and flags from the spec */ +static char * +secmod_getConfigDir(char *spec, char **certPrefix, char **keyPrefix, + PRBool *readOnly) +{ + char * config = NULL; + + *certPrefix = NULL; + *keyPrefix = NULL; + *readOnly = NSSUTIL_ArgHasFlag("flags","readOnly",spec); + + spec = NSSUTIL_ArgStrip(spec); + while (*spec) { + int next; + NSSUTIL_HANDLE_STRING_ARG(spec, config, "configdir=", ;) + NSSUTIL_HANDLE_STRING_ARG(spec, *certPrefix, "certPrefix=", ;) + NSSUTIL_HANDLE_STRING_ARG(spec, *keyPrefix, "keyPrefix=", ;) + NSSUTIL_HANDLE_FINAL_ARG(spec) + } + return config; +} + +struct SECMODConfigListStr { + char *config; + char *certPrefix; + char *keyPrefix; + PRBool isReadOnly; +}; + +/* + * return an array of already openned databases from a spec list. + */ +SECMODConfigList * +secmod_GetConfigList(PRBool isFIPS, char *spec, int *count) +{ + char **children; + CK_SLOT_ID *ids; + char *strippedSpec; + int childCount; + SECMODConfigList *conflist = NULL; + int i; + + strippedSpec = secmod_ParseModuleSpecForTokens(PR_TRUE, isFIPS, + spec,&children,&ids); + if (strippedSpec == NULL) { + return NULL; + } + + for (childCount=0; children && children[childCount]; childCount++) ; + *count = childCount+1; /* include strippedSpec */ + conflist = PORT_NewArray(SECMODConfigList,*count); + if (conflist == NULL) { + *count = 0; + goto loser; + } + + conflist[0].config = secmod_getConfigDir(strippedSpec, + &conflist[0].certPrefix, + &conflist[0].keyPrefix, + &conflist[0].isReadOnly); + for (i=0; i < childCount; i++) { + conflist[i+1].config = secmod_getConfigDir(children[i], + &conflist[i+1].certPrefix, + &conflist[i+1].keyPrefix, + &conflist[i+1].isReadOnly); + } + +loser: + secmod_FreeChildren(children, ids); + PORT_Free(strippedSpec); + return conflist; +} + +/* + * determine if we are trying to open an old dbm database. For this test + * RDB databases should return PR_FALSE. + */ +static PRBool +secmod_configIsDBM(char *configDir) +{ + char *env; + + /* explicit dbm open */ + if (strncmp(configDir, "dbm:", 4) == 0) { + return PR_TRUE; + } + /* explicit open of a non-dbm database */ + if ((strncmp(configDir, "sql:",4) == 0) + || (strncmp(configDir, "rdb:", 4) == 0) + || (strncmp(configDir, "extern:", 7) == 0)) { + return PR_FALSE; + } + env = PR_GetEnv("NSS_DEFAULT_DB_TYPE"); + /* implicit dbm open */ + if ((env == NULL) || (strcmp(env,"dbm") == 0)) { + return PR_TRUE; + } + /* implicit non-dbm open */ + return PR_FALSE; +} + +/* + * match two prefixes. prefix may be NULL. NULL patches '\0' + */ +static PRBool +secmod_matchPrefix(char *prefix1, char *prefix2) +{ + if ((prefix1 == NULL) || (*prefix1 == 0)) { + if ((prefix2 == NULL) || (*prefix2 == 0)) { + return PR_TRUE; + } + return PR_FALSE; + } + if (strcmp(prefix1, prefix2) == 0) { + return PR_TRUE; + } + return PR_FALSE; +} + +/* + * return true if we are requesting a database that is already openned. + */ +PRBool +secmod_MatchConfigList(char *spec, SECMODConfigList *conflist, int count) +{ + char *config; + char *certPrefix; + char *keyPrefix; + PRBool isReadOnly; + PRBool ret=PR_FALSE; + int i; + + config = secmod_getConfigDir(spec, &certPrefix, &keyPrefix, &isReadOnly); + if (!config) { + ret=PR_TRUE; + goto done; + } + + /* NOTE: we dbm isn't multiple open safe. If we open the same database + * twice from two different locations, then we can corrupt our database + * (the cache will be inconsistent). Protect against this by claiming + * for comparison only that we are always openning dbm databases read only. + */ + if (secmod_configIsDBM(config)) { + isReadOnly = 1; + } + for (i=0; i < count; i++) { + if ((strcmp(config,conflist[i].config) == 0) && + secmod_matchPrefix(certPrefix, conflist[i].certPrefix) && + secmod_matchPrefix(keyPrefix, conflist[i].keyPrefix) && + /* this last test -- if we just need the DB open read only, + * than any open will suffice, but if we requested it read/write + * and it's only open read only, we need to open it again */ + (isReadOnly || !conflist[i].isReadOnly)) { + ret = PR_TRUE; + goto done; + } + } + + ret = PR_FALSE; +done: + PORT_Free(config); + PORT_Free(certPrefix); + PORT_Free(keyPrefix); + return ret; +} + +void +secmod_FreeConfigList(SECMODConfigList *conflist, int count) +{ + int i; + for (i=0; i < count; i++) { + PORT_Free(conflist[i].config); + PORT_Free(conflist[i].certPrefix); + PORT_Free(conflist[i].keyPrefix); + } + PORT_Free(conflist); +} + +void +secmod_FreeChildren(char **children, CK_SLOT_ID *ids) +{ + char **thisChild; + + if (!children) { + return; + } + + for (thisChild = children; thisChild && *thisChild; thisChild++ ) { + PORT_Free(*thisChild); + } + PORT_Free(children); + if (ids) { + PORT_Free(ids); + } + return; +} + +/* + * caclulate the length of each child record: + * " 0x{id}=<{escaped_child}>" + */ +static int +secmod_getChildLength(char *child, CK_SLOT_ID id) +{ + int length = NSSUTIL_DoubleEscapeSize(child, '>', ']'); + if (id == 0) { + length++; + } + while (id) { + length++; + id = id >> 4; + } + length += 6; /* {sp}0x[id]=<{child}> */ + return length; +} + +/* + * Build a child record: + * " 0x{id}=<{escaped_child}>" + */ +static SECStatus +secmod_mkTokenChild(char **next, int *length, char *child, CK_SLOT_ID id) +{ + int len; + char *escSpec; + + len = PR_snprintf(*next, *length, " 0x%x=<",id); + if (len < 0) { + return SECFailure; + } + *next += len; + *length -= len; + escSpec = NSSUTIL_DoubleEscape(child, '>', ']'); + if (escSpec == NULL) { + return SECFailure; + } + if (*child && (*escSpec == 0)) { + PORT_Free(escSpec); + return SECFailure; + } + len = strlen(escSpec); + if (len+1 > *length) { + PORT_Free(escSpec); + return SECFailure; + } + PORT_Memcpy(*next,escSpec, len); + *next += len; + *length -= len; + PORT_Free(escSpec); + **next = '>'; + (*next)++; + (*length)--; + return SECSuccess; +} + +#define TOKEN_STRING " tokens=[" + +char * +secmod_MkAppendTokensList(PLArenaPool *arena, char *oldParam, char *newToken, + CK_SLOT_ID newID, char **children, CK_SLOT_ID *ids) +{ + char *rawParam = NULL; /* oldParam with tokens stripped off */ + char *newParam = NULL; /* space for the return parameter */ + char *nextParam = NULL; /* current end of the new parameter */ + char **oldChildren = NULL; + CK_SLOT_ID *oldIds = NULL; + void *mark = NULL; /* mark the arena pool in case we need + * to release it */ + int length, i, tmpLen; + SECStatus rv; + + /* first strip out and save the old tokenlist */ + rawParam = secmod_ParseModuleSpecForTokens(PR_FALSE,PR_FALSE, + oldParam,&oldChildren,&oldIds); + if (!rawParam) { + goto loser; + } + + /* now calculate the total length of the new buffer */ + /* First the 'fixed stuff', length of rawparam (does not include a NULL), + * length of the token string (does include the NULL), closing bracket */ + length = strlen(rawParam) + sizeof(TOKEN_STRING) + 1; + /* now add then length of all the old children */ + for (i=0; oldChildren && oldChildren[i]; i++) { + length += secmod_getChildLength(oldChildren[i], oldIds[i]); + } + + /* add the new token */ + length += secmod_getChildLength(newToken, newID); + + /* and it's new children */ + for (i=0; children && children[i]; i++) { + if (ids[i] == -1) { + continue; + } + length += secmod_getChildLength(children[i], ids[i]); + } + + /* now allocate and build the string */ + mark = PORT_ArenaMark(arena); + if (!mark) { + goto loser; + } + newParam = PORT_ArenaAlloc(arena,length); + if (!newParam) { + goto loser; + } + + PORT_Strcpy(newParam, oldParam); + tmpLen = strlen(oldParam); + nextParam = newParam + tmpLen; + length -= tmpLen; + PORT_Memcpy(nextParam, TOKEN_STRING, sizeof(TOKEN_STRING)-1); + nextParam += sizeof(TOKEN_STRING)-1; + length -= sizeof(TOKEN_STRING)-1; + + for (i=0; oldChildren && oldChildren[i]; i++) { + rv = secmod_mkTokenChild(&nextParam,&length,oldChildren[i],oldIds[i]); + if (rv != SECSuccess) { + goto loser; + } + } + + rv = secmod_mkTokenChild(&nextParam, &length, newToken, newID); + if (rv != SECSuccess) { + goto loser; + } + + for (i=0; children && children[i]; i++) { + if (ids[i] == -1) { + continue; + } + rv = secmod_mkTokenChild(&nextParam, &length, children[i], ids[i]); + if (rv != SECSuccess) { + goto loser; + } + } + + if (length < 2) { + goto loser; + } + + *nextParam++ = ']'; + *nextParam++ = 0; + + /* we are going to return newParam now, don't release the mark */ + PORT_ArenaUnmark(arena, mark); + mark = NULL; + +loser: + if (mark) { + PORT_ArenaRelease(arena, mark); + newParam = NULL; /* if the mark is still active, + * don't return the param */ + } + if (rawParam) { + PORT_Free(rawParam); + } + if (oldChildren) { + secmod_FreeChildren(oldChildren, oldIds); + } + return newParam; +} + +static char * +secmod_mkModuleSpec(SECMODModule * module) +{ + char *nss = NULL, *modSpec = NULL, **slotStrings = NULL; + int slotCount, i, si; + SECMODListLock *moduleLock = SECMOD_GetDefaultModuleListLock(); + + /* allocate target slot info strings */ + slotCount = 0; + + SECMOD_GetReadLock(moduleLock); + if (module->slotCount) { + for (i=0; i < module->slotCount; i++) { + if (module->slots[i]->defaultFlags !=0) { + slotCount++; + } + } + } else { + slotCount = module->slotInfoCount; + } + + slotStrings = (char **)PORT_ZAlloc(slotCount*sizeof(char *)); + if (slotStrings == NULL) { + SECMOD_ReleaseReadLock(moduleLock); + goto loser; + } + + + /* build the slot info strings */ + if (module->slotCount) { + for (i=0, si= 0; i < module->slotCount; i++) { + if (module->slots[i]->defaultFlags) { + PORT_Assert(si < slotCount); + if (si >= slotCount) break; + slotStrings[si] = NSSUTIL_MkSlotString(module->slots[i]->slotID, + module->slots[i]->defaultFlags, + module->slots[i]->timeout, + module->slots[i]->askpw, + module->slots[i]->hasRootCerts, + module->slots[i]->hasRootTrust); + si++; + } + } + } else { + for (i=0; i < slotCount; i++) { + slotStrings[i] = NSSUTIL_MkSlotString( + module->slotInfo[i].slotID, + module->slotInfo[i].defaultFlags, + module->slotInfo[i].timeout, + module->slotInfo[i].askpw, + module->slotInfo[i].hasRootCerts, + module->slotInfo[i].hasRootTrust); + } + } + + SECMOD_ReleaseReadLock(moduleLock); + nss = NSSUTIL_MkNSSString(slotStrings,slotCount,module->internal, + module->isFIPS, module->isModuleDB, + module->moduleDBOnly, module->isCritical, + module->trustOrder, module->cipherOrder, + module->ssl[0],module->ssl[1]); + modSpec= NSSUTIL_MkModuleSpec(module->dllName,module->commonName, + module->libraryParams,nss); + PORT_Free(slotStrings); + PR_smprintf_free(nss); +loser: + return (modSpec); +} + + +char ** +SECMOD_GetModuleSpecList(SECMODModule *module) +{ + SECMODModuleDBFunc func = (SECMODModuleDBFunc) module->moduleDBFunc; + if (func) { + return (*func)(SECMOD_MODULE_DB_FUNCTION_FIND, + module->libraryParams,NULL); + } + return NULL; +} + +SECStatus +SECMOD_AddPermDB(SECMODModule *module) +{ + SECMODModuleDBFunc func; + char *moduleSpec; + char **retString; + + if (module->parent == NULL) return SECFailure; + + func = (SECMODModuleDBFunc) module->parent->moduleDBFunc; + if (func) { + moduleSpec = secmod_mkModuleSpec(module); + retString = (*func)(SECMOD_MODULE_DB_FUNCTION_ADD, + module->parent->libraryParams,moduleSpec); + PORT_Free(moduleSpec); + if (retString != NULL) return SECSuccess; + } + return SECFailure; +} + +SECStatus +SECMOD_DeletePermDB(SECMODModule *module) +{ + SECMODModuleDBFunc func; + char *moduleSpec; + char **retString; + + if (module->parent == NULL) return SECFailure; + + func = (SECMODModuleDBFunc) module->parent->moduleDBFunc; + if (func) { + moduleSpec = secmod_mkModuleSpec(module); + retString = (*func)(SECMOD_MODULE_DB_FUNCTION_DEL, + module->parent->libraryParams,moduleSpec); + PORT_Free(moduleSpec); + if (retString != NULL) return SECSuccess; + } + return SECFailure; +} + +SECStatus +SECMOD_FreeModuleSpecList(SECMODModule *module, char **moduleSpecList) +{ + SECMODModuleDBFunc func = (SECMODModuleDBFunc) module->moduleDBFunc; + char **retString; + if (func) { + retString = (*func)(SECMOD_MODULE_DB_FUNCTION_RELEASE, + module->libraryParams,moduleSpecList); + if (retString != NULL) return SECSuccess; + } + return SECFailure; +} + +/* + * load a PKCS#11 module but do not add it to the default NSS trust domain + */ +SECMODModule * +SECMOD_LoadModule(char *modulespec,SECMODModule *parent, PRBool recurse) +{ + char *library = NULL, *moduleName = NULL, *parameters = NULL, *nss= NULL; + SECStatus status; + SECMODModule *module = NULL; + SECMODModule *oldModule = NULL; + SECStatus rv; + + /* initialize the underlying module structures */ + SECMOD_Init(); + + status = NSSUTIL_ArgParseModuleSpec(modulespec, &library, &moduleName, + ¶meters, &nss); + if (status != SECSuccess) { + goto loser; + } + + module = SECMOD_CreateModule(library, moduleName, parameters, nss); + if (library) PORT_Free(library); + if (moduleName) PORT_Free(moduleName); + if (parameters) PORT_Free(parameters); + if (nss) PORT_Free(nss); + if (!module) { + goto loser; + } + if (parent) { + module->parent = SECMOD_ReferenceModule(parent); + if (module->internal && secmod_IsInternalKeySlot(parent)) { + module->internal = parent->internal; + } + } + + /* load it */ + rv = secmod_LoadPKCS11Module(module, &oldModule); + if (rv != SECSuccess) { + goto loser; + } + + /* if we just reload an old module, no need to add it to any lists. + * we simple release all our references */ + if (oldModule) { + /* This module already exists, don't link it anywhere. This + * will probably destroy this module */ + SECMOD_DestroyModule(module); + return oldModule; + } + + if (recurse && module->isModuleDB) { + char ** moduleSpecList; + PORT_SetError(0); + + moduleSpecList = SECMOD_GetModuleSpecList(module); + if (moduleSpecList) { + char **index; + + index = moduleSpecList; + if (*index && SECMOD_GetSkipFirstFlag(module)) { + index++; + } + + for (; *index; index++) { + SECMODModule *child; + if (0 == PORT_Strcmp(*index, modulespec)) { + /* avoid trivial infinite recursion */ + PORT_SetError(SEC_ERROR_NO_MODULE); + rv = SECFailure; + break; + } + child = SECMOD_LoadModule(*index,module,PR_TRUE); + if (!child) break; + if (child->isCritical && !child->loaded) { + int err = PORT_GetError(); + if (!err) + err = SEC_ERROR_NO_MODULE; + SECMOD_DestroyModule(child); + PORT_SetError(err); + rv = SECFailure; + break; + } + SECMOD_DestroyModule(child); + } + SECMOD_FreeModuleSpecList(module,moduleSpecList); + } else { + if (!PORT_GetError()) + PORT_SetError(SEC_ERROR_NO_MODULE); + rv = SECFailure; + } + } + + if (rv != SECSuccess) { + goto loser; + } + + + /* inherit the reference */ + if (!module->moduleDBOnly) { + SECMOD_AddModuleToList(module); + } else { + SECMOD_AddModuleToDBOnlyList(module); + } + + /* handle any additional work here */ + return module; + +loser: + if (module) { + if (module->loaded) { + SECMOD_UnloadModule(module); + } + SECMOD_AddModuleToUnloadList(module); + } + return module; +} + +/* + * load a PKCS#11 module and add it to the default NSS trust domain + */ +SECMODModule * +SECMOD_LoadUserModule(char *modulespec,SECMODModule *parent, PRBool recurse) +{ + SECStatus rv = SECSuccess; + SECMODModule * newmod = SECMOD_LoadModule(modulespec, parent, recurse); + SECMODListLock *moduleLock = SECMOD_GetDefaultModuleListLock(); + + if (newmod) { + SECMOD_GetReadLock(moduleLock); + rv = STAN_AddModuleToDefaultTrustDomain(newmod); + SECMOD_ReleaseReadLock(moduleLock); + if (SECSuccess != rv) { + SECMOD_DestroyModule(newmod); + return NULL; + } + } + return newmod; +} + +/* + * remove the PKCS#11 module from the default NSS trust domain, call + * C_Finalize, and destroy the module structure + */ +SECStatus SECMOD_UnloadUserModule(SECMODModule *mod) +{ + SECStatus rv = SECSuccess; + int atype = 0; + SECMODListLock *moduleLock = SECMOD_GetDefaultModuleListLock(); + if (!mod) { + return SECFailure; + } + + SECMOD_GetReadLock(moduleLock); + rv = STAN_RemoveModuleFromDefaultTrustDomain(mod); + SECMOD_ReleaseReadLock(moduleLock); + if (SECSuccess != rv) { + return SECFailure; + } + return SECMOD_DeleteModuleEx(NULL, mod, &atype, PR_FALSE); +} +