зеркало из https://github.com/mozilla/gecko-dev.git
879 строки
22 KiB
C
879 строки
22 KiB
C
/* ***** BEGIN LICENSE BLOCK *****
|
|
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
|
*
|
|
* The contents of this file are subject to the Mozilla Public License Version
|
|
* 1.1 (the "License"); you may not use this file except in compliance with
|
|
* the License. You may obtain a copy of the License at
|
|
* http://www.mozilla.org/MPL/
|
|
*
|
|
* Software distributed under the License is distributed on an "AS IS" basis,
|
|
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
|
* for the specific language governing rights and limitations under the
|
|
* License.
|
|
*
|
|
* The Original Code is the Netscape security libraries.
|
|
*
|
|
* The Initial Developer of the Original Code is
|
|
* Netscape Communications Corporation.
|
|
* Portions created by the Initial Developer are Copyright (C) 1994-2000
|
|
* the Initial Developer. All Rights Reserved.
|
|
*
|
|
* Contributor(s):
|
|
*
|
|
* Alternatively, the contents of this file may be used under the terms of
|
|
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
|
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
|
* in which case the provisions of the GPL or the LGPL are applicable instead
|
|
* of those above. If you wish to allow use of your version of this file only
|
|
* under the terms of either the GPL or the LGPL, and not to allow others to
|
|
* use your version of this file under the terms of the MPL, indicate your
|
|
* decision by deleting the provisions above and replace them with the notice
|
|
* and other provisions required by the GPL or the LGPL. If you do not delete
|
|
* the provisions above, a recipient may use your version of this file under
|
|
* the terms of any one of the MPL, the GPL or the LGPL.
|
|
*
|
|
* ***** END LICENSE BLOCK ***** */
|
|
|
|
#ifdef DEBUG
|
|
static const char CVS_ID[] = "@(#) $RCSfile: devmod.c,v $ $Revision: 1.6 $ $Date: 2004/04/25 15:03:06 $ $Name: $";
|
|
#endif /* DEBUG */
|
|
|
|
#ifndef NSSCKEPV_H
|
|
#include "nssckepv.h"
|
|
#endif /* NSSCKEPV_H */
|
|
|
|
#ifndef DEVM_H
|
|
#include "devm.h"
|
|
#endif /* DEVM_H */
|
|
|
|
#ifndef CKHELPER_H
|
|
#include "ckhelper.h"
|
|
#endif /* CKHELPER_H */
|
|
|
|
#ifdef PURE_STAN_CODE
|
|
|
|
extern void FC_GetFunctionList(void);
|
|
extern void NSC_GetFunctionList(void);
|
|
extern void NSC_ModuleDBFunc(void);
|
|
|
|
/* The list of boolean flags used to describe properties of a
|
|
* module.
|
|
*/
|
|
#define NSSMODULE_FLAGS_NOT_THREADSAFE 0x0001 /* isThreadSafe */
|
|
#define NSSMODULE_FLAGS_INTERNAL 0x0002 /* isInternal */
|
|
#define NSSMODULE_FLAGS_FIPS 0x0004 /* isFIPS */
|
|
#define NSSMODULE_FLAGS_MODULE_DB 0x0008 /* isModuleDB */
|
|
#define NSSMODULE_FLAGS_MODULE_DB_ONLY 0x0010 /* moduleDBOnly */
|
|
#define NSSMODULE_FLAGS_CRITICAL 0x0020 /* isCritical */
|
|
|
|
struct NSSModuleStr {
|
|
struct nssDeviceBaseStr base;
|
|
NSSUTF8 *libraryName;
|
|
PRLibrary *library;
|
|
char *libraryParams;
|
|
void *moduleDBFunc;
|
|
void *epv;
|
|
CK_INFO info;
|
|
NSSSlot **slots;
|
|
PRUint32 numSlots;
|
|
PRBool isLoaded;
|
|
struct {
|
|
PRInt32 trust;
|
|
PRInt32 cipher;
|
|
PRInt32 certStorage;
|
|
} order;
|
|
};
|
|
|
|
#define NSSMODULE_IS_THREADSAFE(module) \
|
|
(!(module->base.flags & NSSMODULE_FLAGS_NOT_THREADSAFE))
|
|
|
|
#define NSSMODULE_IS_INTERNAL(module) \
|
|
(module->base.flags & NSSMODULE_FLAGS_INTERNAL)
|
|
|
|
#define NSSMODULE_IS_FIPS(module) \
|
|
(module->base.flags & NSSMODULE_FLAGS_FIPS)
|
|
|
|
#define NSSMODULE_IS_MODULE_DB(module) \
|
|
(module->base.flags & NSSMODULE_FLAGS_MODULE_DB)
|
|
|
|
#define NSSMODULE_IS_MODULE_DB_ONLY(module) \
|
|
(module->base.flags & NSSMODULE_FLAGS_MODULE_DB_ONLY)
|
|
|
|
#define NSSMODULE_IS_CRITICAL(module) \
|
|
(module->base.flags & NSSMODULE_FLAGS_CRITICAL)
|
|
|
|
/* Threading callbacks for C_Initialize. Use NSPR threads. */
|
|
|
|
CK_RV PR_CALLBACK
|
|
nss_ck_CreateMutex(CK_VOID_PTR_PTR pMutex)
|
|
{
|
|
CK_VOID_PTR mutex = (CK_VOID_PTR)PZ_NewLock(nssILockOther);
|
|
if (mutex != NULL) {
|
|
*pMutex = (CK_VOID_PTR)mutex;
|
|
return CKR_OK;
|
|
}
|
|
return CKR_HOST_MEMORY;
|
|
}
|
|
|
|
CK_RV PR_CALLBACK
|
|
nss_ck_DestroyMutex(CK_VOID_PTR mutex)
|
|
{
|
|
PZ_DestroyLock((PZLock *)mutex);
|
|
return CKR_OK;
|
|
}
|
|
|
|
CK_RV PR_CALLBACK
|
|
nss_ck_LockMutex(CK_VOID_PTR mutex)
|
|
{
|
|
PZ_Lock((PZLock *)mutex);
|
|
return CKR_OK;
|
|
}
|
|
|
|
CK_RV PR_CALLBACK
|
|
nss_ck_UnlockMutex(CK_VOID_PTR mutex)
|
|
{
|
|
return (PZ_Unlock((PZLock *)mutex) == PR_SUCCESS) ?
|
|
CKR_OK : CKR_MUTEX_NOT_LOCKED;
|
|
}
|
|
|
|
/* Default callback args to C_Initialize */
|
|
/* XXX not const because we are modifying the pReserved argument in order
|
|
* to use the libraryParams extension.
|
|
*/
|
|
static CK_C_INITIALIZE_ARGS
|
|
s_ck_initialize_args = {
|
|
nss_ck_CreateMutex, /* CreateMutex */
|
|
nss_ck_DestroyMutex, /* DestroyMutex */
|
|
nss_ck_LockMutex, /* LockMutex */
|
|
nss_ck_UnlockMutex, /* UnlockMutex */
|
|
CKF_LIBRARY_CANT_CREATE_OS_THREADS |
|
|
CKF_OS_LOCKING_OK, /* flags */
|
|
NULL /* pReserved */
|
|
};
|
|
|
|
/* load all slots in a module. */
|
|
static PRStatus
|
|
module_load_slots(NSSModule *mod)
|
|
{
|
|
CK_ULONG i, ulNumSlots;
|
|
CK_SLOT_ID *slotIDs;
|
|
nssArenaMark *mark = NULL;
|
|
NSSSlot **slots;
|
|
PRStatus nssrv;
|
|
CK_RV ckrv;
|
|
/* Get the number of slots */
|
|
ckrv = CKAPI(mod->epv)->C_GetSlotList(CK_FALSE, NULL, &ulNumSlots);
|
|
if (ckrv != CKR_OK) {
|
|
/* what is the error? */
|
|
return PR_FAILURE;
|
|
}
|
|
/* Alloc memory for the array of slot ID's */
|
|
slotIDs = nss_ZNEWARRAY(NULL, CK_SLOT_ID, ulNumSlots);
|
|
if (!slotIDs) {
|
|
goto loser;
|
|
}
|
|
/* Get the actual slot list */
|
|
ckrv = CKAPI(mod->epv)->C_GetSlotList(CK_FALSE, slotIDs, &ulNumSlots);
|
|
if (ckrv != CKR_OK) {
|
|
/* what is the error? */
|
|
goto loser;
|
|
}
|
|
/* Alloc memory for the array of slots, in the module's arena */
|
|
mark = nssArena_Mark(mod->base.arena); /* why mark? it'll be destroyed */
|
|
if (!mark) {
|
|
return PR_FAILURE;
|
|
}
|
|
slots = nss_ZNEWARRAY(mod->base.arena, NSSSlot *, ulNumSlots);
|
|
if (!slots) {
|
|
goto loser;
|
|
}
|
|
/* Initialize each slot */
|
|
for (i=0; i<ulNumSlots; i++) {
|
|
slots[i] = nssSlot_Create(slotIDs[i], mod);
|
|
}
|
|
nss_ZFreeIf(slotIDs);
|
|
nssrv = nssArena_Unmark(mod->base.arena, mark);
|
|
if (nssrv != PR_SUCCESS) {
|
|
goto loser;
|
|
}
|
|
mod->slots = slots;
|
|
mod->numSlots = ulNumSlots;
|
|
return PR_SUCCESS;
|
|
loser:
|
|
if (mark) {
|
|
nssArena_Release(mod->base.arena, mark);
|
|
}
|
|
nss_ZFreeIf(slotIDs);
|
|
return PR_FAILURE;
|
|
}
|
|
|
|
NSS_IMPLEMENT PRStatus
|
|
nssModule_Load (
|
|
NSSModule *mod
|
|
)
|
|
{
|
|
PRLibrary *library = NULL;
|
|
CK_C_GetFunctionList epv;
|
|
CK_RV ckrv;
|
|
if (NSSMODULE_IS_INTERNAL(mod)) {
|
|
/* internal, statically get the C_GetFunctionList function */
|
|
if (NSSMODULE_IS_FIPS(mod)) {
|
|
epv = (CK_C_GetFunctionList) FC_GetFunctionList;
|
|
} else {
|
|
epv = (CK_C_GetFunctionList) NSC_GetFunctionList;
|
|
}
|
|
if (NSSMODULE_IS_MODULE_DB(mod)) {
|
|
mod->moduleDBFunc = (void *) NSC_ModuleDBFunc;
|
|
}
|
|
if (NSSMODULE_IS_MODULE_DB_ONLY(mod)) {
|
|
mod->isLoaded = PR_TRUE; /* XXX needed? */
|
|
return PR_SUCCESS;
|
|
}
|
|
} else {
|
|
/* Use NSPR to load the library */
|
|
library = PR_LoadLibrary(mod->libraryName);
|
|
if (!library) {
|
|
/* what's the error to set? */
|
|
return PR_FAILURE;
|
|
}
|
|
mod->library = library;
|
|
/* Skip if only getting the db loader function */
|
|
if (!NSSMODULE_IS_MODULE_DB_ONLY(mod)) {
|
|
/* Load the cryptoki entry point function */
|
|
epv = (CK_C_GetFunctionList)PR_FindSymbol(library,
|
|
"C_GetFunctionList");
|
|
}
|
|
/* Load the module database loader function */
|
|
if (NSSMODULE_IS_MODULE_DB(mod)) {
|
|
mod->moduleDBFunc = (void *)PR_FindSymbol(library,
|
|
"NSS_ReturnModuleSpecData");
|
|
}
|
|
}
|
|
if (epv == NULL) {
|
|
goto loser;
|
|
}
|
|
/* Load the cryptoki entry point vector (function list) */
|
|
ckrv = (*epv)((CK_FUNCTION_LIST_PTR *)&mod->epv);
|
|
if (ckrv != CKR_OK) {
|
|
goto loser;
|
|
}
|
|
/* Initialize the module */
|
|
if (mod->libraryParams) {
|
|
s_ck_initialize_args.LibraryParameters = (void *)mod->libraryParams;
|
|
} else {
|
|
s_ck_initialize_args.LibraryParameters = NULL;
|
|
}
|
|
ckrv = CKAPI(mod->epv)->C_Initialize(&s_ck_initialize_args);
|
|
if (ckrv != CKR_OK) {
|
|
/* Apparently the token is not thread safe. Retry without
|
|
* threading parameters.
|
|
*/
|
|
mod->base.flags |= NSSMODULE_FLAGS_NOT_THREADSAFE;
|
|
ckrv = CKAPI(mod->epv)->C_Initialize((CK_VOID_PTR)NULL);
|
|
if (ckrv != CKR_OK) {
|
|
goto loser;
|
|
}
|
|
}
|
|
/* TODO: check the version # using C_GetInfo */
|
|
ckrv = CKAPI(mod->epv)->C_GetInfo(&mod->info);
|
|
if (ckrv != CKR_OK) {
|
|
goto loser;
|
|
}
|
|
/* TODO: if the name is not set, get it from info.libraryDescription */
|
|
/* Now load the slots */
|
|
if (module_load_slots(mod) != PR_SUCCESS) {
|
|
goto loser;
|
|
}
|
|
/* Module has successfully loaded */
|
|
mod->isLoaded = PR_TRUE;
|
|
return PR_SUCCESS;
|
|
loser:
|
|
if (library) {
|
|
PR_UnloadLibrary(library);
|
|
}
|
|
/* clear all values set above, they are invalid now */
|
|
mod->library = NULL;
|
|
mod->epv = NULL;
|
|
return PR_FAILURE;
|
|
}
|
|
|
|
NSS_IMPLEMENT PRStatus
|
|
nssModule_Unload (
|
|
NSSModule *mod
|
|
)
|
|
{
|
|
PRStatus nssrv = PR_SUCCESS;
|
|
if (mod->library) {
|
|
(void)CKAPI(mod->epv)->C_Finalize(NULL);
|
|
nssrv = PR_UnloadLibrary(mod->library);
|
|
}
|
|
/* Free the slots, yes? */
|
|
mod->library = NULL;
|
|
mod->epv = NULL;
|
|
mod->isLoaded = PR_FALSE;
|
|
return nssrv;
|
|
}
|
|
|
|
/* Alloc memory for a module. Copy in the module name and library path
|
|
* if provided. XXX use the opaque arg also, right?
|
|
*/
|
|
NSS_IMPLEMENT NSSModule *
|
|
nssModule_Create (
|
|
NSSUTF8 *moduleOpt,
|
|
NSSUTF8 *uriOpt,
|
|
NSSUTF8 *opaqueOpt,
|
|
void *reserved
|
|
)
|
|
{
|
|
NSSArena *arena;
|
|
NSSModule *rvMod;
|
|
arena = NSSArena_Create();
|
|
if(!arena) {
|
|
return (NSSModule *)NULL;
|
|
}
|
|
rvMod = nss_ZNEW(arena, NSSModule);
|
|
if (!rvMod) {
|
|
goto loser;
|
|
}
|
|
if (moduleOpt) {
|
|
/* XXX making the gross assumption this is just the module name */
|
|
/* if the name is a duplicate, should that be tested here? or
|
|
* wait for Load?
|
|
*/
|
|
rvMod->base.name = nssUTF8_Duplicate(moduleOpt, arena);
|
|
if (!rvMod->base.name) {
|
|
goto loser;
|
|
}
|
|
}
|
|
if (uriOpt) {
|
|
/* Load the module from a URI. */
|
|
/* XXX at this time - only file URI (even worse, no file:// for now) */
|
|
rvMod->libraryName = nssUTF8_Duplicate(uriOpt, arena);
|
|
if (!rvMod->libraryName) {
|
|
goto loser;
|
|
}
|
|
}
|
|
rvMod->base.arena = arena;
|
|
rvMod->base.refCount = 1;
|
|
rvMod->base.lock = PZ_NewLock(nssNSSILockOther);
|
|
if (!rvMod->base.lock) {
|
|
goto loser;
|
|
}
|
|
/* everything else is 0/NULL at this point. */
|
|
return rvMod;
|
|
loser:
|
|
nssArena_Destroy(arena);
|
|
return (NSSModule *)NULL;
|
|
}
|
|
|
|
NSS_EXTERN PRStatus
|
|
nssCryptokiArgs_ParseNextPair (
|
|
NSSUTF8 *start,
|
|
NSSUTF8 **attrib,
|
|
NSSUTF8 **value,
|
|
NSSUTF8 **remainder,
|
|
NSSArena *arenaOpt
|
|
);
|
|
|
|
static PRStatus
|
|
parse_slot_flags (
|
|
NSSSlot *slot,
|
|
NSSUTF8 *slotFlags
|
|
)
|
|
{
|
|
PRStatus nssrv = PR_SUCCESS;
|
|
#if 0
|
|
PRBool done = PR_FALSE;
|
|
NSSUTF8 *mark, *last;
|
|
last = mark = slotFlags;
|
|
while (PR_TRUE) {
|
|
while (*mark && *mark != ',') ++mark;
|
|
if (!*mark) done = PR_TRUE;
|
|
*mark = '\0';
|
|
if (nssUTF8_Equal(last, "RANDOM", &nssrv)) {
|
|
slot->base.flags |= NSSSLOT_FLAGS_HAS_RANDOM;
|
|
} else if (nssUTF8_Equal(last, "RSA", &nssrv)) {
|
|
slot->base.flags |= NSSSLOT_FLAGS_RSA;
|
|
} else if (nssUTF8_Equal(last, "DSA", &nssrv)) {
|
|
slot->base.flags |= NSSSLOT_FLAGS_DSA;
|
|
} else if (nssUTF8_Equal(last, "DH", &nssrv)) {
|
|
slot->base.flags |= NSSSLOT_FLAGS_DH;
|
|
} else if (nssUTF8_Equal(last, "RC2", &nssrv)) {
|
|
slot->base.flags |= NSSSLOT_FLAGS_RC2;
|
|
} else if (nssUTF8_Equal(last, "RC4", &nssrv)) {
|
|
slot->base.flags |= NSSSLOT_FLAGS_RC4;
|
|
} else if (nssUTF8_Equal(last, "RC5", &nssrv)) {
|
|
slot->base.flags |= NSSSLOT_FLAGS_RC5;
|
|
} else if (nssUTF8_Equal(last, "DES", &nssrv)) {
|
|
slot->base.flags |= NSSSLOT_FLAGS_DES;
|
|
} else if (nssUTF8_Equal(last, "AES", &nssrv)) {
|
|
slot->base.flags |= NSSSLOT_FLAGS_AES;
|
|
} else if (nssUTF8_Equal(last, "SHA1", &nssrv)) {
|
|
slot->base.flags |= NSSSLOT_FLAGS_SHA1;
|
|
} else if (nssUTF8_Equal(last, "MD2", &nssrv)) {
|
|
slot->base.flags |= NSSSLOT_FLAGS_MD2;
|
|
} else if (nssUTF8_Equal(last, "MD5", &nssrv)) {
|
|
slot->base.flags |= NSSSLOT_FLAGS_MD5;
|
|
} else if (nssUTF8_Equal(last, "SSL", &nssrv)) {
|
|
slot->base.flags |= NSSSLOT_FLAGS_SSL;
|
|
} else if (nssUTF8_Equal(last, "TLS", &nssrv)) {
|
|
slot->base.flags |= NSSSLOT_FLAGS_TLS;
|
|
} else if (nssUTF8_Equal(last, "PublicCerts", &nssrv)) {
|
|
slot->base.flags |= NSSSLOT_FLAGS_FRIENDLY;
|
|
} else {
|
|
return PR_FAILURE;
|
|
}
|
|
if (done) break;
|
|
last = ++mark;
|
|
}
|
|
#endif
|
|
return nssrv;
|
|
}
|
|
|
|
static PRStatus
|
|
parse_slot_parameters (
|
|
NSSSlot *slot,
|
|
NSSUTF8 *slotParams,
|
|
NSSArena *tmparena
|
|
)
|
|
{
|
|
PRStatus nssrv = PR_SUCCESS;
|
|
NSSUTF8 *current, *remainder;
|
|
NSSUTF8 *attrib, *value;
|
|
current = slotParams;
|
|
while (nssrv == PR_SUCCESS) {
|
|
nssrv = nssCryptokiArgs_ParseNextPair(current,
|
|
&attrib, &value,
|
|
&remainder, tmparena);
|
|
if (nssrv != PR_SUCCESS) break;
|
|
if (value) {
|
|
if (nssUTF8_Equal(attrib, "slotFlags", &nssrv)) {
|
|
nssrv = parse_slot_flags(slot, value);
|
|
} else if (nssUTF8_Equal(attrib, "askpw", &nssrv)) {
|
|
} else if (nssUTF8_Equal(attrib, "timeout", &nssrv)) {
|
|
}
|
|
}
|
|
if (*remainder == '\0') break;
|
|
current = remainder;
|
|
}
|
|
return nssrv;
|
|
}
|
|
|
|
/* softoken seems to use "0x0000001", but no standard yet... perhaps this
|
|
* should store the number as an ID, in case the input isn't 1,2,3,...?
|
|
*/
|
|
static PRIntn
|
|
get_slot_number(NSSUTF8* snString)
|
|
{
|
|
/* XXX super big hack */
|
|
return atoi(&snString[strlen(snString)-1]);
|
|
}
|
|
|
|
static PRStatus
|
|
parse_module_slot_parameters (
|
|
NSSModule *mod,
|
|
NSSUTF8 *slotParams
|
|
)
|
|
{
|
|
PRStatus nssrv = PR_SUCCESS;
|
|
NSSUTF8 *current, *remainder;
|
|
NSSUTF8 *attrib, *value;
|
|
NSSArena *tmparena;
|
|
PRIntn slotNum;
|
|
tmparena = nssArena_Create();
|
|
if (!tmparena) {
|
|
return PR_FAILURE;
|
|
}
|
|
current = slotParams;
|
|
while (nssrv == PR_SUCCESS) {
|
|
nssrv = nssCryptokiArgs_ParseNextPair(current,
|
|
&attrib, &value,
|
|
&remainder, tmparena);
|
|
if (nssrv != PR_SUCCESS) break;
|
|
if (value) {
|
|
slotNum = get_slot_number(attrib);
|
|
if (slotNum < 0 || slotNum > mod->numSlots) {
|
|
return PR_FAILURE;
|
|
}
|
|
nssrv = parse_slot_parameters(mod->slots[slotNum],
|
|
value, tmparena);
|
|
if (nssrv != PR_SUCCESS) break;
|
|
}
|
|
if (*remainder == '\0') break;
|
|
current = remainder;
|
|
}
|
|
return nssrv;
|
|
}
|
|
|
|
static PRStatus
|
|
parse_nss_flags (
|
|
NSSModule *mod,
|
|
NSSUTF8 *nssFlags
|
|
)
|
|
{
|
|
PRStatus nssrv = PR_SUCCESS;
|
|
PRBool done = PR_FALSE;
|
|
NSSUTF8 *mark, *last;
|
|
last = mark = nssFlags;
|
|
while (PR_TRUE) {
|
|
while (*mark && *mark != ',') ++mark;
|
|
if (!*mark) done = PR_TRUE;
|
|
*mark = '\0';
|
|
if (nssUTF8_Equal(last, "internal", &nssrv)) {
|
|
mod->base.flags |= NSSMODULE_FLAGS_INTERNAL;
|
|
} else if (nssUTF8_Equal(last, "moduleDB", &nssrv)) {
|
|
mod->base.flags |= NSSMODULE_FLAGS_MODULE_DB;
|
|
} else if (nssUTF8_Equal(last, "moduleDBOnly", &nssrv)) {
|
|
mod->base.flags |= NSSMODULE_FLAGS_MODULE_DB_ONLY;
|
|
} else if (nssUTF8_Equal(last, "critical", &nssrv)) {
|
|
mod->base.flags |= NSSMODULE_FLAGS_CRITICAL;
|
|
} else {
|
|
return PR_FAILURE;
|
|
}
|
|
if (done) break;
|
|
last = ++mark;
|
|
}
|
|
return nssrv;
|
|
}
|
|
|
|
static PRStatus
|
|
parse_nss_parameters (
|
|
NSSModule *mod,
|
|
NSSUTF8 *nssParams,
|
|
NSSArena *tmparena,
|
|
NSSUTF8 **slotParams
|
|
)
|
|
{
|
|
PRStatus nssrv = PR_SUCCESS;
|
|
NSSUTF8 *current, *remainder;
|
|
NSSUTF8 *attrib, *value;
|
|
current = nssParams;
|
|
while (nssrv == PR_SUCCESS) {
|
|
nssrv = nssCryptokiArgs_ParseNextPair(current,
|
|
&attrib, &value,
|
|
&remainder, tmparena);
|
|
if (nssrv != PR_SUCCESS) break;
|
|
if (value) {
|
|
if (nssUTF8_Equal(attrib, "flags", &nssrv) ||
|
|
nssUTF8_Equal(attrib, "Flags", &nssrv)) {
|
|
nssrv = parse_nss_flags(mod, value);
|
|
} else if (nssUTF8_Equal(attrib, "trustOrder", &nssrv)) {
|
|
mod->order.trust = atoi(value);
|
|
} else if (nssUTF8_Equal(attrib, "cipherOrder", &nssrv)) {
|
|
mod->order.cipher = atoi(value);
|
|
} else if (nssUTF8_Equal(attrib, "ciphers", &nssrv)) {
|
|
} else if (nssUTF8_Equal(attrib, "slotParams", &nssrv)) {
|
|
/* slotParams doesn't get an arena, it is handled separately */
|
|
*slotParams = nssUTF8_Duplicate(value, NULL);
|
|
}
|
|
}
|
|
if (*remainder == '\0') break;
|
|
current = remainder;
|
|
}
|
|
return nssrv;
|
|
}
|
|
|
|
static PRStatus
|
|
parse_module_parameters (
|
|
NSSModule *mod,
|
|
NSSUTF8 *moduleParams,
|
|
NSSUTF8 **slotParams
|
|
)
|
|
{
|
|
PRStatus nssrv = PR_SUCCESS;
|
|
NSSUTF8 *current, *remainder;
|
|
NSSUTF8 *attrib, *value;
|
|
NSSArena *arena = mod->base.arena;
|
|
NSSArena *tmparena;
|
|
current = moduleParams;
|
|
tmparena = nssArena_Create();
|
|
if (!tmparena) {
|
|
return PR_FAILURE;
|
|
}
|
|
while (nssrv == PR_SUCCESS) {
|
|
nssrv = nssCryptokiArgs_ParseNextPair(current,
|
|
&attrib, &value,
|
|
&remainder, tmparena);
|
|
if (nssrv != PR_SUCCESS) break;
|
|
if (value) {
|
|
if (nssUTF8_Equal(attrib, "name", &nssrv)) {
|
|
mod->base.name = nssUTF8_Duplicate(value, arena);
|
|
} else if (nssUTF8_Equal(attrib, "library", &nssrv)) {
|
|
mod->libraryName = nssUTF8_Duplicate(value, arena);
|
|
} else if (nssUTF8_Equal(attrib, "parameters", &nssrv)) {
|
|
mod->libraryParams = nssUTF8_Duplicate(value, arena);
|
|
} else if (nssUTF8_Equal(attrib, "NSS", &nssrv)) {
|
|
parse_nss_parameters(mod, value, tmparena, slotParams);
|
|
}
|
|
}
|
|
if (*remainder == '\0') break;
|
|
current = remainder;
|
|
}
|
|
nssArena_Destroy(tmparena);
|
|
return nssrv;
|
|
}
|
|
|
|
static NSSUTF8 **
|
|
get_module_specs (
|
|
NSSModule *mod
|
|
)
|
|
{
|
|
SECMODModuleDBFunc func = (SECMODModuleDBFunc)mod->moduleDBFunc;
|
|
if (func) {
|
|
return (*func)(SECMOD_MODULE_DB_FUNCTION_FIND,
|
|
mod->libraryParams,
|
|
NULL);
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
/* XXX continue working on */
|
|
NSS_IMPLEMENT NSSModule *
|
|
nssModule_CreateFromSpec (
|
|
NSSUTF8 *moduleSpec,
|
|
NSSModule *parent,
|
|
PRBool loadSubModules
|
|
)
|
|
{
|
|
PRStatus nssrv;
|
|
NSSModule *thisModule;
|
|
NSSArena *arena;
|
|
NSSUTF8 *slotParams = NULL;
|
|
arena = nssArena_Create();
|
|
if (!arena) {
|
|
return NULL;
|
|
}
|
|
thisModule = nss_ZNEW(arena, NSSModule);
|
|
if (!thisModule) {
|
|
goto loser;
|
|
}
|
|
thisModule->base.lock = PZ_NewLock(nssILockOther);
|
|
if (!thisModule->base.lock) {
|
|
goto loser;
|
|
}
|
|
PR_AtomicIncrement(&thisModule->base.refCount);
|
|
thisModule->base.arena = arena;
|
|
thisModule->base.lock = PZ_NewLock(nssNSSILockOther);
|
|
if (!thisModule->base.lock) {
|
|
goto loser;
|
|
}
|
|
nssrv = parse_module_parameters(thisModule, moduleSpec, &slotParams);
|
|
if (nssrv != PR_SUCCESS) {
|
|
goto loser;
|
|
}
|
|
nssrv = nssModule_Load(thisModule);
|
|
if (nssrv != PR_SUCCESS) {
|
|
goto loser;
|
|
}
|
|
if (slotParams) {
|
|
nssrv = parse_module_slot_parameters(thisModule, slotParams);
|
|
nss_ZFreeIf(slotParams);
|
|
if (nssrv != PR_SUCCESS) {
|
|
goto loser;
|
|
}
|
|
}
|
|
if (loadSubModules && NSSMODULE_IS_MODULE_DB(thisModule)) {
|
|
NSSUTF8 **moduleSpecs;
|
|
NSSUTF8 **index;
|
|
/* get the array of sub modules one level below this module */
|
|
moduleSpecs = get_module_specs(thisModule);
|
|
/* iterate over the array */
|
|
for (index = moduleSpecs; index && *index; index++) {
|
|
NSSModule *child;
|
|
/* load the child recursively */
|
|
child = nssModule_CreateFromSpec(*index, thisModule, PR_TRUE);
|
|
if (!child) {
|
|
/* when children fail, does the parent? */
|
|
nssrv = PR_FAILURE;
|
|
break;
|
|
}
|
|
if (NSSMODULE_IS_CRITICAL(child) && !child->isLoaded) {
|
|
nssrv = PR_FAILURE;
|
|
nssModule_Destroy(child);
|
|
break;
|
|
}
|
|
nssModule_Destroy(child);
|
|
/*nss_ZFreeIf(*index);*/
|
|
}
|
|
/*nss_ZFreeIf(moduleSpecs);*/
|
|
}
|
|
/* The global list inherits the reference */
|
|
nssrv = nssGlobalModuleList_Add(thisModule);
|
|
if (nssrv != PR_SUCCESS) {
|
|
goto loser;
|
|
}
|
|
return thisModule;
|
|
loser:
|
|
if (thisModule->base.lock) {
|
|
PZ_DestroyLock(thisModule->base.lock);
|
|
}
|
|
nssArena_Destroy(arena);
|
|
return (NSSModule *)NULL;
|
|
}
|
|
|
|
NSS_IMPLEMENT PRStatus
|
|
nssModule_Destroy (
|
|
NSSModule *mod
|
|
)
|
|
{
|
|
PRUint32 i, numSlots;
|
|
if (PR_AtomicDecrement(&mod->base.refCount) == 0) {
|
|
if (mod->numSlots == 0) {
|
|
(void)nssModule_Unload(mod);
|
|
return nssArena_Destroy(mod->base.arena);
|
|
} else {
|
|
numSlots = mod->numSlots;
|
|
for (i=0; i<numSlots; i++) {
|
|
nssSlot_Destroy(mod->slots[i]);
|
|
}
|
|
}
|
|
}
|
|
return PR_SUCCESS;
|
|
}
|
|
|
|
NSS_IMPLEMENT PRStatus
|
|
nssModule_DestroyFromSlot (
|
|
NSSModule *mod,
|
|
NSSSlot *slot
|
|
)
|
|
{
|
|
PRUint32 i, numSlots = 0;
|
|
PR_ASSERT(mod->base.refCount == 0);
|
|
for (i=0; i<mod->numSlots; i++) {
|
|
if (mod->slots[i] == slot) {
|
|
mod->slots[i] = NULL;
|
|
} else if (mod->slots[i]) {
|
|
numSlots++;
|
|
}
|
|
}
|
|
if (numSlots == 0) {
|
|
(void)nssModule_Unload(mod);
|
|
return nssArena_Destroy(mod->base.arena);
|
|
}
|
|
return PR_SUCCESS;
|
|
}
|
|
|
|
NSS_IMPLEMENT NSSModule *
|
|
nssModule_AddRef (
|
|
NSSModule *mod
|
|
)
|
|
{
|
|
PR_AtomicIncrement(&mod->base.refCount);
|
|
return mod;
|
|
}
|
|
|
|
NSS_IMPLEMENT NSSUTF8 *
|
|
nssModule_GetName (
|
|
NSSModule *mod
|
|
)
|
|
{
|
|
return mod->base.name;
|
|
}
|
|
|
|
NSS_IMPLEMENT PRBool
|
|
nssModule_IsThreadSafe (
|
|
NSSModule *module
|
|
)
|
|
{
|
|
return NSSMODULE_IS_THREADSAFE(module);
|
|
}
|
|
|
|
NSS_IMPLEMENT PRBool
|
|
nssModule_IsInternal (
|
|
NSSModule *mod
|
|
)
|
|
{
|
|
return NSSMODULE_IS_INTERNAL(mod);
|
|
}
|
|
|
|
NSS_IMPLEMENT PRBool
|
|
nssModule_IsModuleDBOnly (
|
|
NSSModule *mod
|
|
)
|
|
{
|
|
return NSSMODULE_IS_MODULE_DB_ONLY(mod);
|
|
}
|
|
|
|
NSS_IMPLEMENT void *
|
|
nssModule_GetCryptokiEPV (
|
|
NSSModule *mod
|
|
)
|
|
{
|
|
return mod->epv;
|
|
}
|
|
|
|
NSS_IMPLEMENT NSSSlot **
|
|
nssModule_GetSlots (
|
|
NSSModule *mod
|
|
)
|
|
{
|
|
PRUint32 i;
|
|
NSSSlot **rvSlots;
|
|
rvSlots = nss_ZNEWARRAY(NULL, NSSSlot *, mod->numSlots + 1);
|
|
if (rvSlots) {
|
|
for (i=0; i<mod->numSlots; i++) {
|
|
rvSlots[i] = nssSlot_AddRef(mod->slots[i]);
|
|
}
|
|
}
|
|
return rvSlots;
|
|
}
|
|
|
|
NSS_IMPLEMENT NSSSlot *
|
|
nssModule_FindSlotByName (
|
|
NSSModule *mod,
|
|
NSSUTF8 *slotName
|
|
)
|
|
{
|
|
PRUint32 i;
|
|
PRStatus nssrv;
|
|
NSSSlot *slot;
|
|
NSSUTF8 *name;
|
|
for (i=0; i<mod->numSlots; i++) {
|
|
slot = mod->slots[i];
|
|
name = nssSlot_GetName(slot);
|
|
if (nssUTF8_Equal(name, slotName, &nssrv)) {
|
|
return nssSlot_AddRef(slot);
|
|
}
|
|
if (nssrv != PR_SUCCESS) {
|
|
break;
|
|
}
|
|
}
|
|
return (NSSSlot *)NULL;
|
|
}
|
|
|
|
NSS_IMPLEMENT NSSToken *
|
|
nssModule_FindTokenByName (
|
|
NSSModule *mod,
|
|
NSSUTF8 *tokenName
|
|
)
|
|
{
|
|
PRUint32 i;
|
|
PRStatus nssrv;
|
|
NSSToken *tok;
|
|
NSSUTF8 *name;
|
|
for (i=0; i<mod->numSlots; i++) {
|
|
tok = nssSlot_GetToken(mod->slots[i]);
|
|
if (tok) {
|
|
name = nssToken_GetName(tok);
|
|
if (nssUTF8_Equal(name, tokenName, &nssrv)) {
|
|
return tok;
|
|
}
|
|
if (nssrv != PR_SUCCESS) {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
return (NSSToken *)NULL;
|
|
}
|
|
|
|
NSS_IMPLEMENT PRInt32
|
|
nssModule_GetCertOrder (
|
|
NSSModule *module
|
|
)
|
|
{
|
|
return 1; /* XXX */
|
|
}
|
|
|
|
#endif /* PURE_STAN_BUILD */
|
|
|