bug 1324071 - add nsIPK11Token.hasPassword to replace unnecessary uses of nsIPKCS11Slot.status r=Cykesiopka,gps,MattN,sebastian
authorDavid Keeler <dkeeler@mozilla.com>
Fri, 02 Dec 2016 15:09:35 -0800
changeset 327125 6f732b38a5a2
parent 327124 d116e76778e6
child 327126 f95e3018e089
push id31121
push userphilringnalda@gmail.com
push date2016-12-25 00:50 +0000
treeherdermozilla-central@693dabe3a92a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersCykesiopka, gps, MattN, sebastian
bugs1324071
milestone53.0a1
bug 1324071 - add nsIPK11Token.hasPassword to replace unnecessary uses of nsIPKCS11Slot.status r=Cykesiopka,gps,MattN,sebastian

MozReview-Commit-ID: C2jwQHPEDC0
browser/base/content/browser.js
mobile/android/chrome/content/MasterPassword.js
security/manager/pki/resources/content/changepassword.js
security/manager/pki/resources/content/device_manager.js
security/manager/ssl/nsIPK11Token.idl
security/manager/ssl/nsPK11TokenDB.cpp
security/manager/ssl/nsPKCS11Slot.cpp
security/manager/ssl/tests/unit/test_pkcs11_module.js
security/manager/ssl/tests/unit/test_pkcs11_token.js
services/sync/modules/util.js
toolkit/components/passwordmgr/LoginHelper.jsm
toolkit/components/passwordmgr/crypto-SDR.js
toolkit/components/passwordmgr/test/LoginTestUtils.jsm
toolkit/mozapps/preferences/changemp.js
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -1425,22 +1425,20 @@ var gBrowserInit = {
       AddonWatcher.init();
 
       // Telemetry for master-password - we do this after 5 seconds as it
       // can cause IO if NSS/PSM has not already initialized.
       setTimeout(() => {
         if (window.closed) {
           return;
         }
-        let secmodDB = Cc["@mozilla.org/security/pkcs11moduledb;1"]
-                       .getService(Ci.nsIPKCS11ModuleDB);
-        let slot = secmodDB.findSlotByName("");
-        let mpEnabled = slot &&
-                        slot.status != Ci.nsIPKCS11Slot.SLOT_UNINITIALIZED &&
-                        slot.status != Ci.nsIPKCS11Slot.SLOT_READY;
+        let tokenDB = Cc["@mozilla.org/security/pk11tokendb;1"]
+                        .getService(Ci.nsIPK11TokenDB);
+        let token = tokenDB.getInternalKeyToken();
+        let mpEnabled = token.hasPassword;
         if (mpEnabled) {
           Services.telemetry.getHistogramById("MASTER_PASSWORD_ENABLED").add(mpEnabled);
         }
       }, 5000);
 
       PanicButtonNotifier.init();
     });
 
