diff options
Diffstat (limited to 'security/manager/pki/resources/content/device_manager.js')
-rw-r--r-- | security/manager/pki/resources/content/device_manager.js | 509 |
1 files changed, 509 insertions, 0 deletions
diff --git a/security/manager/pki/resources/content/device_manager.js b/security/manager/pki/resources/content/device_manager.js new file mode 100644 index 000000000..7d16c5888 --- /dev/null +++ b/security/manager/pki/resources/content/device_manager.js @@ -0,0 +1,509 @@ +/* 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/. */ +"use strict"; + +const nsIFilePicker = Components.interfaces.nsIFilePicker; +const nsFilePicker = "@mozilla.org/filepicker;1"; +const nsIPKCS11Slot = Components.interfaces.nsIPKCS11Slot; +const nsIPKCS11Module = Components.interfaces.nsIPKCS11Module; +const nsPKCS11ModuleDB = "@mozilla.org/security/pkcs11moduledb;1"; +const nsIPKCS11ModuleDB = Components.interfaces.nsIPKCS11ModuleDB; +const nsIPK11Token = Components.interfaces.nsIPK11Token; +const nsPK11TokenDB = "@mozilla.org/security/pk11tokendb;1"; +const nsIPK11TokenDB = Components.interfaces.nsIPK11TokenDB; +const nsIDialogParamBlock = Components.interfaces.nsIDialogParamBlock; +const nsDialogParamBlock = "@mozilla.org/embedcomp/dialogparam;1"; +const nsIPKCS11 = Components.interfaces.nsIPKCS11; +const nsPKCS11ContractID = "@mozilla.org/security/pkcs11;1"; + +var { Services } = Components.utils.import("resource://gre/modules/Services.jsm", {}); + +var bundle; +var secmoddb; +var skip_enable_buttons = false; + +var smartCardObserver = { + observe: function() { + onSmartCardChange(); + } +}; + +function DeregisterSmartCardObservers() +{ + Services.obs.removeObserver(smartCardObserver, "smartcard-insert"); + Services.obs.removeObserver(smartCardObserver, "smartcard-remove"); +} + +/* Do the initial load of all PKCS# modules and list them. */ +function LoadModules() +{ + bundle = document.getElementById("pippki_bundle"); + secmoddb = Components.classes[nsPKCS11ModuleDB].getService(nsIPKCS11ModuleDB); + Services.obs.addObserver(smartCardObserver, "smartcard-insert", false); + Services.obs.addObserver(smartCardObserver, "smartcard-remove", false); + + RefreshDeviceList(); +} + +function getPKCS11() +{ + return Components.classes[nsPKCS11ContractID].getService(nsIPKCS11); +} + +function getNSSString(name) +{ + return document.getElementById("pipnss_bundle").getString(name); +} + +function doPrompt(msg) +{ + let prompts = Components.classes["@mozilla.org/embedcomp/prompt-service;1"]. + getService(Components.interfaces.nsIPromptService); + prompts.alert(window, null, msg); +} + +function doConfirm(msg) +{ + let prompts = Components.classes["@mozilla.org/embedcomp/prompt-service;1"]. + getService(Components.interfaces.nsIPromptService); + return prompts.confirm(window, null, msg); +} + +function RefreshDeviceList() +{ + let modules = secmoddb.listModules(); + while (modules.hasMoreElements()) { + let module = modules.getNext().QueryInterface(nsIPKCS11Module); + let slotnames = []; + let slots = module.listSlots(); + while (slots.hasMoreElements()) { + let slot = slots.getNext().QueryInterface(nsIPKCS11Slot); + // Token names are preferred because NSS prefers lookup by token name. + slotnames.push(slot.tokenName ? slot.tokenName : slot.name); + } + AddModule(module.name, slotnames); + } + + // Set the text on the FIPS button. + SetFIPSButton(); +} + +function SetFIPSButton() +{ + var fipsButton = document.getElementById("fipsbutton"); + var label; + if (secmoddb.isFIPSEnabled) { + label = bundle.getString("disable_fips"); + } else { + label = bundle.getString("enable_fips"); + } + fipsButton.setAttribute("label", label); + + var can_toggle = secmoddb.canToggleFIPS; + if (can_toggle) { + fipsButton.removeAttribute("disabled"); + } else { + fipsButton.setAttribute("disabled", "true"); + } +} + +/* Add a module to the tree. slots is the array of slots in the module, + * to be represented as children. + */ +function AddModule(module, slots) +{ + var tree = document.getElementById("device_list"); + var item = document.createElement("treeitem"); + var row = document.createElement("treerow"); + var cell = document.createElement("treecell"); + cell.setAttribute("label", module); + row.appendChild(cell); + item.appendChild(row); + var parent = document.createElement("treechildren"); + for (let slot of slots) { + var child_item = document.createElement("treeitem"); + var child_row = document.createElement("treerow"); + var child_cell = document.createElement("treecell"); + child_cell.setAttribute("label", slot); + child_row.appendChild(child_cell); + child_item.appendChild(child_row); + child_item.setAttribute("pk11kind", "slot"); + parent.appendChild(child_item); + } + item.appendChild(parent); + item.setAttribute("pk11kind", "module"); + item.setAttribute("open", "true"); + item.setAttribute("container", "true"); + tree.appendChild(item); +} + +var selected_slot; +var selected_module; + +/* get the slot selected by the user (can only be one-at-a-time) */ +function getSelectedItem() +{ + var tree = document.getElementById('device_tree'); + if (tree.currentIndex < 0) return; + var item = tree.contentView.getItemAtIndex(tree.currentIndex); + selected_slot = null; + selected_module = null; + if (item) { + var kind = item.getAttribute("pk11kind"); + var module_name; + if (kind == "slot") { + // get the module cell for this slot cell + var cell = item.parentNode.parentNode.firstChild.firstChild; + module_name = cell.getAttribute("label"); + var module = secmoddb.findModuleByName(module_name); + // get the cell for the selected row (the slot to display) + cell = item.firstChild.firstChild; + var slot_name = cell.getAttribute("label"); + selected_slot = module.findSlotByName(slot_name); + } else { // (kind == "module") + // get the cell for the selected row (the module to display) + cell = item.firstChild.firstChild; + module_name = cell.getAttribute("label"); + selected_module = secmoddb.findModuleByName(module_name); + } + } +} + +function enableButtons() +{ + if (skip_enable_buttons) { + return; + } + + var login_toggle = "true"; + var logout_toggle = "true"; + var pw_toggle = "true"; + var unload_toggle = "true"; + getSelectedItem(); + if (selected_module) { + unload_toggle = "false"; + showModuleInfo(); + } else if (selected_slot) { + // here's the workaround - login functions are all with token, + // so grab the token type + var selected_token = selected_slot.getToken(); + if (selected_token != null) { + if (selected_token.needsLogin() || !(selected_token.needsUserInit)) { + pw_toggle = "false"; + if (selected_token.needsLogin()) { + if (selected_token.isLoggedIn()) { + logout_toggle = "false"; + } else { + login_toggle = "false"; + } + } + } + } + showSlotInfo(); + } + var thebutton = document.getElementById('login_button'); + thebutton.setAttribute("disabled", login_toggle); + thebutton = document.getElementById('logout_button'); + thebutton.setAttribute("disabled", logout_toggle); + thebutton = document.getElementById('change_pw_button'); + thebutton.setAttribute("disabled", pw_toggle); + thebutton = document.getElementById('unload_button'); + thebutton.setAttribute("disabled", unload_toggle); + // not implemented + //thebutton = document.getElementById('change_slotname_button'); + //thebutton.setAttribute("disabled", toggle); +} + +// clear the display of information for the slot +function ClearInfoList() +{ + let infoList = document.getElementById("info_list"); + while (infoList.hasChildNodes()) { + infoList.removeChild(infoList.firstChild); + } +} + +function ClearDeviceList() +{ + ClearInfoList(); + + skip_enable_buttons = true; + var tree = document.getElementById('device_tree'); + tree.view.selection.clearSelection(); + skip_enable_buttons = false; + + // Remove the existing listed modules so that a refresh doesn't display the + // module that just changed. + let deviceList = document.getElementById("device_list"); + while (deviceList.hasChildNodes()) { + deviceList.removeChild(deviceList.firstChild); + } +} + + +// show a list of info about a slot +function showSlotInfo() +{ + var present = true; + ClearInfoList(); + switch (selected_slot.status) { + case nsIPKCS11Slot.SLOT_DISABLED: + AddInfoRow(bundle.getString("devinfo_status"), + bundle.getString("devinfo_stat_disabled"), + "tok_status"); + present = false; + break; + case nsIPKCS11Slot.SLOT_NOT_PRESENT: + AddInfoRow(bundle.getString("devinfo_status"), + bundle.getString("devinfo_stat_notpresent"), + "tok_status"); + present = false; + break; + case nsIPKCS11Slot.SLOT_UNINITIALIZED: + AddInfoRow(bundle.getString("devinfo_status"), + bundle.getString("devinfo_stat_uninitialized"), + "tok_status"); + break; + case nsIPKCS11Slot.SLOT_NOT_LOGGED_IN: + AddInfoRow(bundle.getString("devinfo_status"), + bundle.getString("devinfo_stat_notloggedin"), + "tok_status"); + break; + case nsIPKCS11Slot.SLOT_LOGGED_IN: + AddInfoRow(bundle.getString("devinfo_status"), + bundle.getString("devinfo_stat_loggedin"), + "tok_status"); + break; + case nsIPKCS11Slot.SLOT_READY: + AddInfoRow(bundle.getString("devinfo_status"), + bundle.getString("devinfo_stat_ready"), + "tok_status"); + break; + } + AddInfoRow(bundle.getString("devinfo_desc"), + selected_slot.desc, "slot_desc"); + AddInfoRow(bundle.getString("devinfo_manID"), + selected_slot.manID, "slot_manID"); + AddInfoRow(bundle.getString("devinfo_hwversion"), + selected_slot.HWVersion, "slot_hwv"); + AddInfoRow(bundle.getString("devinfo_fwversion"), + selected_slot.FWVersion, "slot_fwv"); + if (present) { + showTokenInfo(); + } +} + +function showModuleInfo() +{ + ClearInfoList(); + AddInfoRow(bundle.getString("devinfo_modname"), + selected_module.name, "module_name"); + AddInfoRow(bundle.getString("devinfo_modpath"), + selected_module.libName, "module_path"); +} + +// add a row to the info list, as [col1 col2] (ex.: ["status" "logged in"]) +function AddInfoRow(col1, col2, cell_id) +{ + var tree = document.getElementById("info_list"); + var item = document.createElement("treeitem"); + var row = document.createElement("treerow"); + var cell1 = document.createElement("treecell"); + cell1.setAttribute("label", col1); + cell1.setAttribute("crop", "never"); + row.appendChild(cell1); + var cell2 = document.createElement("treecell"); + cell2.setAttribute("label", col2); + cell2.setAttribute("crop", "never"); + cell2.setAttribute("id", cell_id); + row.appendChild(cell2); + item.appendChild(row); + tree.appendChild(item); +} + +// log in to a slot +function doLogin() +{ + getSelectedItem(); + // here's the workaround - login functions are with token + var selected_token = selected_slot.getToken(); + try { + selected_token.login(false); + var tok_status = document.getElementById("tok_status"); + if (selected_token.isLoggedIn()) { + tok_status.setAttribute("label", + bundle.getString("devinfo_stat_loggedin")); + } else { + tok_status.setAttribute("label", + bundle.getString("devinfo_stat_notloggedin")); + } + } catch (e) { + doPrompt(bundle.getString("login_failed")); + } + enableButtons(); +} + +// log out of a slot +function doLogout() +{ + getSelectedItem(); + // here's the workaround - login functions are with token + var selected_token = selected_slot.getToken(); + try { + selected_token.logoutAndDropAuthenticatedResources(); + var tok_status = document.getElementById("tok_status"); + if (selected_token.isLoggedIn()) { + tok_status.setAttribute("label", + bundle.getString("devinfo_stat_loggedin")); + } else { + tok_status.setAttribute("label", + bundle.getString("devinfo_stat_notloggedin")); + } + } catch (e) { + } + enableButtons(); +} + +// load a new device +function doLoad() +{ + window.open("load_device.xul", "loaddevice", "chrome,centerscreen,modal"); + ClearDeviceList(); + RefreshDeviceList(); +} + +function deleteSelected() +{ + getSelectedItem(); + if (selected_module && + doConfirm(getNSSString("DelModuleWarning"))) { + try { + getPKCS11().deleteModule(selected_module.name); + } + catch (e) { + doPrompt(getNSSString("DelModuleError")); + return false; + } + selected_module = null; + return true; + } + return false; +} + +function doUnload() +{ + if (deleteSelected()) { + ClearDeviceList(); + RefreshDeviceList(); + } +} + +// handle card insertion and removal +function onSmartCardChange() +{ + var tree = document.getElementById('device_tree'); + var index = tree.currentIndex; + tree.currentIndex = 0; + ClearDeviceList(); + RefreshDeviceList(); + tree.currentIndex = index; + enableButtons(); +} + +function changePassword() +{ + getSelectedItem(); + let params = Components.classes[nsDialogParamBlock] + .createInstance(nsIDialogParamBlock); + params.SetString(1, selected_slot.tokenName); + window.openDialog("changepassword.xul", "", "chrome,centerscreen,modal", + params); + showSlotInfo(); + enableButtons(); +} + +// browse fs for PKCS#11 device +function doBrowseFiles() +{ + var srbundle = document.getElementById("pippki_bundle"); + var fp = Components.classes[nsFilePicker].createInstance(nsIFilePicker); + fp.init(window, + srbundle.getString("loadPK11TokenDialog"), + nsIFilePicker.modeOpen); + fp.appendFilters(nsIFilePicker.filterAll); + if (fp.show() == nsIFilePicker.returnOK) { + var pathbox = document.getElementById("device_path"); + pathbox.setAttribute("value", fp.file.path); + } +} + +function doLoadDevice() +{ + var name_box = document.getElementById("device_name"); + var path_box = document.getElementById("device_path"); + try { + getPKCS11().addModule(name_box.value, path_box.value, 0, 0); + } catch (e) { + if (e.result == Components.results.NS_ERROR_ILLEGAL_VALUE) { + doPrompt(getNSSString("AddModuleDup")); + } else { + doPrompt(getNSSString("AddModuleFailure")); + } + + return false; + } + return true; +} + +// ------------------------------------- Old code + +function showTokenInfo() +{ + //ClearInfoList(); + var selected_token = selected_slot.getToken(); + AddInfoRow(bundle.getString("devinfo_label"), + selected_token.tokenLabel, "tok_label"); + AddInfoRow(bundle.getString("devinfo_manID"), + selected_token.tokenManID, "tok_manID"); + AddInfoRow(bundle.getString("devinfo_serialnum"), + selected_token.tokenSerialNumber, "tok_sNum"); + AddInfoRow(bundle.getString("devinfo_hwversion"), + selected_token.tokenHWVersion, "tok_hwv"); + AddInfoRow(bundle.getString("devinfo_fwversion"), + selected_token.tokenFWVersion, "tok_fwv"); +} + +function toggleFIPS() +{ + if (!secmoddb.isFIPSEnabled) { + // A restriction of FIPS mode is, the password must be set + // In FIPS mode the password must be non-empty. + // This is different from what we allow in NON-Fips mode. + + var tokendb = Components.classes[nsPK11TokenDB].getService(nsIPK11TokenDB); + var internal_token = tokendb.getInternalKeyToken(); // nsIPK11Token + var slot = secmoddb.findSlotByName(internal_token.tokenName); + switch (slot.status) { + case nsIPKCS11Slot.SLOT_UNINITIALIZED: + case nsIPKCS11Slot.SLOT_READY: + // Token has either no or an empty password. + doPrompt(bundle.getString("fips_nonempty_password_required")); + return; + } + } + + try { + secmoddb.toggleFIPSMode(); + } + catch (e) { + doPrompt(bundle.getString("unable_to_toggle_fips")); + return; + } + + // Remove the existing listed modules so that a refresh doesn't display the + // module that just changed. + ClearDeviceList(); + + RefreshDeviceList(); +} |