Bug 1259149 - Add additional tests for the nsIPK11* and nsIPKCS11* implementations. r=keeler draft
authorCykesiopka <cykesiopka.bmo@gmail.com>
Thu, 24 Mar 2016 18:29:39 -0700
changeset 344636 b3e009b9e462d041f00072081f9d6de7cc39e36c
parent 344635 517f25117d11ba60dd0b2eb135eff6e89f6c6e68
child 517010 c9f0ff871df7d755da99e34d309a80a022d7e703
push id13887
push usercykesiopka.bmo@gmail.com
push dateFri, 25 Mar 2016 01:29:55 +0000
reviewerskeeler
bugs1259149
milestone48.0a1
Bug 1259149 - Add additional tests for the nsIPK11* and nsIPKCS11* implementations. r=keeler After these additions, the majority of the API surface should be covered. MozReview-Commit-ID: CvpEX6Cm94d
security/manager/ssl/tests/unit/test_pkcs11_insert_remove.js
security/manager/ssl/tests/unit/test_pkcs11_list.js
security/manager/ssl/tests/unit/test_pkcs11_module.js
security/manager/ssl/tests/unit/test_pkcs11_slot.js
security/manager/ssl/tests/unit/test_pkcs11_token.js
security/manager/ssl/tests/unit/xpcshell-smartcards.ini
--- a/security/manager/ssl/tests/unit/test_pkcs11_insert_remove.js
+++ b/security/manager/ssl/tests/unit/test_pkcs11_insert_remove.js
@@ -40,19 +40,32 @@ SmartcardObserver.prototype = {
     let testTokenLabelFound = false;
     while (tokenList.hasMoreElements()) {
       let token = tokenList.getNext().QueryInterface(Ci.nsIPK11Token);
       if (token.tokenLabel == gExpectedTokenLabel) {
         testTokenLabelFound = true;
         break;
       }
     }
-    equal(testTokenLabelFound, this.type == "smartcard-insert",
+    let testTokenShouldBePresent = this.type == "smartcard-insert";
+    equal(testTokenLabelFound, testTokenShouldBePresent,
           "Should find test token only when the test module is loaded");
 
+    // Test that the token is findable by name only when the test module is
+    // loaded.
+    // Note: Again, this test is located here out of convenience.
+    if (testTokenShouldBePresent) {
+      notEqual(gTokenDB.findTokenByName(gExpectedTokenLabel), null,
+               "Test token should be findable by name");
+    } else {
+      throws(() => gTokenDB.findTokenByName(gExpectedTokenLabel),
+             /NS_ERROR_FAILURE/,
+             "Non-present test token should not be findable by name");
+    }
+
     Services.obs.removeObserver(this, this.type);
     do_test_finished();
   }
 };
 
 function run_test() {
   Services.obs.addObserver(new SmartcardObserver("smartcard-insert"),
                            "smartcard-insert", false);
rename from security/manager/ssl/tests/unit/test_pkcs11_list.js
rename to security/manager/ssl/tests/unit/test_pkcs11_module.js
--- a/security/manager/ssl/tests/unit/test_pkcs11_list.js
+++ b/security/manager/ssl/tests/unit/test_pkcs11_module.js
@@ -1,39 +1,41 @@
 /* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
 // Any copyright is dedicated to the Public Domain.
 // http://creativecommons.org/publicdomain/zero/1.0/
 "use strict";
 
-// Tests the methods for listing PKCS #11 modules and slots via loading and
-// unloading a test PKCS #11 module.
-
-// Note: Tests for listing PKCS #11 tokens are located in
-//       test_pkcs11_insert_remove.js out of convenience.
+// Tests the methods and attributes for interfacing with a PKCS #11 module and
+// the module database.
 
 // Ensure that the appropriate initialization has happened.
 do_get_profile();
-Cc["@mozilla.org/psm;1"].getService(Ci.nsISupports);
 
 const gModuleDB = Cc["@mozilla.org/security/pkcs11moduledb;1"]
                     .getService(Ci.nsIPKCS11ModuleDB);
 
 function checkTestModuleNotPresent() {
   let modules = gModuleDB.listModules();
   ok(modules.hasMoreElements(),
      "One or more modules should be present with test module not present");
   while (modules.hasMoreElements()) {
     let module = modules.getNext().QueryInterface(Ci.nsIPKCS11Module);
     notEqual(module.name, "PKCS11 Test Module",
              "Non-test module name shouldn't equal 'PKCS11 Test Module'");
+    ok(!(module.libName && module.libName.includes("pkcs11testmodule")),
+       "Non-test module lib name should not include 'pkcs11testmodule'");
   }
+
+  throws(() => gModuleDB.findModuleByName("PKCS11 Test Module"),
+         /NS_ERROR_FAILURE/, "Test module should not be findable by name");
 }
 
 /**
  * Checks that the test module exists in the module list.
+ * Also checks various attributes of the test module for correctness.
  *
  * @returns {nsIPKCS11Module}
  *          The test module.
  */
 function checkTestModuleExists() {
   let modules = gModuleDB.listModules();
   ok(modules.hasMoreElements(),
      "One or more modules should be present with test module present");
@@ -41,25 +43,30 @@ function checkTestModuleExists() {
   while (modules.hasMoreElements()) {
     let module = modules.getNext().QueryInterface(Ci.nsIPKCS11Module);
     if (module.name == "PKCS11 Test Module") {
       testModule = module;
       break;
     }
   }
   notEqual(testModule, null, "Test module should have been found");
+  notEqual(testModule.libName, null, "Test module lib name should not be null");
+  ok(testModule.libName.includes(ctypes.libraryName("pkcs11testmodule")),
+     "Test module lib name should include lib name of 'pkcs11testmodule'");
+
+  notEqual(gModuleDB.findModuleByName("PKCS11 Test Module"), null,
+           "Test module should be findable by name");
 
   return testModule;
 }
 
 function run_test() {
-  let libraryName = ctypes.libraryName("pkcs11testmodule");
   let libraryFile = Services.dirsvc.get("CurWorkD", Ci.nsILocalFile);
   libraryFile.append("pkcs11testmodule");
-  libraryFile.append(libraryName);
+  libraryFile.append(ctypes.libraryName("pkcs11testmodule"));
   ok(libraryFile.exists(), "The pkcs11testmodule file should exist");
 
   // Check that if we have never added the test module, that we don't find it
   // in the module list.
   checkTestModuleNotPresent();
 
   // Check that adding the test module makes it appear in the module list.
   let pkcs11 = Cc["@mozilla.org/security/pkcs11;1"].getService(Ci.nsIPKCS11);
@@ -83,12 +90,27 @@ function run_test() {
   while (slots.hasMoreElements()) {
     let slot = slots.getNext().QueryInterface(Ci.nsIPKCS11Slot);
     equal(slot.name, "Test PKCS11 Slot",
           "Test module slot should have correct name");
     testModuleSlotCount++;
   }
   equal(testModuleSlotCount, 1, "Test module should only have one slot");
 
+  // Check that finding the test slot by name is possible, and that trying to
+  // find a non-present slot fails.
+  notEqual(testModule.findSlotByName("Test PKCS11 Slot"), null,
+           "Test slot should be findable by name");
+  throws(() => testModule.findSlotByName("Not Present"), /NS_ERROR_FAILURE/,
+         "Non-present slot should not be findable by name");
+
   // Check that deleting the test module makes it disappear from the module list.
   pkcs11.deleteModule("PKCS11 Test Module");
   checkTestModuleNotPresent();
+
+  // Check miscellaneous module DB methods and attributes.
+  notEqual(gModuleDB.getInternal(), null,
+           "The internal module should be present");
+  notEqual(gModuleDB.getInternalFIPS(), null,
+           "The internal FIPS module should be present");
+  ok(gModuleDB.canToggleFIPS, "It should be possible to toggle FIPS");
+  ok(!gModuleDB.isFIPSEnabled, "FIPS should not be enabled");
 }
new file mode 100644
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_pkcs11_slot.js
@@ -0,0 +1,42 @@
+/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
+// Any copyright is dedicated to the Public Domain.
+// http://creativecommons.org/publicdomain/zero/1.0/
+"use strict";
+
+// Tests the methods and attributes for interfacing with a PKCS #11 slot.
+
+// Ensure that the appropriate initialization has happened.
+do_get_profile();
+
+function run_test() {
+  let libraryFile = Services.dirsvc.get("CurWorkD", Ci.nsILocalFile);
+  libraryFile.append("pkcs11testmodule");
+  libraryFile.append(ctypes.libraryName("pkcs11testmodule"));
+  ok(libraryFile.exists(), "The pkcs11testmodule file should exist");
+
+  let pkcs11 = Cc["@mozilla.org/security/pkcs11;1"].getService(Ci.nsIPKCS11);
+  do_register_cleanup(() => {
+    pkcs11.deleteModule("PKCS11 Test Module");
+  });
+  pkcs11.addModule("PKCS11 Test Module", libraryFile.path, 0, 0);
+
+  let moduleDB = Cc["@mozilla.org/security/pkcs11moduledb;1"]
+                   .getService(Ci.nsIPKCS11ModuleDB);
+  let testModule = moduleDB.findModuleByName("PKCS11 Test Module");
+  let testSlot = testModule.findSlotByName("Test PKCS11 Slot");
+
+  equal(testSlot.name, "Test PKCS11 Slot",
+        "Actual and expected name should match");
+  equal(testSlot.desc, "Test PKCS11 Slot",
+        "Actual and expected description should match");
+  equal(testSlot.manID, "Test PKCS11 Manufacturer ID",
+        "Actual and expected manufacturer ID should match");
+  equal(testSlot.HWVersion, "0.0",
+        "Actual and expected hardware version should match");
+  equal(testSlot.FWVersion, "0.0",
+        "Actual and expected firmware version should match");
+  // Note: testSlot.status is not tested because the implementation calls
+  //       PK11_IsPresent(), which checks whether the test token is present.
+  //       The test module inserts and removes the test token in a tight loop,
+  //       so the result might not be deterministic.
+}
new file mode 100644
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_pkcs11_token.js
@@ -0,0 +1,105 @@
+/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
+// Any copyright is dedicated to the Public Domain.
+// http://creativecommons.org/publicdomain/zero/1.0/
+"use strict";
+
+// Tests the methods and attributes for interfacing with a PKCS #11 token, using
+// the internal key token.
+// Note: We don't use the test token in the test PKCS #11 module because it is
+//       inconvenient to test. See the top level comment in
+//       test_pkcs11_insert_remove.js for why. However, some token DB tests are
+//       located in that file out of convenience.
+
+// Ensure that the appropriate initialization has happened.
+do_get_profile();
+
+function checkBasicAttributes(token) {
+  let strBundleSvc = Cc["@mozilla.org/intl/stringbundle;1"]
+                       .getService(Ci.nsIStringBundleService);
+  let bundle =
+    strBundleSvc.createBundle("chrome://pipnss/locale/pipnss.properties");
+
+  let expectedTokenName = bundle.GetStringFromName("PrivateTokenDescription");
+  equal(token.tokenName, expectedTokenName,
+        "Actual and expected name should match");
+  equal(token.tokenLabel, expectedTokenName,
+        "Actual and expected label should match");
+  equal(token.tokenManID, bundle.GetStringFromName("ManufacturerID"),
+        "Actual and expected manufacturer ID should match");
+  equal(token.tokenHWVersion, "0.0",
+        "Actual and expected hardware version should match");
+  equal(token.tokenFWVersion, "0.0",
+        "Actual and expected firmware version should match");
+  equal(token.tokenSerialNumber, "0000000000000000",
+        "Actual and expected serial number should match");
+}
+
+/**
+ * Checks the various password related features of the given token.
+ * The token should already have been init with a password and be logged into.
+ * The password of the token will be reset after calling this function.
+ *
+ * @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");
+
+  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,
+        "Actual and expected ask password timeout should match");
+
+  ok(token.checkPassword(initialPW),
+     "checkPassword() should succeed if the correct initial password is given");
+  token.changePassword(initialPW, "newPW");
+  ok(token.checkPassword("newPW"),
+     "checkPassword() should succeed if the correct new password is given");
+
+  ok(!token.checkPassword("wrongPW"),
+     "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");
+}
+
+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");
+  let initialPW = "foo 1234567890`~!#$%^&*()-_=+{[}]|\\:;'\",<.>/?";
+  token.initPassword(initialPW);
+  token.login(/*force*/ false);
+  ok(token.isLoggedIn(), "Token should now be logged into");
+
+  checkPasswordFeaturesAndResetPassword(token, initialPW);
+
+  // We reset the password previously, so we need to initialize again.
+  token.initPassword("arbitrary");
+  token.logoutSimple();
+  ok(!token.isLoggedIn(),
+     "Token should be logged out after calling logoutSimple()");
+
+  ok(!token.isHardwareToken(),
+     "The internal token should not be considered a hardware token");
+  ok(token.isFriendly(),
+     "The internal token should always be considered friendly");
+}
--- a/security/manager/ssl/tests/unit/xpcshell-smartcards.ini
+++ b/security/manager/ssl/tests/unit/xpcshell-smartcards.ini
@@ -1,11 +1,13 @@
 [DEFAULT]
 head = head_psm.js
 tail =
 tags = psm
 skip-if = toolkit == 'android' || toolkit == 'gonk'
 support-files =
 
 [test_pkcs11_insert_remove.js]
-[test_pkcs11_list.js]
+[test_pkcs11_module.js]
 [test_pkcs11_no_events_after_removal.js]
 [test_pkcs11_safe_mode.js]
+[test_pkcs11_slot.js]
+[test_pkcs11_token.js]