pjs/security/psm/server/pkcs11ui.c

962 строки
26 KiB
C

/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
* 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 Netscape are
* Copyright (C) 1994-2000 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
*
* Alternatively, the contents of this file may be used under the
* terms of the GNU General Public License Version 2 or later (the
* "GPL"), in which case the provisions of the GPL are applicable
* instead of those above. If you wish to allow use of your
* version of this file only under the terms of the GPL and not to
* allow others to use your version of this file under the MPL,
* indicate your decision by deleting the provisions above and
* replace them with the notice and other provisions required by
* the GPL. If you do not delete the provisions above, a recipient
* may use your version of this file under either the MPL or the
* GPL.
*/
#include "pkcs11ui.h"
#include "pkcs11.h"
#include "pk11func.h"
#include "plstr.h"
#include "secmod.h"
#include "secmodti.h"
#include "minihttp.h"
#include "textgen.h"
/* Utility */
PK11SlotInfo *
SSMPKCS11_FindSlotByID(SECMODModuleID modID,
CK_SLOT_ID slotID)
{
SECMODModule *mod = NULL;
PRIntn i;
mod = SECMOD_FindModuleByID(modID);
if (mod)
{
for(i=0;i<mod->slotCount;i++)
{
if (mod->slots[i]->slotID == slotID)
return mod->slots[i];
}
}
return NULL;
}
/*
---------------------------------------------------------
PKCS11 module processing (list, add, delete)
---------------------------------------------------------
*/
SSMStatus
ssmpkcs11_convert_module(SSMTextGenContext *cx,
PRInt32 modIndex,
SECMODModule *mod,
char *fmt)
{
char *dllName = NULL;
char *tempStr = NULL;
char *lib_ch = NULL;
CK_INFO modInfo;
SSMStatus rv = SSM_FAILURE;
SECStatus srv;
/* 65? Why 65??? It's what's was used in the original UI. */
char buf[65];
char buf2[65];
srv = PK11_GetModInfo(mod, &modInfo);
if (srv != SECSuccess)
goto loser;
/* we provide the space in (buf), so we don't deallocate lib_ch */
lib_ch = PK11_MakeString(NULL,buf2,(char *)modInfo.libraryDescription,
sizeof(modInfo.libraryDescription));
if (mod->dllName)
{
char *cursor, *newString;
int numSlashes = 0, newLen, i, j, oldLen;
dllName = mod->dllName;
/*
* Now we need to escape the '\' characters so the string shows
* up correctly in the UI.
*/
/* First count them to see if we even need to re-allocate*/
cursor = dllName;
while ((cursor = PL_strchr(cursor, '\\')) != NULL) {
numSlashes++;
cursor++;
}
if (numSlashes > 0) {
oldLen = PL_strlen(dllName);
newLen = oldLen + numSlashes + 1;
newString = SSM_NEW_ARRAY(char, newLen);
/*
* If we can't allocate a new buffer, then let's just display
* the original string. That's better than not displaying
* anything.
*/
if (newString != NULL) {
for (i=0, j=0; i<oldLen+1; i++,j++){
newString[j] = dllName[i];
if (newString[j] == '\\'){
newString[j+1] = '\\';
j++;
}
}
dllName = newString;
}
}
}
else
{
rv = SSM_GetAndExpandText(cx, "text_pk11_no_dll", &dllName);
if (rv != SSM_SUCCESS)
goto loser;
}
PR_snprintf(buf, sizeof(buf), "%d.%d",
modInfo.libraryVersion.major, modInfo.libraryVersion.minor);
tempStr = PR_smprintf(fmt, modIndex, (long)mod->moduleID, lib_ch,
mod->commonName, dllName, buf);
if (tempStr == NULL) {
rv = SSM_FAILURE;
goto loser;
}
rv = SSM_ConcatenateUTF8String(&cx->m_result, tempStr);
loser:
if (dllName && dllName != mod->dllName)
PR_Free(dllName);
PR_FREEIF (tempStr);
return rv;
}
/*
PKCS11 module list keyword handler.
Syntax: {_pk11modules <wrapper_key>}
*/
SSMStatus
SSM_PKCS11ModulesKeywordHandler(SSMTextGenContext *cx)
{
SSMStatus rv = SSM_SUCCESS;
char *wrapperKey = NULL;
char *wrapperStr = NULL;
SECMODModuleList *modList = SECMOD_GetDefaultModuleList();
SECMODModuleList *modWalk = NULL;
SECMODListLock *modLock = SECMOD_GetDefaultModuleListLock();
PRBool gotLock = PR_FALSE; /* indicates whether we should release at end */
PRInt32 i=0;
/* Check for parameter validity */
PR_ASSERT(cx);
PR_ASSERT(cx->m_request);
PR_ASSERT(cx->m_params);
PR_ASSERT(cx->m_result);
if (!cx || !cx->m_request || !cx->m_params || !cx->m_result)
{
rv = PR_INVALID_ARGUMENT_ERROR;
goto real_loser; /* really bail here */
}
if (SSM_Count(cx->m_params) != 1)
{
SSM_HTTPReportSpecificError(cx->m_request, "_certList: "
"Incorrect number of parameters "
"(%d supplied, 1 needed).\n",
SSM_Count(cx->m_params));
goto user_loser;
}
/* Convert parameters to something we can use in finding certs. */
wrapperKey = (char *) SSM_At(cx->m_params, 0);
PR_ASSERT(wrapperKey);
/* Get the wrapper text. */
rv = SSM_GetAndExpandTextKeyedByString(cx, wrapperKey, &wrapperStr);
if (rv != SSM_SUCCESS)
goto real_loser; /* error string set by the called function */
/* Iterate over the PKCS11 modules. Put relevant info from each
into its own copy of the wrapper text. */
SECMOD_GetReadLock(modLock);
gotLock = PR_TRUE;
modWalk = modList;
while (modWalk)
{
rv = ssmpkcs11_convert_module(cx, i++, modWalk->module, wrapperStr);
modWalk = modWalk->next;
}
goto done;
user_loser:
/* If we reach this point, something in the input is wrong, but we
can still send something back to the client to indicate that a
problem has occurred. */
/* If we can't do what we're about to do, really bail. */
if (!cx->m_request || !cx->m_request->errormsg)
goto real_loser;
/* Clear the string we were accumulating. */
SSMTextGen_UTF8StringClear(&cx->m_result);
/* Use the result string given to us to explain what happened. */
SSM_ConcatenateUTF8String(&cx->m_result, cx->m_request->errormsg);
/* Clear the result string, since we're sending this inline */
SSMTextGen_UTF8StringClear(&cx->m_request->errormsg);
goto done;
real_loser:
/* If we reach this point, then we are so screwed that we cannot
send anything vaguely normal back to the client. Bail. */
if (rv == SSM_SUCCESS) rv = SSM_FAILURE;
done:
PR_FREEIF(wrapperStr);
if (modLock && gotLock)
SECMOD_ReleaseReadLock(modLock);
return rv;
}
/*
---------------------------------------------------------
PKCS11 slot code
---------------------------------------------------------
*/
enum
{
SSM_PK11STR_SLOT_LOGGED_IN = (long) 0,
SSM_PK11STR_SLOT_NOT_LOGGED_IN,
SSM_PK11STR_SLOT_NO_LOGIN_REQUIRED,
SSM_PK11STR_SLOT_NOT_PRESENT,
SSM_PK11STR_SLOT_UNINITIALIZED,
SSM_PK11STR_SLOT_DISABLED,
SSM_PK11STR_SLOT_READY,
SSM_PK11STR_SLOT_STRING_COUNT
};
static char *slotStringKeys[] =
{
"text_pk11_slot_logged_in",
"text_pk11_slot_not_logged_in",
"text_pk11_slot_no_login_required",
"text_pk11_slot_not_present",
"text_pk11_slot_uninitialized",
"text_pk11_slot_disabled",
"text_pk11_slot_ready"
};
static char **slotStrings = NULL;
void
ssmpkcs11_initialize_slot_labels(SSMTextGenContext *cx)
{
SSMStatus rv = SSM_SUCCESS;
PRIntn i;
slotStrings = (char **) PR_Calloc(SSM_PK11STR_SLOT_STRING_COUNT + 1,
sizeof(char**));
PR_ASSERT(slotStrings);
for(i=0;i<SSM_PK11STR_SLOT_STRING_COUNT;i++)
{
rv = SSM_FindUTF8StringInBundles(cx, slotStringKeys[i],
&slotStrings[i]);
PR_ASSERT(rv == SSM_SUCCESS);
}
}
SSMStatus
ssmpkcs11_convert_slot(SSMTextGenContext *cx,
PRInt32 slotIndex,
PK11SlotInfo *slot,
char *fmt,
PRBool accumulate) /* accumulate in cx->m_result? */
{
char *name = NULL;
char *statusStr = NULL;
char *serial = NULL;
char *version = NULL;
char *tempStr = NULL;
long status, slotID = 0, moduleID = 0;
CK_TOKEN_INFO tokenInfo;
SSMStatus rv = SSM_FAILURE;
SECStatus srv = SECSuccess;
/* 65? Why 65??? It's what's was used in the original UI. */
char buf[65];
char empty[1] = { '\0' } ;
if (!slotStrings)
ssmpkcs11_initialize_slot_labels(cx);
/* If we have a NULL slot, return blank information. */
if (!slot)
{
name = empty;
statusStr = empty;
serial = empty;
version = empty;
slotID = 0;
goto show_stuff;
}
/* Get the slot name. Either the default name or the name of the token
in the slot will be used. */
if (PK11_IsPresent(slot))
name = PK11_GetTokenName(slot);
else
name = PK11_GetSlotName(slot);
/* Report the status of the slot. */
if (PK11_IsDisabled(slot))
status = SSM_PK11STR_SLOT_DISABLED;
else if (!PK11_IsPresent(slot))
status = SSM_PK11STR_SLOT_NOT_PRESENT;
else if (PK11_NeedLogin(slot) && PK11_NeedUserInit(slot))
status = SSM_PK11STR_SLOT_UNINITIALIZED;
else if (PK11_NeedLogin(slot) && !PK11_IsLoggedIn(slot, NULL))
status = SSM_PK11STR_SLOT_NOT_LOGGED_IN;
else if (PK11_NeedLogin(slot))
status = SSM_PK11STR_SLOT_LOGGED_IN;
else
status = SSM_PK11STR_SLOT_READY;
statusStr = slotStrings[status];
/* Get the serial number and version. */
/* This is how the old UI determines if there's a token in, so... */
if (PK11_IsPresent(slot))
srv = PK11_GetTokenInfo(slot, &tokenInfo);
if (PK11_IsPresent(slot) && (srv == SECSuccess))
{
/* Get serial number and version from the token info. */
serial = PK11_MakeString(NULL, NULL, (char*)tokenInfo.serialNumber,
sizeof(tokenInfo.serialNumber));
PR_snprintf(buf, sizeof(buf), "%d.%d",
tokenInfo.firmwareVersion.major,
tokenInfo.firmwareVersion.minor);
version = buf;
}
else
{
/* Get serial number and version from the slot info. */
CK_SLOT_INFO slotInfo;
srv = PK11_GetSlotInfo(slot, &slotInfo);
if (srv != SECSuccess)
goto loser;
serial = empty;
PR_snprintf(buf, sizeof(buf), "%d.%d",
slotInfo.firmwareVersion.major,
slotInfo.firmwareVersion.minor);
version = buf;
}
slotID = (long) (slot->slotID);
moduleID = (long) (slot->module->moduleID);
show_stuff:
tempStr = PR_smprintf(fmt, slotIndex, slotID, moduleID, name,
statusStr, serial, version);
if (accumulate)
{
rv = SSM_ConcatenateUTF8String(&cx->m_result, tempStr);
if (rv != SSM_SUCCESS) {
goto loser;
}
}
else
rv = SSM_HTTPSendUTF8String(cx->m_request, tempStr);
loser:
/* The data that isn't freed is either because it's a member of the
* data in a structure of the PK11 libraries or its a static local
* variable.
*/
if (serial && serial != empty)
PR_Free(serial);
PR_FREEIF(tempStr);
return rv;
}
/*
PKCS11 slot list keyword handler.
Syntax: {_pk11slots <moduleID>,<wrapper_key>}
*/
SSMStatus
SSM_PKCS11SlotsKeywordHandler(SSMTextGenContext *cx)
{
SSMStatus rv = SSM_SUCCESS;
SECMODModule *module = NULL;
char *wrapperKey = NULL;
char *moduleIDStr = NULL;
long moduleID;
char *wrapperStr = NULL;
PRInt32 i=0;
/* Check for parameter validity */
PR_ASSERT(cx);
PR_ASSERT(cx->m_request);
PR_ASSERT(cx->m_params);
PR_ASSERT(cx->m_result);
if (!cx || !cx->m_request || !cx->m_params || !cx->m_result)
{
rv = PR_INVALID_ARGUMENT_ERROR;
goto real_loser; /* really bail here */
}
if (SSM_Count(cx->m_params) != 2)
{
SSM_HTTPReportSpecificError(cx->m_request, "_certList: "
"Incorrect number of parameters "
"(%d supplied, 2 needed).\n",
SSM_Count(cx->m_params));
goto user_loser;
}
/* Convert parameters to something we can use in finding certs. */
moduleIDStr = (char *) SSM_At(cx->m_params, 0);
PR_ASSERT(moduleIDStr);
wrapperKey = (char *) SSM_At(cx->m_params, 1);
PR_ASSERT(wrapperKey);
/* Find the module we're looking for based on the module ID. */
module = SECMOD_FindModuleByID((SECMODModuleID) moduleID);
if (!module)
goto user_loser;
/* Get the wrapper text. */
rv = SSM_GetAndExpandTextKeyedByString(cx, wrapperKey, &wrapperStr);
if (rv != SSM_SUCCESS)
goto real_loser; /* error string set by the called function */
/* Iterate over the slots from this module. Put relevant info from each
into its own copy of the wrapper text. */
for(i=0;i<module->slotCount;i++)
{
rv = ssmpkcs11_convert_slot(cx, i, module->slots[i], wrapperStr,
PR_TRUE);
if (rv != SSM_SUCCESS)
goto user_loser;
}
goto done;
user_loser:
/* If we reach this point, something in the input is wrong, but we
can still send something back to the client to indicate that a
problem has occurred. */
/* If we can't do what we're about to do, really bail. */
if (!cx->m_request || !cx->m_request->errormsg)
goto real_loser;
/* Clear the string we were accumulating. */
SSMTextGen_UTF8StringClear(&cx->m_result);
/* Use the result string given to us to explain what happened. */
SSM_ConcatenateUTF8String(&cx->m_result, cx->m_request->errormsg);
/* Clear the result string, since we're sending this inline */
SSMTextGen_UTF8StringClear(&cx->m_request->errormsg);
goto done;
real_loser:
/* If we reach this point, then we are so screwed that we cannot
send anything vaguely normal back to the client. Bail. */
if (rv == SSM_SUCCESS) rv = SSM_FAILURE;
done:
PR_FREEIF(wrapperStr);
if (module)
SECMOD_DestroyModule(module);
return rv;
}
SSMStatus
ssm_pkcs11_chuck_property(SSMTextGenContext *cx, char *propName)
{
char *text = NULL;
SSMStatus rv;
rv = SSM_GetAndExpandText(cx, propName, &text);
if (rv != SSM_SUCCESS)
goto loser;
rv = SSM_HTTPSendUTF8String(cx->m_request, text);
loser:
PR_FREEIF(text);
SSMTextGen_UTF8StringClear(&cx->m_result);
return rv;
}
/* PKCS11ShowSlots?module=<moduleID> */
SSMStatus
SSM_ShowSlotsCommandHandler(HTTPRequest *req)
{
SSMTextGenContext *cx = NULL;
char *tmpl = NULL, *type = NULL;
char *nomod_ch = NULL;
char *modID_ch = NULL;
long moduleID;
SECMODModule *module = NULL;
PRIntn i;
SSMStatus rv;
/* If we have a "no_module" parameter, then there
is no module for which to load slots. */
rv = SSM_HTTPParamValue(req, "no_module", &nomod_ch);
if (rv == SSM_SUCCESS)
goto display_stuff;
rv = SSM_HTTPParamValue(req, "module", &modID_ch);
if (rv != SSM_SUCCESS)
goto display_stuff;
if (modID_ch)
{
/* Convert the module ID into a real module ID. */
PR_sscanf(modID_ch, "%ld", &moduleID);
/* Find the module we're looking for based on the module ID. */
module = SECMOD_FindModuleByID((SECMODModuleID) moduleID);
if (!module)
goto loser;
}
display_stuff:
/* Make a new top-level text gen context to chuck text back. */
rv = SSMTextGen_NewTopLevelContext(req, &cx);
if (rv != SSM_SUCCESS)
goto loser;
rv = SSM_GetAndExpandText(cx, "adv_modules_slotlist_type", &type);
if (rv != SSM_SUCCESS)
goto loser;
rv = SSM_HTTPSendOKHeader(req, NULL, type);
if (rv != SSM_SUCCESS)
goto loser;
/* Chuck out part 1. */
rv = ssm_pkcs11_chuck_property(cx, "adv_modules_slotlist_part1");
if (rv != SSM_SUCCESS)
goto loser;
/* Get the template for the JS slot list. */
rv = SSM_GetAndExpandText(cx, "adv_modules_slotlist_js_template", &tmpl);
if (rv != SSM_SUCCESS)
goto loser;
/* Iterate over the slots from this module. Put relevant info from each
into its own copy of the wrapper text. */
if (module)
{
for(i=0;i<module->slotCount;i++)
{
rv = ssmpkcs11_convert_slot(cx, i, module->slots[i], tmpl,
PR_FALSE);
if (rv != SSM_SUCCESS)
goto loser;
}
}
PR_Free(tmpl);
tmpl = NULL;
/* Chuck out part 2. */
rv = ssm_pkcs11_chuck_property(cx, "adv_modules_slotlist_part2");
if (rv != SSM_SUCCESS)
goto loser;
/* Get the template for the selectable slot list. */
rv = SSM_GetAndExpandText(cx, "adv_modules_slotlist_select_template", &tmpl);
if (rv != SSM_SUCCESS)
goto loser;
/* Iterate over the slots from this module. Put relevant info from each
into its own copy of the wrapper text. */
if (module)
{
for(i=0;i<module->slotCount;i++)
{
rv = ssmpkcs11_convert_slot(cx, i, module->slots[i], tmpl,
PR_FALSE);
if (rv != SSM_SUCCESS)
goto loser;
}
}
/* Chuck out part 3. */
rv = ssm_pkcs11_chuck_property(cx, "adv_modules_slotlist_part3");
req->sentResponse = PR_TRUE;
goto done;
loser:
if (rv == SSM_SUCCESS) rv = SSM_FAILURE;
done:
if (cx)
SSMTextGen_DestroyContext(cx);
PR_FREEIF(tmpl);
return rv;
}
SSMStatus
ssm_find_module_from_request(HTTPRequest *req, SECMODModule **mod)
{
char *modID_ch = NULL;
PRInt32 moduleID;
SSMStatus rv;
rv = SSM_HTTPParamValue(req, "module", &modID_ch);
if (rv != SSM_SUCCESS)
goto done;
if (modID_ch)
{
/* Convert the module ID into a real module ID. */
PR_sscanf(modID_ch, "%ld", &moduleID);
/* Find the module we're looking for based on the module ID. */
*mod = SECMOD_FindModuleByID((SECMODModuleID) moduleID);
}
done:
if ((!*mod) && (rv == SSM_SUCCESS))
rv = SSM_FAILURE;
return rv;
}
PK11SlotInfo *
find_slot_by_ID(SECMODModule *mod, CK_SLOT_ID slotID)
{
int i;
PK11SlotInfo *slot;
for (i=0; i < mod->slotCount; i++) {
slot = mod->slots[i];
if (slot->slotID == (CK_SLOT_ID) slotID)
return PK11_ReferenceSlot(slot);
}
return NULL;
}
SSMStatus
ssm_find_slot_from_request(HTTPRequest *req, PK11SlotInfo **slot)
{
char *slotID_ch = NULL;
PRInt32 slotID;
SECMODModule *mod;
SSMStatus rv = SSM_SUCCESS;
rv = ssm_find_module_from_request(req, &mod);
if (rv != SSM_SUCCESS)
goto done;
rv = SSM_HTTPParamValue(req, "slot", &slotID_ch);
if (rv != SSM_SUCCESS)
goto done;
if (slotID_ch)
{
/* Convert the module ID into a real module ID. */
PR_sscanf(slotID_ch, "%ld", &slotID);
/* Find the module we're looking for based on the module ID. */
*slot = find_slot_by_ID(mod, (CK_SLOT_ID) slotID);
}
done:
if ((!*slot) && (rv == SSM_SUCCESS))
rv = SSM_FAILURE;
return rv;
}
SSMStatus
ssmpkcs11_show_slot_info(HTTPRequest *req, PK11SlotInfo *slot)
{
char *wrapperStr = NULL;
char *tmpl = NULL;
char *type = NULL;
SSMTextGenContext *cx;
SSMStatus rv;
/* Make a new top-level text gen context to chuck text back. */
rv = SSMTextGen_NewTopLevelContext(req, &cx);
if (rv != SSM_SUCCESS)
goto loser;
rv = SSM_GetAndExpandText(cx, "adv_modules_slot_info_type", &type);
if (rv != SSM_SUCCESS)
goto loser;
rv = SSM_HTTPSendOKHeader(req, NULL, type);
if (rv != SSM_SUCCESS)
goto loser;
rv = SSM_GetAndExpandText(cx, "adv_modules_slot_info_content", &wrapperStr);
if (rv != SSM_SUCCESS)
goto loser; /* error string set by the called function */
rv = ssmpkcs11_convert_slot(cx, 0, slot, wrapperStr, PR_FALSE);
goto done;
loser:
if (rv == SSM_SUCCESS) rv = SSM_FAILURE;
done:
if (cx)
SSMTextGen_DestroyContext(cx);
PR_FREEIF(tmpl);
PR_FREEIF(type);
PR_FREEIF(wrapperStr);
return rv;
}
SSMStatus
SSM_ShowSlotCommandHandler(HTTPRequest *req)
{
SSMStatus rv;
PK11SlotInfo *slot;
/* Find the slot. */
rv = ssm_find_slot_from_request(req, &slot);
if (rv != SSM_SUCCESS)
goto loser;
/* Display the slot info. */
rv = ssmpkcs11_show_slot_info(req, slot);
req->sentResponse = PR_TRUE;
loser:
if (slot)
PK11_FreeSlot(slot);
return rv;
}
SSMStatus
SSM_LoginSlotCommandHandler(HTTPRequest *req)
{
SSMStatus rv;
PK11SlotInfo *slot;
/* Find the slot. */
rv = ssm_find_slot_from_request(req, &slot);
if (rv != SSM_SUCCESS)
goto loser;
/* Log into the slot. */
PK11_Authenticate(slot, PR_TRUE, req->ctrlconn);
/* Display the slot info. */
rv = ssmpkcs11_show_slot_info(req, slot);
req->sentResponse = PR_TRUE;
loser:
if (slot)
PK11_FreeSlot(slot);
return rv;
}
SSMStatus
SSM_LogoutSlotCommandHandler(HTTPRequest *req)
{
SSMStatus rv;
PK11SlotInfo *slot;
/* Find the slot. */
rv = ssm_find_slot_from_request(req, &slot);
if (rv != SSM_SUCCESS)
goto loser;
/* Log out of the slot. */
PK11_Logout(slot);
/* Display the slot info. */
rv = ssmpkcs11_show_slot_info(req, slot);
req->sentResponse = PR_TRUE;
loser:
if (slot)
PK11_FreeSlot(slot);
return rv;
}
SSMStatus
SSM_LogoutAllSlotsCommandHandler(HTTPRequest *req)
{
SSMStatus rv;
PK11SlotInfo *slot;
/* Find the slot. */
rv = ssm_find_slot_from_request(req, &slot);
/* Not relevant if we find the slot here,
just remember to display (or not) whatever slot we have */
if (rv != SSM_SUCCESS)
slot = NULL;
/* Log out of all slots. */
PK11_LogoutAll();
/* Display the slot info (if any). */
rv = ssmpkcs11_show_slot_info(req, slot);
req->sentResponse = PR_TRUE;
if (slot)
PK11_FreeSlot(slot);
return rv;
}
/*
---------------------------------------------------------
FIPS mode code
---------------------------------------------------------
*/
/*
FIPS mode keyword handler.
Syntax: {_fipsmode <true_text>,<false_text>}
where <true_text> is displayed if FIPS mode is on, <false_text> otherwise.
*/
SSMStatus
SSM_PKCS11FIPSModeKeywordHandler(SSMTextGenContext *cx)
{
SSMStatus rv = SSM_SUCCESS;
char *param = NULL;
char *tempStr = NULL;
PR_ASSERT(cx);
PR_ASSERT(cx->m_params);
PR_ASSERT(cx->m_result);
if (!cx || !cx->m_params || !cx->m_result)
{
rv = PR_INVALID_ARGUMENT_ERROR;
goto loser;
}
/* Figure out if we're in FIPS mode. */
if (PK11_IsFIPS())
param = (char *) SSM_At(cx->m_params, 0);
else
param = (char *) SSM_At(cx->m_params, 1);
/* Display the appropriate string. */
rv = SSMTextGen_SubstituteString(cx, param, &tempStr);
if (rv != SSM_SUCCESS)
goto loser; /* error string set by the called function */
rv = SSM_ConcatenateUTF8String(&cx->m_result, tempStr);
if (rv == SSM_SUCCESS)
goto done;
loser:
if (rv == SSM_SUCCESS) rv = SSM_FAILURE;
done:
PR_FREEIF(tempStr);
return rv;
}
void
SSM_TrimTrailingWhitespace(char *str)
{
char *end = &(str[strlen(str)]);
char *start = str;
do
{
end--;
}
while ((end >= start) &&
((*end == ' ') || (*end == '\0')));
*(++end) = '\0';
}
/*
Command handler to set FIPS mode.
Syntax: setFIPSMode?fips={on|off}&baseRef=<baseRef>&target=<ctrlconn>
*/
SSMStatus
SSM_SetFIPSModeCommandHandler(HTTPRequest *req)
{
char *fips_ch = NULL, *baseRef_ch = NULL;
SECStatus srv = SECSuccess;
PRBool oldFIPS, newFIPS;
SSMStatus rv = SSM_SUCCESS;
rv = SSM_HTTPParamValue(req, "fips", &fips_ch);
if (rv != SSM_SUCCESS)
goto loser;
newFIPS = !PL_strncmp(fips_ch, "on", 2);
oldFIPS = PK11_IsFIPS();
if (newFIPS != oldFIPS)
{
/*
Turning FIPS mode on/off requires the exact same operation:
deleting the built-in PKCS11 module.
### mwelch We need these calls to differentiate between
secmod dbs!
*/
SECMODModule *internal;
CK_INFO modInfo;
internal = SECMOD_GetInternalModule();
if (!internal)
goto loser;
srv = PK11_GetModInfo(internal, &modInfo);
if (srv != SECSuccess)
goto loser;
SSM_TrimTrailingWhitespace((char*) modInfo.libraryDescription);
/* Delete the {FIPS,non-FIPS} internal module, so that
it will be replaced by the {non-FIPS,FIPS} counterpart. */
srv = SECMOD_DeleteInternalModule(internal->commonName);
if (srv != SECSuccess)
goto loser;
}
/* if there's a baseRef, send it back. otherwise, no content. */
rv = SSM_HTTPParamValue(req, "baseRef", &baseRef_ch);
if (rv == SSM_SUCCESS)
{
/* send what was requested */
rv = SSM_HTTPCloseAndSleep(req);
}
goto done;
loser:
if (rv == SSM_SUCCESS) rv = SSM_FAILURE;
SSM_HTTPReportSpecificError(req, "SetFIPSModeCommandHandler: Error %d "
"attempting to change FIPS mode.",
srv != SECSuccess ? srv : rv);
done:
return rv;
}