Wed, 31 Dec 2014 07:16:47 +0100
Revert simplistic fix pending revisit of Mozilla integration attempt.
1 /* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 const nsIFilePicker = Components.interfaces.nsIFilePicker;
6 const nsFilePicker = "@mozilla.org/filepicker;1";
7 const nsIPKCS11Slot = Components.interfaces.nsIPKCS11Slot;
8 const nsIPKCS11Module = Components.interfaces.nsIPKCS11Module;
9 const nsPKCS11ModuleDB = "@mozilla.org/security/pkcs11moduledb;1";
10 const nsIPKCS11ModuleDB = Components.interfaces.nsIPKCS11ModuleDB;
11 const nsIPK11Token = Components.interfaces.nsIPK11Token;
12 const nsPK11TokenDB = "@mozilla.org/security/pk11tokendb;1";
13 const nsIPK11TokenDB = Components.interfaces.nsIPK11TokenDB;
14 const nsIDialogParamBlock = Components.interfaces.nsIDialogParamBlock;
15 const nsDialogParamBlock = "@mozilla.org/embedcomp/dialogparam;1";
16 const nsIPKCS11 = Components.interfaces.nsIPKCS11;
17 const nsPKCS11ContractID = "@mozilla.org/security/pkcs11;1";
19 var bundle;
20 var secmoddb;
21 var skip_enable_buttons = false;
23 /* Do the initial load of all PKCS# modules and list them. */
24 function LoadModules()
25 {
26 bundle = document.getElementById("pippki_bundle");
27 secmoddb = Components.classes[nsPKCS11ModuleDB].getService(nsIPKCS11ModuleDB);
28 window.crypto.enableSmartCardEvents = true;
29 document.addEventListener("smartcard-insert", onSmartCardChange, false);
30 document.addEventListener("smartcard-remove", onSmartCardChange, false);
32 RefreshDeviceList();
33 }
35 function getPKCS11()
36 {
37 return Components.classes[nsPKCS11ContractID].getService(nsIPKCS11);
38 }
40 function getNSSString(name)
41 {
42 return document.getElementById("pipnss_bundle").getString(name);
43 }
45 function doPrompt(msg)
46 {
47 let prompts = Components.classes["@mozilla.org/embedcomp/prompt-service;1"].
48 getService(Components.interfaces.nsIPromptService);
49 prompts.alert(window, null, msg);
50 }
52 function doConfirm(msg)
53 {
54 let prompts = Components.classes["@mozilla.org/embedcomp/prompt-service;1"].
55 getService(Components.interfaces.nsIPromptService);
56 return prompts.confirm(window, null, msg);
57 }
59 function RefreshDeviceList()
60 {
61 var modules = secmoddb.listModules();
62 var done = false;
64 try {
65 modules.isDone();
66 } catch (e) { done = true; }
67 while (!done) {
68 var module = modules.currentItem().QueryInterface(nsIPKCS11Module);
69 if (module) {
70 var slotnames = [];
71 var slots = module.listSlots();
72 var slots_done = false;
73 try {
74 slots.isDone();
75 } catch (e) { slots_done = true; }
76 while (!slots_done) {
77 var slot = null;
78 try {
79 slot = slots.currentItem().QueryInterface(nsIPKCS11Slot);
80 } catch (e) { slot = null; }
81 // in the ongoing discussion of whether slot names or token names
82 // are to be shown, I've gone with token names because NSS will
83 // prefer lookup by token name. However, the token may not be
84 // present, so maybe slot names should be listed, while token names
85 // are "remembered" for lookup?
86 if (slot != null) {
87 if (slot.tokenName)
88 slotnames[slotnames.length] = slot.tokenName;
89 else
90 slotnames[slotnames.length] = slot.name;
91 }
92 try {
93 slots.next();
94 } catch (e) { slots_done = true; }
95 }
96 AddModule(module.name, slotnames);
97 }
98 try {
99 modules.next();
100 } catch (e) { done = true; }
101 }
102 /* Set the text on the fips button */
103 SetFIPSButton();
104 }
106 function SetFIPSButton()
107 {
108 var fipsButton = document.getElementById("fipsbutton");
109 var label;
110 if (secmoddb.isFIPSEnabled) {
111 label = bundle.getString("disable_fips");
112 } else {
113 label = bundle.getString("enable_fips");
114 }
115 fipsButton.setAttribute("label", label);
117 var can_toggle = secmoddb.canToggleFIPS;
118 if (can_toggle) {
119 fipsButton.removeAttribute("disabled");
120 } else {
121 fipsButton.setAttribute("disabled", "true");
122 }
123 }
125 /* Add a module to the tree. slots is the array of slots in the module,
126 * to be represented as children.
127 */
128 function AddModule(module, slots)
129 {
130 var tree = document.getElementById("device_list");
131 var item = document.createElement("treeitem");
132 var row = document.createElement("treerow");
133 var cell = document.createElement("treecell");
134 cell.setAttribute("label", module);
135 row.appendChild(cell);
136 item.appendChild(row);
137 var parent = document.createElement("treechildren");
138 for (var i = 0; i<slots.length; i++) {
139 var child_item = document.createElement("treeitem");
140 var child_row = document.createElement("treerow");
141 var child_cell = document.createElement("treecell");
142 child_cell.setAttribute("label", slots[i]);
143 child_row.appendChild(child_cell);
144 child_item.appendChild(child_row);
145 child_item.setAttribute("pk11kind", "slot");
146 parent.appendChild(child_item);
147 }
148 item.appendChild(parent);
149 item.setAttribute("pk11kind", "module");
150 item.setAttribute("open", "true");
151 item.setAttribute("container", "true");
152 tree.appendChild(item);
153 }
155 var selected_slot;
156 var selected_module;
158 /* get the slot selected by the user (can only be one-at-a-time) */
159 function getSelectedItem()
160 {
161 var tree = document.getElementById('device_tree');
162 if (tree.currentIndex < 0) return;
163 var item = tree.contentView.getItemAtIndex(tree.currentIndex);
164 selected_slot = null;
165 selected_module = null;
166 if (item) {
167 var kind = item.getAttribute("pk11kind");
168 var module_name;
169 if (kind == "slot") {
170 // get the module cell for this slot cell
171 var cell = item.parentNode.parentNode.firstChild.firstChild;
172 module_name = cell.getAttribute("label");
173 var module = secmoddb.findModuleByName(module_name);
174 // get the cell for the selected row (the slot to display)
175 cell = item.firstChild.firstChild;
176 var slot_name = cell.getAttribute("label");
177 selected_slot = module.findSlotByName(slot_name);
178 } else { // (kind == "module")
179 // get the cell for the selected row (the module to display)
180 cell = item.firstChild.firstChild;
181 module_name = cell.getAttribute("label");
182 selected_module = secmoddb.findModuleByName(module_name);
183 }
184 }
185 }
187 function enableButtons()
188 {
189 if (skip_enable_buttons)
190 return;
192 var login_toggle = "true";
193 var logout_toggle = "true";
194 var pw_toggle = "true";
195 var unload_toggle = "true";
196 getSelectedItem();
197 if (selected_module) {
198 unload_toggle = "false";
199 showModuleInfo();
200 } else if (selected_slot) {
201 // here's the workaround - login functions are all with token,
202 // so grab the token type
203 var selected_token = selected_slot.getToken();
204 if (selected_token != null) {
205 if (selected_token.needsLogin() || !(selected_token.needsUserInit)) {
206 pw_toggle = "false";
207 if(selected_token.needsLogin()) {
208 if (selected_token.isLoggedIn()) {
209 logout_toggle = "false";
210 } else {
211 login_toggle = "false";
212 }
213 }
214 }
215 }
216 showSlotInfo();
217 }
218 var thebutton = document.getElementById('login_button');
219 thebutton.setAttribute("disabled", login_toggle);
220 thebutton = document.getElementById('logout_button');
221 thebutton.setAttribute("disabled", logout_toggle);
222 thebutton = document.getElementById('change_pw_button');
223 thebutton.setAttribute("disabled", pw_toggle);
224 thebutton = document.getElementById('unload_button');
225 thebutton.setAttribute("disabled", unload_toggle);
226 // not implemented
227 //thebutton = document.getElementById('change_slotname_button');
228 //thebutton.setAttribute("disabled", toggle);
229 }
231 // clear the display of information for the slot
232 function ClearInfoList()
233 {
234 var info_list = document.getElementById("info_list");
235 while (info_list.firstChild)
236 info_list.removeChild(info_list.firstChild);
237 }
239 function ClearDeviceList()
240 {
241 ClearInfoList();
243 skip_enable_buttons = true;
244 var tree = document.getElementById('device_tree');
245 tree.view.selection.clearSelection();
246 skip_enable_buttons = false;
248 // Remove the existing listed modules so that refresh doesn't
249 // display the module that just changed.
250 var device_list = document.getElementById("device_list");
251 while (device_list.hasChildNodes())
252 device_list.removeChild(device_list.firstChild);
253 }
256 // show a list of info about a slot
257 function showSlotInfo()
258 {
259 var present = true;
260 ClearInfoList();
261 switch (selected_slot.status) {
262 case nsIPKCS11Slot.SLOT_DISABLED:
263 AddInfoRow(bundle.getString("devinfo_status"),
264 bundle.getString("devinfo_stat_disabled"),
265 "tok_status");
266 present = false;
267 break;
268 case nsIPKCS11Slot.SLOT_NOT_PRESENT:
269 AddInfoRow(bundle.getString("devinfo_status"),
270 bundle.getString("devinfo_stat_notpresent"),
271 "tok_status");
272 present = false;
273 break;
274 case nsIPKCS11Slot.SLOT_UNINITIALIZED:
275 AddInfoRow(bundle.getString("devinfo_status"),
276 bundle.getString("devinfo_stat_uninitialized"),
277 "tok_status");
278 break;
279 case nsIPKCS11Slot.SLOT_NOT_LOGGED_IN:
280 AddInfoRow(bundle.getString("devinfo_status"),
281 bundle.getString("devinfo_stat_notloggedin"),
282 "tok_status");
283 break;
284 case nsIPKCS11Slot.SLOT_LOGGED_IN:
285 AddInfoRow(bundle.getString("devinfo_status"),
286 bundle.getString("devinfo_stat_loggedin"),
287 "tok_status");
288 break;
289 case nsIPKCS11Slot.SLOT_READY:
290 AddInfoRow(bundle.getString("devinfo_status"),
291 bundle.getString("devinfo_stat_ready"),
292 "tok_status");
293 break;
294 }
295 AddInfoRow(bundle.getString("devinfo_desc"),
296 selected_slot.desc, "slot_desc");
297 AddInfoRow(bundle.getString("devinfo_manID"),
298 selected_slot.manID, "slot_manID");
299 AddInfoRow(bundle.getString("devinfo_hwversion"),
300 selected_slot.HWVersion, "slot_hwv");
301 AddInfoRow(bundle.getString("devinfo_fwversion"),
302 selected_slot.FWVersion, "slot_fwv");
303 if (present) {
304 showTokenInfo();
305 }
306 }
308 function showModuleInfo()
309 {
310 ClearInfoList();
311 AddInfoRow(bundle.getString("devinfo_modname"),
312 selected_module.name, "module_name");
313 AddInfoRow(bundle.getString("devinfo_modpath"),
314 selected_module.libName, "module_path");
315 }
317 // add a row to the info list, as [col1 col2] (ex.: ["status" "logged in"])
318 function AddInfoRow(col1, col2, cell_id)
319 {
320 var tree = document.getElementById("info_list");
321 var item = document.createElement("treeitem");
322 var row = document.createElement("treerow");
323 var cell1 = document.createElement("treecell");
324 cell1.setAttribute("label", col1);
325 cell1.setAttribute("crop", "never");
326 row.appendChild(cell1);
327 var cell2 = document.createElement("treecell");
328 cell2.setAttribute("label", col2);
329 cell2.setAttribute("crop", "never");
330 cell2.setAttribute("id", cell_id);
331 row.appendChild(cell2);
332 item.appendChild(row);
333 tree.appendChild(item);
334 }
336 // log in to a slot
337 function doLogin()
338 {
339 getSelectedItem();
340 // here's the workaround - login functions are with token
341 var selected_token = selected_slot.getToken();
342 try {
343 selected_token.login(false);
344 var tok_status = document.getElementById("tok_status");
345 if (selected_token.isLoggedIn()) {
346 tok_status.setAttribute("label",
347 bundle.getString("devinfo_stat_loggedin"));
348 } else {
349 tok_status.setAttribute("label",
350 bundle.getString("devinfo_stat_notloggedin"));
351 }
352 } catch (e) {
353 doPrompt(bundle.getString("login_failed"));
354 }
355 enableButtons();
356 }
358 // log out of a slot
359 function doLogout()
360 {
361 getSelectedItem();
362 // here's the workaround - login functions are with token
363 var selected_token = selected_slot.getToken();
364 try {
365 selected_token.logoutAndDropAuthenticatedResources();
366 var tok_status = document.getElementById("tok_status");
367 if (selected_token.isLoggedIn()) {
368 tok_status.setAttribute("label",
369 bundle.getString("devinfo_stat_loggedin"));
370 } else {
371 tok_status.setAttribute("label",
372 bundle.getString("devinfo_stat_notloggedin"));
373 }
374 } catch (e) {
375 }
376 enableButtons();
377 }
379 // load a new device
380 function doLoad()
381 {
382 window.open("load_device.xul", "loaddevice",
383 "chrome,centerscreen,modal");
384 ClearDeviceList();
385 RefreshDeviceList();
386 }
388 function deleteSelected()
389 {
390 getSelectedItem();
391 if (selected_module &&
392 doConfirm(getNSSString("DelModuleWarning"))) {
393 try {
394 getPKCS11().deleteModule(selected_module.name);
395 }
396 catch (e) {
397 doPrompt(getNSSString("DelModuleError"));
398 return false;
399 }
400 selected_module = null;
401 return true;
402 }
403 return false;
404 }
406 function doUnload()
407 {
408 if (deleteSelected()) {
409 ClearDeviceList();
410 RefreshDeviceList();
411 }
412 }
414 // handle card insertion and removal
415 function onSmartCardChange()
416 {
417 var tree = document.getElementById('device_tree');
418 var index = tree.currentIndex;
419 tree.currentIndex = 0;
420 ClearDeviceList();
421 RefreshDeviceList();
422 tree.currentIndex = index;
423 enableButtons();
424 }
426 function changePassword()
427 {
428 getSelectedItem();
429 var params = Components.classes[nsDialogParamBlock].createInstance(nsIDialogParamBlock);
430 params.SetString(1,selected_slot.tokenName);
431 window.openDialog("changepassword.xul",
432 "",
433 "chrome,centerscreen,modal", params);
434 showSlotInfo();
435 enableButtons();
436 }
438 // browse fs for PKCS#11 device
439 function doBrowseFiles()
440 {
441 var srbundle = document.getElementById("pippki_bundle");
442 var fp = Components.classes[nsFilePicker].createInstance(nsIFilePicker);
443 fp.init(window,
444 srbundle.getString("loadPK11TokenDialog"),
445 nsIFilePicker.modeOpen);
446 fp.appendFilters(nsIFilePicker.filterAll);
447 if (fp.show() == nsIFilePicker.returnOK) {
448 var pathbox = document.getElementById("device_path");
449 pathbox.setAttribute("value", fp.file.path);
450 }
451 }
453 function doLoadDevice()
454 {
455 var name_box = document.getElementById("device_name");
456 var path_box = document.getElementById("device_path");
457 try {
458 getPKCS11().addModule(name_box.value, path_box.value, 0,0);
459 }
460 catch (e) {
461 if (e.result == Components.results.NS_ERROR_ILLEGAL_VALUE)
462 doPrompt(getNSSString("AddModuleDup"));
463 else
464 doPrompt(getNSSString("AddModuleFailure"));
466 return false;
467 }
468 return true;
469 }
471 // ------------------------------------- Old code
473 function showTokenInfo()
474 {
475 //ClearInfoList();
476 var selected_token = selected_slot.getToken();
477 AddInfoRow(bundle.getString("devinfo_label"),
478 selected_token.tokenLabel, "tok_label");
479 AddInfoRow(bundle.getString("devinfo_manID"),
480 selected_token.tokenManID, "tok_manID");
481 AddInfoRow(bundle.getString("devinfo_serialnum"),
482 selected_token.tokenSerialNumber, "tok_sNum");
483 AddInfoRow(bundle.getString("devinfo_hwversion"),
484 selected_token.tokenHWVersion, "tok_hwv");
485 AddInfoRow(bundle.getString("devinfo_fwversion"),
486 selected_token.tokenFWVersion, "tok_fwv");
487 }
489 function toggleFIPS()
490 {
491 if (!secmoddb.isFIPSEnabled) {
492 // A restriction of FIPS mode is, the password must be set
493 // In FIPS mode the password must be non-empty.
494 // This is different from what we allow in NON-Fips mode.
496 var tokendb = Components.classes[nsPK11TokenDB].getService(nsIPK11TokenDB);
497 var internal_token = tokendb.getInternalKeyToken(); // nsIPK11Token
498 var slot = secmoddb.findSlotByName(internal_token.tokenName);
499 switch (slot.status) {
500 case nsIPKCS11Slot.SLOT_UNINITIALIZED:
501 case nsIPKCS11Slot.SLOT_READY:
502 // Token has either no or an empty password.
503 doPrompt(bundle.getString("fips_nonempty_password_required"));
504 return;
505 }
506 }
508 try {
509 secmoddb.toggleFIPSMode();
510 }
511 catch (e) {
512 doPrompt(bundle.getString("unable_to_toggle_FIPS"));
513 return;
514 }
516 //Remove the existing listed modules so that re-fresh doesn't
517 //display the module that just changed.
518 ClearDeviceList();
520 RefreshDeviceList();
521 }