1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/security/manager/pki/resources/content/device_manager.js Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,521 @@ 1.4 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.5 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.6 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.7 + 1.8 +const nsIFilePicker = Components.interfaces.nsIFilePicker; 1.9 +const nsFilePicker = "@mozilla.org/filepicker;1"; 1.10 +const nsIPKCS11Slot = Components.interfaces.nsIPKCS11Slot; 1.11 +const nsIPKCS11Module = Components.interfaces.nsIPKCS11Module; 1.12 +const nsPKCS11ModuleDB = "@mozilla.org/security/pkcs11moduledb;1"; 1.13 +const nsIPKCS11ModuleDB = Components.interfaces.nsIPKCS11ModuleDB; 1.14 +const nsIPK11Token = Components.interfaces.nsIPK11Token; 1.15 +const nsPK11TokenDB = "@mozilla.org/security/pk11tokendb;1"; 1.16 +const nsIPK11TokenDB = Components.interfaces.nsIPK11TokenDB; 1.17 +const nsIDialogParamBlock = Components.interfaces.nsIDialogParamBlock; 1.18 +const nsDialogParamBlock = "@mozilla.org/embedcomp/dialogparam;1"; 1.19 +const nsIPKCS11 = Components.interfaces.nsIPKCS11; 1.20 +const nsPKCS11ContractID = "@mozilla.org/security/pkcs11;1"; 1.21 + 1.22 +var bundle; 1.23 +var secmoddb; 1.24 +var skip_enable_buttons = false; 1.25 + 1.26 +/* Do the initial load of all PKCS# modules and list them. */ 1.27 +function LoadModules() 1.28 +{ 1.29 + bundle = document.getElementById("pippki_bundle"); 1.30 + secmoddb = Components.classes[nsPKCS11ModuleDB].getService(nsIPKCS11ModuleDB); 1.31 + window.crypto.enableSmartCardEvents = true; 1.32 + document.addEventListener("smartcard-insert", onSmartCardChange, false); 1.33 + document.addEventListener("smartcard-remove", onSmartCardChange, false); 1.34 + 1.35 + RefreshDeviceList(); 1.36 +} 1.37 + 1.38 +function getPKCS11() 1.39 +{ 1.40 + return Components.classes[nsPKCS11ContractID].getService(nsIPKCS11); 1.41 +} 1.42 + 1.43 +function getNSSString(name) 1.44 +{ 1.45 + return document.getElementById("pipnss_bundle").getString(name); 1.46 +} 1.47 + 1.48 +function doPrompt(msg) 1.49 +{ 1.50 + let prompts = Components.classes["@mozilla.org/embedcomp/prompt-service;1"]. 1.51 + getService(Components.interfaces.nsIPromptService); 1.52 + prompts.alert(window, null, msg); 1.53 +} 1.54 + 1.55 +function doConfirm(msg) 1.56 +{ 1.57 + let prompts = Components.classes["@mozilla.org/embedcomp/prompt-service;1"]. 1.58 + getService(Components.interfaces.nsIPromptService); 1.59 + return prompts.confirm(window, null, msg); 1.60 +} 1.61 + 1.62 +function RefreshDeviceList() 1.63 +{ 1.64 + var modules = secmoddb.listModules(); 1.65 + var done = false; 1.66 + 1.67 + try { 1.68 + modules.isDone(); 1.69 + } catch (e) { done = true; } 1.70 + while (!done) { 1.71 + var module = modules.currentItem().QueryInterface(nsIPKCS11Module); 1.72 + if (module) { 1.73 + var slotnames = []; 1.74 + var slots = module.listSlots(); 1.75 + var slots_done = false; 1.76 + try { 1.77 + slots.isDone(); 1.78 + } catch (e) { slots_done = true; } 1.79 + while (!slots_done) { 1.80 + var slot = null; 1.81 + try { 1.82 + slot = slots.currentItem().QueryInterface(nsIPKCS11Slot); 1.83 + } catch (e) { slot = null; } 1.84 + // in the ongoing discussion of whether slot names or token names 1.85 + // are to be shown, I've gone with token names because NSS will 1.86 + // prefer lookup by token name. However, the token may not be 1.87 + // present, so maybe slot names should be listed, while token names 1.88 + // are "remembered" for lookup? 1.89 + if (slot != null) { 1.90 + if (slot.tokenName) 1.91 + slotnames[slotnames.length] = slot.tokenName; 1.92 + else 1.93 + slotnames[slotnames.length] = slot.name; 1.94 + } 1.95 + try { 1.96 + slots.next(); 1.97 + } catch (e) { slots_done = true; } 1.98 + } 1.99 + AddModule(module.name, slotnames); 1.100 + } 1.101 + try { 1.102 + modules.next(); 1.103 + } catch (e) { done = true; } 1.104 + } 1.105 + /* Set the text on the fips button */ 1.106 + SetFIPSButton(); 1.107 +} 1.108 + 1.109 +function SetFIPSButton() 1.110 +{ 1.111 + var fipsButton = document.getElementById("fipsbutton"); 1.112 + var label; 1.113 + if (secmoddb.isFIPSEnabled) { 1.114 + label = bundle.getString("disable_fips"); 1.115 + } else { 1.116 + label = bundle.getString("enable_fips"); 1.117 + } 1.118 + fipsButton.setAttribute("label", label); 1.119 + 1.120 + var can_toggle = secmoddb.canToggleFIPS; 1.121 + if (can_toggle) { 1.122 + fipsButton.removeAttribute("disabled"); 1.123 + } else { 1.124 + fipsButton.setAttribute("disabled", "true"); 1.125 + } 1.126 +} 1.127 + 1.128 +/* Add a module to the tree. slots is the array of slots in the module, 1.129 + * to be represented as children. 1.130 + */ 1.131 +function AddModule(module, slots) 1.132 +{ 1.133 + var tree = document.getElementById("device_list"); 1.134 + var item = document.createElement("treeitem"); 1.135 + var row = document.createElement("treerow"); 1.136 + var cell = document.createElement("treecell"); 1.137 + cell.setAttribute("label", module); 1.138 + row.appendChild(cell); 1.139 + item.appendChild(row); 1.140 + var parent = document.createElement("treechildren"); 1.141 + for (var i = 0; i<slots.length; i++) { 1.142 + var child_item = document.createElement("treeitem"); 1.143 + var child_row = document.createElement("treerow"); 1.144 + var child_cell = document.createElement("treecell"); 1.145 + child_cell.setAttribute("label", slots[i]); 1.146 + child_row.appendChild(child_cell); 1.147 + child_item.appendChild(child_row); 1.148 + child_item.setAttribute("pk11kind", "slot"); 1.149 + parent.appendChild(child_item); 1.150 + } 1.151 + item.appendChild(parent); 1.152 + item.setAttribute("pk11kind", "module"); 1.153 + item.setAttribute("open", "true"); 1.154 + item.setAttribute("container", "true"); 1.155 + tree.appendChild(item); 1.156 +} 1.157 + 1.158 +var selected_slot; 1.159 +var selected_module; 1.160 + 1.161 +/* get the slot selected by the user (can only be one-at-a-time) */ 1.162 +function getSelectedItem() 1.163 +{ 1.164 + var tree = document.getElementById('device_tree'); 1.165 + if (tree.currentIndex < 0) return; 1.166 + var item = tree.contentView.getItemAtIndex(tree.currentIndex); 1.167 + selected_slot = null; 1.168 + selected_module = null; 1.169 + if (item) { 1.170 + var kind = item.getAttribute("pk11kind"); 1.171 + var module_name; 1.172 + if (kind == "slot") { 1.173 + // get the module cell for this slot cell 1.174 + var cell = item.parentNode.parentNode.firstChild.firstChild; 1.175 + module_name = cell.getAttribute("label"); 1.176 + var module = secmoddb.findModuleByName(module_name); 1.177 + // get the cell for the selected row (the slot to display) 1.178 + cell = item.firstChild.firstChild; 1.179 + var slot_name = cell.getAttribute("label"); 1.180 + selected_slot = module.findSlotByName(slot_name); 1.181 + } else { // (kind == "module") 1.182 + // get the cell for the selected row (the module to display) 1.183 + cell = item.firstChild.firstChild; 1.184 + module_name = cell.getAttribute("label"); 1.185 + selected_module = secmoddb.findModuleByName(module_name); 1.186 + } 1.187 + } 1.188 +} 1.189 + 1.190 +function enableButtons() 1.191 +{ 1.192 + if (skip_enable_buttons) 1.193 + return; 1.194 + 1.195 + var login_toggle = "true"; 1.196 + var logout_toggle = "true"; 1.197 + var pw_toggle = "true"; 1.198 + var unload_toggle = "true"; 1.199 + getSelectedItem(); 1.200 + if (selected_module) { 1.201 + unload_toggle = "false"; 1.202 + showModuleInfo(); 1.203 + } else if (selected_slot) { 1.204 + // here's the workaround - login functions are all with token, 1.205 + // so grab the token type 1.206 + var selected_token = selected_slot.getToken(); 1.207 + if (selected_token != null) { 1.208 + if (selected_token.needsLogin() || !(selected_token.needsUserInit)) { 1.209 + pw_toggle = "false"; 1.210 + if(selected_token.needsLogin()) { 1.211 + if (selected_token.isLoggedIn()) { 1.212 + logout_toggle = "false"; 1.213 + } else { 1.214 + login_toggle = "false"; 1.215 + } 1.216 + } 1.217 + } 1.218 + } 1.219 + showSlotInfo(); 1.220 + } 1.221 + var thebutton = document.getElementById('login_button'); 1.222 + thebutton.setAttribute("disabled", login_toggle); 1.223 + thebutton = document.getElementById('logout_button'); 1.224 + thebutton.setAttribute("disabled", logout_toggle); 1.225 + thebutton = document.getElementById('change_pw_button'); 1.226 + thebutton.setAttribute("disabled", pw_toggle); 1.227 + thebutton = document.getElementById('unload_button'); 1.228 + thebutton.setAttribute("disabled", unload_toggle); 1.229 + // not implemented 1.230 + //thebutton = document.getElementById('change_slotname_button'); 1.231 + //thebutton.setAttribute("disabled", toggle); 1.232 +} 1.233 + 1.234 +// clear the display of information for the slot 1.235 +function ClearInfoList() 1.236 +{ 1.237 + var info_list = document.getElementById("info_list"); 1.238 + while (info_list.firstChild) 1.239 + info_list.removeChild(info_list.firstChild); 1.240 +} 1.241 + 1.242 +function ClearDeviceList() 1.243 +{ 1.244 + ClearInfoList(); 1.245 + 1.246 + skip_enable_buttons = true; 1.247 + var tree = document.getElementById('device_tree'); 1.248 + tree.view.selection.clearSelection(); 1.249 + skip_enable_buttons = false; 1.250 + 1.251 + // Remove the existing listed modules so that refresh doesn't 1.252 + // display the module that just changed. 1.253 + var device_list = document.getElementById("device_list"); 1.254 + while (device_list.hasChildNodes()) 1.255 + device_list.removeChild(device_list.firstChild); 1.256 +} 1.257 + 1.258 + 1.259 +// show a list of info about a slot 1.260 +function showSlotInfo() 1.261 +{ 1.262 + var present = true; 1.263 + ClearInfoList(); 1.264 + switch (selected_slot.status) { 1.265 + case nsIPKCS11Slot.SLOT_DISABLED: 1.266 + AddInfoRow(bundle.getString("devinfo_status"), 1.267 + bundle.getString("devinfo_stat_disabled"), 1.268 + "tok_status"); 1.269 + present = false; 1.270 + break; 1.271 + case nsIPKCS11Slot.SLOT_NOT_PRESENT: 1.272 + AddInfoRow(bundle.getString("devinfo_status"), 1.273 + bundle.getString("devinfo_stat_notpresent"), 1.274 + "tok_status"); 1.275 + present = false; 1.276 + break; 1.277 + case nsIPKCS11Slot.SLOT_UNINITIALIZED: 1.278 + AddInfoRow(bundle.getString("devinfo_status"), 1.279 + bundle.getString("devinfo_stat_uninitialized"), 1.280 + "tok_status"); 1.281 + break; 1.282 + case nsIPKCS11Slot.SLOT_NOT_LOGGED_IN: 1.283 + AddInfoRow(bundle.getString("devinfo_status"), 1.284 + bundle.getString("devinfo_stat_notloggedin"), 1.285 + "tok_status"); 1.286 + break; 1.287 + case nsIPKCS11Slot.SLOT_LOGGED_IN: 1.288 + AddInfoRow(bundle.getString("devinfo_status"), 1.289 + bundle.getString("devinfo_stat_loggedin"), 1.290 + "tok_status"); 1.291 + break; 1.292 + case nsIPKCS11Slot.SLOT_READY: 1.293 + AddInfoRow(bundle.getString("devinfo_status"), 1.294 + bundle.getString("devinfo_stat_ready"), 1.295 + "tok_status"); 1.296 + break; 1.297 + } 1.298 + AddInfoRow(bundle.getString("devinfo_desc"), 1.299 + selected_slot.desc, "slot_desc"); 1.300 + AddInfoRow(bundle.getString("devinfo_manID"), 1.301 + selected_slot.manID, "slot_manID"); 1.302 + AddInfoRow(bundle.getString("devinfo_hwversion"), 1.303 + selected_slot.HWVersion, "slot_hwv"); 1.304 + AddInfoRow(bundle.getString("devinfo_fwversion"), 1.305 + selected_slot.FWVersion, "slot_fwv"); 1.306 + if (present) { 1.307 + showTokenInfo(); 1.308 + } 1.309 +} 1.310 + 1.311 +function showModuleInfo() 1.312 +{ 1.313 + ClearInfoList(); 1.314 + AddInfoRow(bundle.getString("devinfo_modname"), 1.315 + selected_module.name, "module_name"); 1.316 + AddInfoRow(bundle.getString("devinfo_modpath"), 1.317 + selected_module.libName, "module_path"); 1.318 +} 1.319 + 1.320 +// add a row to the info list, as [col1 col2] (ex.: ["status" "logged in"]) 1.321 +function AddInfoRow(col1, col2, cell_id) 1.322 +{ 1.323 + var tree = document.getElementById("info_list"); 1.324 + var item = document.createElement("treeitem"); 1.325 + var row = document.createElement("treerow"); 1.326 + var cell1 = document.createElement("treecell"); 1.327 + cell1.setAttribute("label", col1); 1.328 + cell1.setAttribute("crop", "never"); 1.329 + row.appendChild(cell1); 1.330 + var cell2 = document.createElement("treecell"); 1.331 + cell2.setAttribute("label", col2); 1.332 + cell2.setAttribute("crop", "never"); 1.333 + cell2.setAttribute("id", cell_id); 1.334 + row.appendChild(cell2); 1.335 + item.appendChild(row); 1.336 + tree.appendChild(item); 1.337 +} 1.338 + 1.339 +// log in to a slot 1.340 +function doLogin() 1.341 +{ 1.342 + getSelectedItem(); 1.343 + // here's the workaround - login functions are with token 1.344 + var selected_token = selected_slot.getToken(); 1.345 + try { 1.346 + selected_token.login(false); 1.347 + var tok_status = document.getElementById("tok_status"); 1.348 + if (selected_token.isLoggedIn()) { 1.349 + tok_status.setAttribute("label", 1.350 + bundle.getString("devinfo_stat_loggedin")); 1.351 + } else { 1.352 + tok_status.setAttribute("label", 1.353 + bundle.getString("devinfo_stat_notloggedin")); 1.354 + } 1.355 + } catch (e) { 1.356 + doPrompt(bundle.getString("login_failed")); 1.357 + } 1.358 + enableButtons(); 1.359 +} 1.360 + 1.361 +// log out of a slot 1.362 +function doLogout() 1.363 +{ 1.364 + getSelectedItem(); 1.365 + // here's the workaround - login functions are with token 1.366 + var selected_token = selected_slot.getToken(); 1.367 + try { 1.368 + selected_token.logoutAndDropAuthenticatedResources(); 1.369 + var tok_status = document.getElementById("tok_status"); 1.370 + if (selected_token.isLoggedIn()) { 1.371 + tok_status.setAttribute("label", 1.372 + bundle.getString("devinfo_stat_loggedin")); 1.373 + } else { 1.374 + tok_status.setAttribute("label", 1.375 + bundle.getString("devinfo_stat_notloggedin")); 1.376 + } 1.377 + } catch (e) { 1.378 + } 1.379 + enableButtons(); 1.380 +} 1.381 + 1.382 +// load a new device 1.383 +function doLoad() 1.384 +{ 1.385 + window.open("load_device.xul", "loaddevice", 1.386 + "chrome,centerscreen,modal"); 1.387 + ClearDeviceList(); 1.388 + RefreshDeviceList(); 1.389 +} 1.390 + 1.391 +function deleteSelected() 1.392 +{ 1.393 + getSelectedItem(); 1.394 + if (selected_module && 1.395 + doConfirm(getNSSString("DelModuleWarning"))) { 1.396 + try { 1.397 + getPKCS11().deleteModule(selected_module.name); 1.398 + } 1.399 + catch (e) { 1.400 + doPrompt(getNSSString("DelModuleError")); 1.401 + return false; 1.402 + } 1.403 + selected_module = null; 1.404 + return true; 1.405 + } 1.406 + return false; 1.407 +} 1.408 + 1.409 +function doUnload() 1.410 +{ 1.411 + if (deleteSelected()) { 1.412 + ClearDeviceList(); 1.413 + RefreshDeviceList(); 1.414 + } 1.415 +} 1.416 + 1.417 +// handle card insertion and removal 1.418 +function onSmartCardChange() 1.419 +{ 1.420 + var tree = document.getElementById('device_tree'); 1.421 + var index = tree.currentIndex; 1.422 + tree.currentIndex = 0; 1.423 + ClearDeviceList(); 1.424 + RefreshDeviceList(); 1.425 + tree.currentIndex = index; 1.426 + enableButtons(); 1.427 +} 1.428 + 1.429 +function changePassword() 1.430 +{ 1.431 + getSelectedItem(); 1.432 + var params = Components.classes[nsDialogParamBlock].createInstance(nsIDialogParamBlock); 1.433 + params.SetString(1,selected_slot.tokenName); 1.434 + window.openDialog("changepassword.xul", 1.435 + "", 1.436 + "chrome,centerscreen,modal", params); 1.437 + showSlotInfo(); 1.438 + enableButtons(); 1.439 +} 1.440 + 1.441 +// browse fs for PKCS#11 device 1.442 +function doBrowseFiles() 1.443 +{ 1.444 + var srbundle = document.getElementById("pippki_bundle"); 1.445 + var fp = Components.classes[nsFilePicker].createInstance(nsIFilePicker); 1.446 + fp.init(window, 1.447 + srbundle.getString("loadPK11TokenDialog"), 1.448 + nsIFilePicker.modeOpen); 1.449 + fp.appendFilters(nsIFilePicker.filterAll); 1.450 + if (fp.show() == nsIFilePicker.returnOK) { 1.451 + var pathbox = document.getElementById("device_path"); 1.452 + pathbox.setAttribute("value", fp.file.path); 1.453 + } 1.454 +} 1.455 + 1.456 +function doLoadDevice() 1.457 +{ 1.458 + var name_box = document.getElementById("device_name"); 1.459 + var path_box = document.getElementById("device_path"); 1.460 + try { 1.461 + getPKCS11().addModule(name_box.value, path_box.value, 0,0); 1.462 + } 1.463 + catch (e) { 1.464 + if (e.result == Components.results.NS_ERROR_ILLEGAL_VALUE) 1.465 + doPrompt(getNSSString("AddModuleDup")); 1.466 + else 1.467 + doPrompt(getNSSString("AddModuleFailure")); 1.468 + 1.469 + return false; 1.470 + } 1.471 + return true; 1.472 +} 1.473 + 1.474 +// ------------------------------------- Old code 1.475 + 1.476 +function showTokenInfo() 1.477 +{ 1.478 + //ClearInfoList(); 1.479 + var selected_token = selected_slot.getToken(); 1.480 + AddInfoRow(bundle.getString("devinfo_label"), 1.481 + selected_token.tokenLabel, "tok_label"); 1.482 + AddInfoRow(bundle.getString("devinfo_manID"), 1.483 + selected_token.tokenManID, "tok_manID"); 1.484 + AddInfoRow(bundle.getString("devinfo_serialnum"), 1.485 + selected_token.tokenSerialNumber, "tok_sNum"); 1.486 + AddInfoRow(bundle.getString("devinfo_hwversion"), 1.487 + selected_token.tokenHWVersion, "tok_hwv"); 1.488 + AddInfoRow(bundle.getString("devinfo_fwversion"), 1.489 + selected_token.tokenFWVersion, "tok_fwv"); 1.490 +} 1.491 + 1.492 +function toggleFIPS() 1.493 +{ 1.494 + if (!secmoddb.isFIPSEnabled) { 1.495 + // A restriction of FIPS mode is, the password must be set 1.496 + // In FIPS mode the password must be non-empty. 1.497 + // This is different from what we allow in NON-Fips mode. 1.498 + 1.499 + var tokendb = Components.classes[nsPK11TokenDB].getService(nsIPK11TokenDB); 1.500 + var internal_token = tokendb.getInternalKeyToken(); // nsIPK11Token 1.501 + var slot = secmoddb.findSlotByName(internal_token.tokenName); 1.502 + switch (slot.status) { 1.503 + case nsIPKCS11Slot.SLOT_UNINITIALIZED: 1.504 + case nsIPKCS11Slot.SLOT_READY: 1.505 + // Token has either no or an empty password. 1.506 + doPrompt(bundle.getString("fips_nonempty_password_required")); 1.507 + return; 1.508 + } 1.509 + } 1.510 + 1.511 + try { 1.512 + secmoddb.toggleFIPSMode(); 1.513 + } 1.514 + catch (e) { 1.515 + doPrompt(bundle.getString("unable_to_toggle_FIPS")); 1.516 + return; 1.517 + } 1.518 + 1.519 + //Remove the existing listed modules so that re-fresh doesn't 1.520 + //display the module that just changed. 1.521 + ClearDeviceList(); 1.522 + 1.523 + RefreshDeviceList(); 1.524 +}