|
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/. */ |
|
4 |
|
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"; |
|
18 |
|
19 var bundle; |
|
20 var secmoddb; |
|
21 var skip_enable_buttons = false; |
|
22 |
|
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); |
|
31 |
|
32 RefreshDeviceList(); |
|
33 } |
|
34 |
|
35 function getPKCS11() |
|
36 { |
|
37 return Components.classes[nsPKCS11ContractID].getService(nsIPKCS11); |
|
38 } |
|
39 |
|
40 function getNSSString(name) |
|
41 { |
|
42 return document.getElementById("pipnss_bundle").getString(name); |
|
43 } |
|
44 |
|
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 } |
|
51 |
|
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 } |
|
58 |
|
59 function RefreshDeviceList() |
|
60 { |
|
61 var modules = secmoddb.listModules(); |
|
62 var done = false; |
|
63 |
|
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 } |
|
105 |
|
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); |
|
116 |
|
117 var can_toggle = secmoddb.canToggleFIPS; |
|
118 if (can_toggle) { |
|
119 fipsButton.removeAttribute("disabled"); |
|
120 } else { |
|
121 fipsButton.setAttribute("disabled", "true"); |
|
122 } |
|
123 } |
|
124 |
|
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 } |
|
154 |
|
155 var selected_slot; |
|
156 var selected_module; |
|
157 |
|
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 } |
|
186 |
|
187 function enableButtons() |
|
188 { |
|
189 if (skip_enable_buttons) |
|
190 return; |
|
191 |
|
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 } |
|
230 |
|
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 } |
|
238 |
|
239 function ClearDeviceList() |
|
240 { |
|
241 ClearInfoList(); |
|
242 |
|
243 skip_enable_buttons = true; |
|
244 var tree = document.getElementById('device_tree'); |
|
245 tree.view.selection.clearSelection(); |
|
246 skip_enable_buttons = false; |
|
247 |
|
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 } |
|
254 |
|
255 |
|
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 } |
|
307 |
|
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 } |
|
316 |
|
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 } |
|
335 |
|
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 } |
|
357 |
|
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 } |
|
378 |
|
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 } |
|
387 |
|
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 } |
|
405 |
|
406 function doUnload() |
|
407 { |
|
408 if (deleteSelected()) { |
|
409 ClearDeviceList(); |
|
410 RefreshDeviceList(); |
|
411 } |
|
412 } |
|
413 |
|
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 } |
|
425 |
|
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 } |
|
437 |
|
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 } |
|
452 |
|
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")); |
|
465 |
|
466 return false; |
|
467 } |
|
468 return true; |
|
469 } |
|
470 |
|
471 // ------------------------------------- Old code |
|
472 |
|
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 } |
|
488 |
|
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. |
|
495 |
|
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 } |
|
507 |
|
508 try { |
|
509 secmoddb.toggleFIPSMode(); |
|
510 } |
|
511 catch (e) { |
|
512 doPrompt(bundle.getString("unable_to_toggle_FIPS")); |
|
513 return; |
|
514 } |
|
515 |
|
516 //Remove the existing listed modules so that re-fresh doesn't |
|
517 //display the module that just changed. |
|
518 ClearDeviceList(); |
|
519 |
|
520 RefreshDeviceList(); |
|
521 } |