--- a/mobile/android/chrome/content/MasterPassword.js
+++ b/mobile/android/chrome/content/MasterPassword.js
@@ -2,52 +2,38 @@
  * 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";
 
 XPCOMUtils.defineLazyModuleGetter(this, "Snackbars", "resource://gre/modules/Snackbars.jsm");
 
 var MasterPassword = {
   pref: "privacy.masterpassword.enabled",
-  _tokenName: "",
-
-  get _secModuleDB() {
-    delete this._secModuleDB;
-    return this._secModuleDB = Cc["@mozilla.org/security/pkcs11moduledb;1"].getService(Ci.nsIPKCS11ModuleDB);
-  },
 
   get _pk11DB() {
     delete this._pk11DB;
     return this._pk11DB = Cc["@mozilla.org/security/pk11tokendb;1"].getService(Ci.nsIPK11TokenDB);
   },
 
   get enabled() {
-    let slot = this._secModuleDB.findSlotByName(this._tokenName);
-    if (slot) {
-      let status = slot.status;
-      return status != Ci.nsIPKCS11Slot.SLOT_UNINITIALIZED && status != Ci.nsIPKCS11Slot.SLOT_READY;
+    let token = this._pk11DB.getInternalKeyToken();
+    if (token) {
+      return token.hasPassword;
     }
     return false;
   },
 
   setPassword: function setPassword(aPassword) {
     try {
-      let status;
-      let slot = this._secModuleDB.findSlotByName(this._tokenName);
-      if (slot)
-        status = slot.status;
-      else
-        return false;
-
-      let token = this._pk11DB.findTokenByName(this._tokenName);
-
-      if (status == Ci.nsIPKCS11Slot.SLOT_UNINITIALIZED)
+      let token = this._pk11DB.getInternalKeyToken();
+      if (token.needsUserInit) {
         token.initPassword(aPassword);
-      else if (status == Ci.nsIPKCS11Slot.SLOT_READY)
+      } else if (!token.needsLogin()) {
         token.changePassword("", aPassword);
+      }
 
       return true;
     } catch(e) {
       dump("MasterPassword.setPassword: " + e);
     }
     return false;
   },
 
--- a/security/manager/pki/resources/content/changepassword.js
+++ b/security/manager/pki/resources/content/changepassword.js
@@ -1,13 +1,15 @@
 /* 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 { classes: Cc, interfaces: Ci, utils: Cu, results: Cr } = Components;
+
 const nsPK11TokenDB = "@mozilla.org/security/pk11tokendb;1";
 const nsIPK11TokenDB = Components.interfaces.nsIPK11TokenDB;
 const nsIDialogParamBlock = Components.interfaces.nsIDialogParamBlock;
 const nsPKCS11ModuleDB = "@mozilla.org/security/pkcs11moduledb;1";
 const nsIPKCS11ModuleDB = Components.interfaces.nsIPKCS11ModuleDB;
 const nsIPKCS11Slot = Components.interfaces.nsIPKCS11Slot;
 const nsIPK11Token = Components.interfaces.nsIPK11Token;
 
@@ -76,63 +78,72 @@ function onMenuChange()
    tokenName = list.value;
 
    process();
 }
 
 
 function process()
 {
-   var secmoddb = Components.classes[nsPKCS11ModuleDB].getService(nsIPKCS11ModuleDB);
-   var bundle = document.getElementById("pippki_bundle");
-
-   // If the token is unitialized, don't use the old password box.
-   // Otherwise, do.
-
-   var slot = secmoddb.findSlotByName(tokenName);
-   if (slot) {
-     var oldpwbox = document.getElementById("oldpw");
-     var msgBox = document.getElementById("message");
-     var status = slot.status;
-     if (status == nsIPKCS11Slot.SLOT_UNINITIALIZED
-         || status == nsIPKCS11Slot.SLOT_READY) {
+  let bundle = document.getElementById("pippki_bundle");
 
-       oldpwbox.setAttribute("hidden", "true");
-       msgBox.setAttribute("value", bundle.getString("password_not_set"));
-       msgBox.setAttribute("hidden", "false");
-
-       if (status == nsIPKCS11Slot.SLOT_READY) {
-         oldpwbox.setAttribute("inited", "empty");
-       } else {
-         oldpwbox.setAttribute("inited", "true");
-       }
+  // If the token is unitialized, don't use the old password box.
+  // Otherwise, do.
 
-       // Select first password field
-       document.getElementById("pw1").focus();
-     } else {
-       // Select old password field
-       oldpwbox.setAttribute("hidden", "false");
-       msgBox.setAttribute("hidden", "true");
-       oldpwbox.setAttribute("inited", "false");
-       oldpwbox.focus();
-     }
-   }
+  let tokenDB = Cc["@mozilla.org/security/pk11tokendb;1"]
+                  .getService(Ci.nsIPK11TokenDB);
+  let token;
+  if (tokenName.length > 0) {
+    token = tokenDB.findTokenByName(tokenName);
+  } else {
+    token = tokenDB.getInternalKeyToken();
+  }
+  if (token) {
+    let oldpwbox = document.getElementById("oldpw");
+    let msgBox = document.getElementById("message");
+    if ((token.needsLogin() && token.needsUserInit) || !token.needsLogin()) {
+      oldpwbox.setAttribute("hidden", "true");
+      msgBox.setAttribute("value", bundle.getString("password_not_set"));
+      msgBox.setAttribute("hidden", "false");
+
+      if (!token.needsLogin()) {
+        oldpwbox.setAttribute("inited", "empty");
+      } else {
+        oldpwbox.setAttribute("inited", "true");
+      }
+
+      // Select first password field
+      document.getElementById("pw1").focus();
+    } else {
+      // Select old password field
+      oldpwbox.setAttribute("hidden", "false");
+      msgBox.setAttribute("hidden", "true");
+      oldpwbox.setAttribute("inited", "false");
+      oldpwbox.focus();
+    }
+  }
 
   if (params) {
     // Return value 0 means "canceled"
     params.SetInt(1, 0);
   }
 
   checkPasswords();
 }
 
 function setPassword()
 {
-  var pk11db = Components.classes[nsPK11TokenDB].getService(nsIPK11TokenDB);
-  var token = pk11db.findTokenByName(tokenName);
+  let tokenDB = Cc["@mozilla.org/security/pk11tokendb;1"]
+                  .getService(Ci.nsIPK11TokenDB);
+  let token;
+  if (tokenName.length > 0) {
+    token = tokenDB.findTokenByName(tokenName);
+  } else {
+    token = tokenDB.getInternalKeyToken();
+  }
 
   var oldpwbox = document.getElementById("oldpw");
   var initpw = oldpwbox.getAttribute("inited");
   var bundle = document.getElementById("pippki_bundle");
 
   var success = false;
 
   if (initpw == "false" || initpw == "empty") {
--- a/security/manager/pki/resources/content/device_manager.js
+++ b/security/manager/pki/resources/content/device_manager.js
@@ -475,23 +475,20 @@ 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;
+    if (!internal_token.hasPassword) {
+      // 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"));
--- a/security/manager/ssl/nsIPK11Token.idl
+++ b/security/manager/ssl/nsIPK11Token.idl
@@ -60,15 +60,23 @@ interface nsIPK11Token : nsISupports
   boolean checkPassword(in AUTF8String password);
   void initPassword(in AUTF8String initialPassword);
   void changePassword(in AUTF8String oldPassword, in AUTF8String newPassword);
   long getAskPasswordTimes();
   long getAskPasswordTimeout();
   void setAskPasswordDefaults([const] in long askTimes, [const] in long timeout);
 
   /*
+   * True if a password has been configured for this token, and false otherwise.
+   * (Whether or not the user is currently logged in makes no difference.)
+   * In particular, this can be used to determine if a user has set a master
+   * password (if this is the internal key token).
+   */
+  readonly attribute boolean hasPassword;
+
+  /*
    * Other attributes
    */
   boolean isHardwareToken();
   boolean needsLogin();
   boolean isFriendly();
 };
 
--- a/security/manager/ssl/nsPK11TokenDB.cpp
+++ b/security/manager/ssl/nsPK11TokenDB.cpp
@@ -354,16 +354,33 @@ nsPK11Token::ChangePassword(const nsACSt
   // See Bug 447589.
   return MapSECStatus(PK11_ChangePW(
     mSlot.get(),
     oldPassword.IsVoid() ? nullptr : PromiseFlatCString(oldPassword).get(),
     newPassword.IsVoid() ? nullptr : PromiseFlatCString(newPassword).get()));
 }
 
 NS_IMETHODIMP
+nsPK11Token::GetHasPassword(bool* hasPassword)
+{
+  NS_ENSURE_ARG_POINTER(hasPassword);
+
+  nsNSSShutDownPreventionLock locker;
+  if (isAlreadyShutDown()) {
+    return NS_ERROR_NOT_AVAILABLE;
+  }
+
+  // PK11_NeedLogin returns true if the token is currently configured to require
+  // the user to log in (whether or not the user is actually logged in makes no
+  // difference).
+  *hasPassword = PK11_NeedLogin(mSlot.get()) && !PK11_NeedUserInit(mSlot.get());
+  return NS_OK;
+}
+
+NS_IMETHODIMP
 nsPK11Token::IsHardwareToken(bool* _retval)
 {
   NS_ENSURE_ARG_POINTER(_retval);
 
   nsNSSShutDownPreventionLock locker;
   if (isAlreadyShutDown())
     return NS_ERROR_NOT_AVAILABLE;
 
--- a/security/manager/ssl/nsPKCS11Slot.cpp
+++ b/security/manager/ssl/nsPKCS11Slot.cpp
@@ -448,16 +448,20 @@ nsPKCS11ModuleDB::FindSlotByName(const n
 {
   NS_ENSURE_ARG_POINTER(_retval);
 
   nsNSSShutDownPreventionLock locker;
   if (isAlreadyShutDown()) {
     return NS_ERROR_NOT_AVAILABLE;
   }
 
+  if (name.IsEmpty()) {
+    return NS_ERROR_ILLEGAL_VALUE;
+  }
+
   UniquePK11SlotInfo slotInfo(
     PK11_FindSlotByName(PromiseFlatCString(name).get()));
   if (!slotInfo) {
     return NS_ERROR_FAILURE;
   }
 
   nsCOMPtr<nsIPKCS11Slot> slot = new nsPKCS11Slot(slotInfo.get());
   slot.forget(_retval);
--- a/security/manager/ssl/tests/unit/test_pkcs11_module.js
+++ b/security/manager/ssl/tests/unit/test_pkcs11_module.js
@@ -100,16 +100,18 @@ function run_test() {
            "Internal 'slot' should be findable by name via the module DB");
   ok(internalTokenAsSlot instanceof Ci.nsIPKCS11Slot,
      "Module DB findSlotByName() should return a token as an nsIPKCS11Slot");
   equal(internalTokenAsSlot.name,
         bundle.GetStringFromName("PrivateSlotDescription"),
         "Spot check: actual and expected internal 'slot' names should be equal");
   throws(() => gModuleDB.findSlotByName("Not Present"), /NS_ERROR_FAILURE/,
          "Non-present 'slot' should not be findable by name via the module DB");
+  throws(() => gModuleDB.findSlotByName(""), /NS_ERROR_ILLEGAL_VALUE/,
+         "nsIPKCS11ModuleDB.findSlotByName should throw given an empty name");
 
   // Check that deleting the test module makes it disappear from the module list.
   let pkcs11 = Cc["@mozilla.org/security/pkcs11;1"].getService(Ci.nsIPKCS11);
   pkcs11.deleteModule("PKCS11 Test Module");
   checkTestModuleNotPresent();
 
   // Check miscellaneous module DB methods and attributes.
   notEqual(gModuleDB.getInternal(), null,
--- a/security/manager/ssl/tests/unit/test_pkcs11_token.js
+++ b/security/manager/ssl/tests/unit/test_pkcs11_token.js
@@ -46,16 +46,18 @@ function checkBasicAttributes(token) {
  * @param {nsIPK11Token} token
  *        The token to test.
  * @param {String} initialPW
  *        The password that the token should have been init with.
  */
 function checkPasswordFeaturesAndResetPassword(token, initialPW) {
   ok(!token.needsUserInit,
      "Token should not need user init after setting a password");
+  ok(token.hasPassword,
+     "Token should have a password after setting a password");
 
   equal(token.minimumPasswordLength, 0,
         "Actual and expected min password length should match");
 
   token.setAskPasswordDefaults(10, 20);
   equal(token.getAskPasswordTimes(), 10,
         "Actual and expected ask password times should match");
   equal(token.getAskPasswordTimeout(), 20,
@@ -71,34 +73,36 @@ function checkPasswordFeaturesAndResetPa
      "checkPassword() should fail if an incorrect password is given");
   ok(!token.isLoggedIn(),
      "Token should be logged out after an incorrect password was given");
   ok(!token.needsUserInit,
      "Token should still be init with a password even if an incorrect " +
      "password was given");
 
   token.reset();
-  ok(token.needsUserInit,
-     "Token should need password init after reset");
+  ok(token.needsUserInit, "Token should need password init after reset");
+  ok(!token.hasPassword, "Token should not have a password after reset");
   ok(!token.isLoggedIn(), "Token should be logged out of after reset");
 }
 
 function run_test() {
   let tokenDB = Cc["@mozilla.org/security/pk11tokendb;1"]
                   .getService(Ci.nsIPK11TokenDB);
   let token = tokenDB.getInternalKeyToken();
   notEqual(token, null, "The internal token should be present");
 
   checkBasicAttributes(token);
 
   ok(!token.isLoggedIn(), "Token should not be logged into yet");
   // Test that attempting to log out even when the token was not logged into
   // does not result in an error.
   token.logoutSimple();
   ok(!token.isLoggedIn(), "Token should still not be logged into");
+  ok(!token.hasPassword,
+     "Token should not have a password before it has been set");
 
   let initialPW = "foo 1234567890`~!@#$%^&*()-_=+{[}]|\\:;'\",<.>/? 一二三";
   token.initPassword(initialPW);
   token.login(/*force*/ false);
   ok(token.isLoggedIn(), "Token should now be logged into");
 
   checkPasswordFeaturesAndResetPassword(token, initialPW);
 
--- a/services/sync/modules/util.js
+++ b/services/sync/modules/util.js
@@ -597,44 +597,30 @@ this.Utils = {
   bind2: function Async_bind2(object, method) {
     return function innerBind() { return method.apply(object, arguments); };
   },
 
   /**
    * Is there a master password configured, regardless of current lock state?
    */
   mpEnabled: function mpEnabled() {
-    let modules = Cc["@mozilla.org/security/pkcs11moduledb;1"]
-                    .getService(Ci.nsIPKCS11ModuleDB);
-    let sdrSlot = modules.findSlotByName("");
-    let status  = sdrSlot.status;
-    let slots = Ci.nsIPKCS11Slot;
-
-    return status != slots.SLOT_UNINITIALIZED && status != slots.SLOT_READY;
+    let tokenDB = Cc["@mozilla.org/security/pk11tokendb;1"]
+                    .getService(Ci.nsIPK11TokenDB);
+    let token = tokenDB.getInternalKeyToken();
+    return token.hasPassword;
   },
 
   /**
    * Is there a master password configured and currently locked?
    */
   mpLocked: function mpLocked() {
-    let modules = Cc["@mozilla.org/security/pkcs11moduledb;1"]
-                    .getService(Ci.nsIPKCS11ModuleDB);
-    let sdrSlot = modules.findSlotByName("");
-    let status  = sdrSlot.status;
-    let slots = Ci.nsIPKCS11Slot;
-
-    if (status == slots.SLOT_READY || status == slots.SLOT_LOGGED_IN
-                                   || status == slots.SLOT_UNINITIALIZED)
-      return false;
-
-    if (status == slots.SLOT_NOT_LOGGED_IN)
-      return true;
-
-    // something wacky happened, pretend MP is locked
-    return true;
+    let tokenDB = Cc["@mozilla.org/security/pk11tokendb;1"]
+                    .getService(Ci.nsIPK11TokenDB);
+    let token = tokenDB.getInternalKeyToken();
+    return token.hasPassword && !token.isLoggedIn();
   },
 
   // If Master Password is enabled and locked, present a dialog to unlock it.
   // Return whether the system is unlocked.
   ensureMPUnlocked: function ensureMPUnlocked() {
     if (!Utils.mpLocked()) {
       return true;
     }
--- a/toolkit/components/passwordmgr/LoginHelper.jsm
+++ b/toolkit/components/passwordmgr/LoginHelper.jsm
@@ -682,25 +682,20 @@ this.LoginHelper = {
       File.remove(file);
     }
   },
 
   /**
    * Returns true if the user has a master password set and false otherwise.
    */
   isMasterPasswordSet() {
-    let secmodDB = Cc["@mozilla.org/security/pkcs11moduledb;1"].
-                   getService(Ci.nsIPKCS11ModuleDB);
-    let slot = secmodDB.findSlotByName("");
-    if (!slot) {
-      return false;
-    }
-    let hasMP = slot.status != Ci.nsIPKCS11Slot.SLOT_UNINITIALIZED &&
-                slot.status != Ci.nsIPKCS11Slot.SLOT_READY;
-    return hasMP;
+    let tokenDB = Cc["@mozilla.org/security/pk11tokendb;1"]
+                    .getService(Ci.nsIPK11TokenDB);
+    let token = tokenDB.getInternalKeyToken();
+    return token.hasPassword;
   },
 
   /**
    * Send a notification when stored data is changed.
    */
   notifyStorageChanged(changeType, data) {
     let dataObject = data;
     // Can't pass a raw JS string or array though notifyObservers(). :-(
--- a/toolkit/components/passwordmgr/crypto-SDR.js
+++ b/toolkit/components/passwordmgr/crypto-SDR.js
@@ -14,26 +14,16 @@ function LoginManagerCrypto_SDR() {
   this.init();
 }
 
 LoginManagerCrypto_SDR.prototype = {
 
   classID : Components.ID("{dc6c2976-0f73-4f1f-b9ff-3d72b4e28309}"),
   QueryInterface : XPCOMUtils.generateQI([Ci.nsILoginManagerCrypto]),
 
-  __sdrSlot : null, // PKCS#11 slot being used by the SDR.
-  get _sdrSlot() {
-    if (!this.__sdrSlot) {
-      let modules = Cc["@mozilla.org/security/pkcs11moduledb;1"].
-                    getService(Ci.nsIPKCS11ModuleDB);
-      this.__sdrSlot = modules.findSlotByName("");
-    }
-    return this.__sdrSlot;
-  },
-
   __decoderRing : null,  // nsSecretDecoderRing service
   get _decoderRing() {
     if (!this.__decoderRing)
       this.__decoderRing = Cc["@mozilla.org/security/sdr;1"].
                            getService(Ci.nsISecretDecoderRing);
     return this.__decoderRing;
   },
 
@@ -165,24 +155,20 @@ LoginManagerCrypto_SDR.prototype = {
     return this._uiBusy;
   },
 
 
   /*
    * isLoggedIn
    */
   get isLoggedIn() {
-    let status = this._sdrSlot.status;
-    this.log("SDR slot status is " + status);
-    if (status == Ci.nsIPKCS11Slot.SLOT_READY ||
-        status == Ci.nsIPKCS11Slot.SLOT_LOGGED_IN)
-      return true;
-    if (status == Ci.nsIPKCS11Slot.SLOT_NOT_LOGGED_IN)
-      return false;
-    throw Components.Exception("unexpected slot status: " + status, Cr.NS_ERROR_FAILURE);
+    let tokenDB = Cc["@mozilla.org/security/pk11tokendb;1"].
+                  getService(Ci.nsIPK11TokenDB);
+    let token = tokenDB.getInternalKeyToken();
+    return !token.hasPassword || token.isLoggedIn();
   },
 
 
   /*
    * defaultEncType
    */
   get defaultEncType() {
     return Ci.nsILoginManagerCrypto.ENCTYPE_SDR;
--- a/toolkit/components/passwordmgr/test/LoginTestUtils.jsm
+++ b/toolkit/components/passwordmgr/test/LoginTestUtils.jsm
@@ -258,29 +258,22 @@ this.LoginTestUtils.masterPassword = {
     if (enable) {
       oldPW = "";
       newPW = this.masterPassword;
     } else {
       oldPW = this.masterPassword;
       newPW = "";
     }
 
-    let secmodDB = Cc["@mozilla.org/security/pkcs11moduledb;1"]
-                     .getService(Ci.nsIPKCS11ModuleDB);
-    let slot = secmodDB.findSlotByName("");
-    if (!slot) {
-      throw new Error("Can't find slot");
-    }
-
     // Set master password. Note that this does not log you in, so the next
     // invocation of pwmgr can trigger a MP prompt.
     let pk11db = Cc["@mozilla.org/security/pk11tokendb;1"]
                    .getService(Ci.nsIPK11TokenDB);
-    let token = pk11db.findTokenByName("");
-    if (slot.status == Ci.nsIPKCS11Slot.SLOT_UNINITIALIZED) {
+    let token = pk11db.getInternalKeyToken();
+    if (token.needsUserInit) {
       dump("MP initialized to " + newPW + "\n");
       token.initPassword(newPW);
     } else {
       token.checkPassword(oldPW);
       dump("MP change from " + oldPW + " to " + newPW + "\n");
       token.changePassword(oldPW, newPW);
     }
   },
--- a/toolkit/mozapps/preferences/changemp.js
+++ b/toolkit/mozapps/preferences/changemp.js
@@ -1,88 +1,85 @@
 // -*- tab-width: 2; indent-tabs-mode: nil; js-indent-level: 2 -*-
 
 /* 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/. */
 
+const { classes: Cc, interfaces: Ci, utils: Cu, results: Cr } = Components;
+
 const nsPK11TokenDB = "@mozilla.org/security/pk11tokendb;1";
 const nsIPK11TokenDB = Components.interfaces.nsIPK11TokenDB;
 const nsIDialogParamBlock = Components.interfaces.nsIDialogParamBlock;
 const nsPKCS11ModuleDB = "@mozilla.org/security/pkcs11moduledb;1";
 const nsIPKCS11ModuleDB = Components.interfaces.nsIPKCS11ModuleDB;
 const nsIPKCS11Slot = Components.interfaces.nsIPKCS11Slot;
 const nsIPK11Token = Components.interfaces.nsIPK11Token;
 
 
 var params;
-var tokenName = "";
 var pw1;
 
 function init()
 {
   pw1 = document.getElementById("pw1");
 
   process();
 }
 
 
 function process()
 {
-   var secmoddb = Components.classes[nsPKCS11ModuleDB].getService(nsIPKCS11ModuleDB);
-   var bundle = document.getElementById("bundlePreferences");
-
-   // If the token is unitialized, don't use the old password box.
-   // Otherwise, do.
-
-   var slot = secmoddb.findSlotByName(tokenName);
-   if (slot) {
-     var oldpwbox = document.getElementById("oldpw");
-     var msgBox = document.getElementById("message");
-     var status = slot.status;
-     if (status == nsIPKCS11Slot.SLOT_UNINITIALIZED
-         || status == nsIPKCS11Slot.SLOT_READY) {
+  let bundle = document.getElementById("bundlePreferences");
 
-       oldpwbox.setAttribute("hidden", "true");
-       msgBox.setAttribute("value", bundle.getString("password_not_set"));
-       msgBox.setAttribute("hidden", "false");
-
-       if (status == nsIPKCS11Slot.SLOT_READY) {
-         oldpwbox.setAttribute("inited", "empty");
-       } else {
-         oldpwbox.setAttribute("inited", "true");
-       }
+  // If the token is unitialized, don't use the old password box.
+  // Otherwise, do.
 
-       // Select first password field
-       document.getElementById('pw1').focus();
+  let tokenDB = Cc["@mozilla.org/security/pk11tokendb;1"]
+                  .getService(Ci.nsIPK11TokenDB);
+  let token = tokenDB.getInternalKeyToken();
+  if (token) {
+    let oldpwbox = document.getElementById("oldpw");
+    let msgBox = document.getElementById("message");
+    if ((token.needsLogin() && token.needsUserInit) || !token.needsLogin()) {
+      oldpwbox.setAttribute("hidden", "true");
+      msgBox.setAttribute("value", bundle.getString("password_not_set"));
+      msgBox.setAttribute("hidden", "false");
 
-     } else {
-       // Select old password field
-       oldpwbox.setAttribute("hidden", "false");
-       msgBox.setAttribute("hidden", "true");
-       oldpwbox.setAttribute("inited", "false");
-       oldpwbox.focus();
-     }
-   }
+      if (!token.needsLogin()) {
+        oldpwbox.setAttribute("inited", "empty");
+      } else {
+        oldpwbox.setAttribute("inited", "true");
+      }
+
+      // Select first password field
+      document.getElementById('pw1').focus();
+    } else {
+      // Select old password field
+      oldpwbox.setAttribute("hidden", "false");
+      msgBox.setAttribute("hidden", "true");
+      oldpwbox.setAttribute("inited", "false");
+      oldpwbox.focus();
+    }
+  }
 
   if (params) {
     // Return value 0 means "canceled"
     params.SetInt(1, 0);
   }
 
   checkPasswords();
 }
 
 function setPassword()
 {
   var pk11db = Components.classes[nsPK11TokenDB].getService(nsIPK11TokenDB);
   var promptService = Components.classes["@mozilla.org/embedcomp/prompt-service;1"]
                                 .getService(Components.interfaces.nsIPromptService);
-  var token = pk11db.findTokenByName(tokenName);
-  dump("*** TOKEN!!!! (name = |" + token + "|\n");
+  var token = pk11db.getInternalKeyToken();
 
   var oldpwbox = document.getElementById("oldpw");
   var initpw = oldpwbox.getAttribute("inited");
   var bundle = document.getElementById("bundlePreferences");
 
   var success = false;
 
   if (initpw == "false" || initpw == "empty") {