Bug 1220237 - Remove uses of nsIEnumerator from PSM. r=keeler

MozReview-Commit-ID: 3FhBCqnJz4n
This commit is contained in:
Cykesiopka 2016-02-24 17:42:45 -08:00
parent 010a1e397c
commit eb7fd9a45b
11 changed files with 246 additions and 147 deletions

View File

@ -71,46 +71,20 @@ function doConfirm(msg)
function RefreshDeviceList()
{
var modules = secmoddb.listModules();
var done = false;
try {
modules.isDone();
} catch (e) { done = true; }
while (!done) {
var module = modules.currentItem().QueryInterface(nsIPKCS11Module);
if (module) {
var slotnames = [];
var slots = module.listSlots();
var slots_done = false;
try {
slots.isDone();
} catch (e) { slots_done = true; }
while (!slots_done) {
var slot = null;
try {
slot = slots.currentItem().QueryInterface(nsIPKCS11Slot);
} catch (e) { slot = null; }
// in the ongoing discussion of whether slot names or token names
// are to be shown, I've gone with token names because NSS will
// prefer lookup by token name. However, the token may not be
// present, so maybe slot names should be listed, while token names
// are "remembered" for lookup?
if (slot != null) {
slotnames[slotnames.length] = slot.tokenName ? slot.tokenName
: slot.name;
}
try {
slots.next();
} catch (e) { slots_done = true; }
}
AddModule(module.name, slotnames);
let modules = secmoddb.listModules();
while (modules.hasMoreElements()) {
let module = modules.getNext().QueryInterface(nsIPKCS11Module);
let slotnames = [];
let slots = module.listSlots();
while (slots.hasMoreElements()) {
let slot = slots.getNext().QueryInterface(nsIPKCS11Slot);
// Token names are preferred because NSS prefers lookup by token name.
slotnames.push(slot.tokenName ? slot.tokenName : slot.name);
}
try {
modules.next();
} catch (e) { done = true; }
AddModule(module.name, slotnames);
}
/* Set the text on the fips button */
// Set the text on the FIPS button.
SetFIPSButton();
}

View File

@ -39,28 +39,24 @@ function onLoad()
}
if (tokenName == "") {
var sectokdb = Components.classes[nsPK11TokenDB].getService(nsIPK11TokenDB);
var tokenList = sectokdb.listTokens();
var enumElement;
let i = 0;
var menu = document.getElementById("tokenMenu");
try {
for (; !tokenList.isDone(); tokenList.next()) {
enumElement = tokenList.currentItem();
var token = enumElement.QueryInterface(nsIPK11Token);
if(token.needsLogin() || !(token.needsUserInit)) {
var menuItemNode = document.createElement("menuitem");
menuItemNode.setAttribute("value", token.tokenName);
menuItemNode.setAttribute("label", token.tokenName);
menu.firstChild.appendChild(menuItemNode);
if (i == 0) {
menu.selectedItem = menuItemNode;
tokenName = token.tokenName;
}
i++;
}
let tokenDB = Components.classes[nsPK11TokenDB].getService(nsIPK11TokenDB);
let tokenList = tokenDB.listTokens();
let i = 0;
let menu = document.getElementById("tokenMenu");
while (tokenList.hasMoreElements()) {
let token = tokenList.getNext().QueryInterface(nsIPK11Token);
if (token.needsLogin() || !(token.needsUserInit)) {
let menuItemNode = document.createElement("menuitem");
menuItemNode.setAttribute("value", token.tokenName);
menuItemNode.setAttribute("label", token.tokenName);
menu.firstChild.appendChild(menuItemNode);
if (i == 0) {
menu.selectedItem = menuItemNode;
tokenName = token.tokenName;
}
} catch (exception) {}
i++;
}
}
} else {
var sel = document.getElementById("tokenMenu");
sel.setAttribute("hidden", "true");

View File

@ -7,7 +7,7 @@
#include "nsISupports.idl"
interface nsIPK11Token;
interface nsIEnumerator;
interface nsISimpleEnumerator;
/**
* The PK11 Token Database provides access to the PK11 modules
@ -38,7 +38,5 @@ interface nsIPK11TokenDB : nsISupports
/*
* List all tokens
*/
nsIEnumerator listTokens();
nsISimpleEnumerator listTokens();
};

View File

@ -7,18 +7,15 @@
#include "nsISupports.idl"
interface nsIPKCS11Slot;
interface nsIEnumerator;
interface nsISimpleEnumerator;
[scriptable, uuid(8a44bdf9-d1a5-4734-bd5a-34ed7fe564c2)]
interface nsIPKCS11Module : nsISupports
{
readonly attribute wstring name;
readonly attribute wstring libName;
nsIPKCS11Slot findSlotByName(in wstring name);
nsIEnumerator listSlots();
nsISimpleEnumerator listSlots();
};

View File

@ -8,7 +8,7 @@
interface nsIPKCS11Module;
interface nsIPKCS11Slot;
interface nsIEnumerator;
interface nsISimpleEnumerator;
%{C++
#define NS_PKCS11MODULEDB_CONTRACTID "@mozilla.org/security/pkcs11moduledb;1"
@ -25,7 +25,7 @@ interface nsIPKCS11ModuleDB : nsISupports
nsIPKCS11Slot findSlotByName(in wstring name);
nsIEnumerator listModules();
nsISimpleEnumerator listModules();
readonly attribute boolean canToggleFIPS;
@ -33,4 +33,3 @@ interface nsIPKCS11ModuleDB : nsISupports
readonly attribute boolean isFIPSEnabled;
};

View File

@ -3,17 +3,17 @@
* 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/. */
#include "nsISupports.h"
#include "nsISupportsArray.h"
#include "nsIPK11TokenDB.h"
#include "prerror.h"
#include "secerr.h"
#include "nsReadableUtils.h"
#include "nsNSSComponent.h"
#include "nsServiceManagerUtils.h"
#include "nsPK11TokenDB.h"
#include "nsIMutableArray.h"
#include "nsISupports.h"
#include "nsNSSComponent.h"
#include "nsReadableUtils.h"
#include "nsServiceManagerUtils.h"
#include "prerror.h"
#include "ScopedNSSTypes.h"
#include "secerr.h"
extern PRLogModuleInfo* gPIPNSSLog;
NS_IMPL_ISUPPORTS(nsPK11Token, nsIPK11Token)
@ -447,37 +447,31 @@ done:
return rv;
}
NS_IMETHODIMP nsPK11TokenDB::ListTokens(nsIEnumerator* *_retval)
NS_IMETHODIMP
nsPK11TokenDB::ListTokens(nsISimpleEnumerator** _retval)
{
nsNSSShutDownPreventionLock locker;
nsCOMPtr<nsISupportsArray> array;
PK11SlotList *list = 0;
PK11SlotListElement *le;
nsCOMPtr<nsIMutableArray> array = do_CreateInstance(NS_ARRAY_CONTRACTID);
if (!array) {
return NS_ERROR_FAILURE;
}
*_retval = nullptr;
nsresult rv = NS_NewISupportsArray(getter_AddRefs(array));
if (NS_FAILED(rv)) { goto done; }
/* List all tokens, creating PK11Token objects and putting them
* into the array.
*/
list = PK11_GetAllTokens(CKM_INVALID_MECHANISM, false, false, 0);
if (!list) { rv = NS_ERROR_FAILURE; goto done; }
UniquePK11SlotList list(
PK11_GetAllTokens(CKM_INVALID_MECHANISM, false, false, 0));
if (!list) {
return NS_ERROR_FAILURE;
}
for (le = PK11_GetFirstSafe(list); le; le = PK11_GetNextSafe(list, le, false)) {
for (PK11SlotListElement* le = PK11_GetFirstSafe(list.get()); le;
le = PK11_GetNextSafe(list.get(), le, false)) {
nsCOMPtr<nsIPK11Token> token = new nsPK11Token(le->slot);
rv = array->AppendElement(token);
nsresult rv = array->AppendElement(token, false);
if (NS_FAILED(rv)) {
PK11_FreeSlotListElement(list, le);
rv = NS_ERROR_OUT_OF_MEMORY;
goto done;
return rv;
}
}
rv = array->Enumerate(_retval);
done:
if (list) PK11_FreeSlotList(list);
return rv;
return array->Enumerate(_retval);
}

View File

@ -7,7 +7,7 @@
#include "mozilla/Logging.h"
#include "mozilla/Telemetry.h"
#include "nsCOMPtr.h"
#include "nsISupportsArray.h"
#include "nsIMutableArray.h"
#include "nsPK11TokenDB.h"
#include "secmod.h"
@ -318,34 +318,35 @@ nsPKCS11Module::FindSlotByName(const char16_t *aName,
return NS_OK;
}
NS_IMETHODIMP
nsPKCS11Module::ListSlots(nsIEnumerator **_retval)
NS_IMETHODIMP
nsPKCS11Module::ListSlots(nsISimpleEnumerator** _retval)
{
nsNSSShutDownPreventionLock locker;
if (isAlreadyShutDown())
if (isAlreadyShutDown()) {
return NS_ERROR_NOT_AVAILABLE;
}
nsCOMPtr<nsIMutableArray> array = do_CreateInstance(NS_ARRAY_CONTRACTID);
if (!array) {
return NS_ERROR_FAILURE;
}
nsresult rv = NS_OK;
int i;
/* get isupports array */
nsCOMPtr<nsISupportsArray> array;
rv = NS_NewISupportsArray(getter_AddRefs(array));
if (NS_FAILED(rv)) return rv;
/* applications which allow new slot creation (which Firefox now does
* since it uses the WaitForSlotEvent call) need to hold the
* ModuleList Read lock to prevent the slot array from changing out
* from under it. */
SECMODListLock *lock = SECMOD_GetDefaultModuleListLock();
SECMOD_GetReadLock(lock);
for (i=0; i<mModule->slotCount; i++) {
AutoSECMODListReadLock lock;
for (int i = 0; i < mModule->slotCount; i++) {
if (mModule->slots[i]) {
nsCOMPtr<nsIPKCS11Slot> slot = new nsPKCS11Slot(mModule->slots[i]);
array->AppendElement(slot);
nsresult rv = array->AppendElement(slot, false);
if (NS_FAILED(rv)) {
return rv;
}
}
}
SECMOD_ReleaseReadLock(lock);
rv = array->Enumerate(_retval);
return rv;
return array->Enumerate(_retval);
}
NS_IMPL_ISUPPORTS(nsPKCS11ModuleDB, nsIPKCS11ModuleDB, nsICryptoFIPSInfo)
@ -417,35 +418,37 @@ nsPKCS11ModuleDB::FindSlotByName(const char16_t *aName,
return NS_OK;
}
NS_IMETHODIMP
nsPKCS11ModuleDB::ListModules(nsIEnumerator **_retval)
NS_IMETHODIMP
nsPKCS11ModuleDB::ListModules(nsISimpleEnumerator** _retval)
{
nsNSSShutDownPreventionLock locker;
nsresult rv = NS_OK;
/* get isupports array */
nsCOMPtr<nsISupportsArray> array;
rv = NS_NewISupportsArray(getter_AddRefs(array));
if (NS_FAILED(rv)) return rv;
/* get the default list of modules */
SECMODModuleList *list = SECMOD_GetDefaultModuleList();
nsCOMPtr<nsIMutableArray> array = do_CreateInstance(NS_ARRAY_CONTRACTID);
if (!array) {
return NS_ERROR_FAILURE;
}
/* lock down the list for reading */
SECMODListLock *lock = SECMOD_GetDefaultModuleListLock();
SECMOD_GetReadLock(lock);
while (list) {
AutoSECMODListReadLock lock;
for (SECMODModuleList* list = SECMOD_GetDefaultModuleList(); list;
list = list->next) {
nsCOMPtr<nsIPKCS11Module> module = new nsPKCS11Module(list->module);
array->AppendElement(module);
list = list->next;
nsresult rv = array->AppendElement(module, false);
if (NS_FAILED(rv)) {
return rv;
}
}
/* Get the modules in the database that didn't load */
list = SECMOD_GetDeadModuleList();
while (list) {
for (SECMODModuleList* list = SECMOD_GetDeadModuleList(); list;
list = list->next) {
nsCOMPtr<nsIPKCS11Module> module = new nsPKCS11Module(list->module);
array->AppendElement(module);
list = list->next;
nsresult rv = array->AppendElement(module, false);
if (NS_FAILED(rv)) {
return rv;
}
}
SECMOD_ReleaseReadLock(lock);
rv = array->Enumerate(_retval);
return rv;
return array->Enumerate(_retval);
}
NS_IMETHODIMP nsPKCS11ModuleDB::GetCanToggleFIPS(bool *aCanToggleFIPS)

View File

@ -4,17 +4,17 @@
* 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/. */
#ifndef __NS_PKCS11SLOT_H__
#define __NS_PKCS11SLOT_H__
#ifndef nsPKCS11Slot_h
#define nsPKCS11Slot_h
#include "nsISupports.h"
#include "nsIPKCS11Slot.h"
#include "nsICryptoFIPSInfo.h"
#include "nsIPKCS11Module.h"
#include "nsIPKCS11ModuleDB.h"
#include "nsICryptoFIPSInfo.h"
#include "nsIPKCS11Slot.h"
#include "nsISupports.h"
#include "nsNSSShutDown.h"
#include "nsString.h"
#include "pk11func.h"
#include "nsNSSShutDown.h"
class nsPKCS11Slot : public nsIPKCS11Slot,
public nsNSSShutDownObject
@ -77,4 +77,23 @@ protected:
{ 0xff9fbcd7, 0x9517, 0x4334, \
{ 0xb9, 0x7a, 0xce, 0xed, 0x78, 0x90, 0x99, 0x74 }}
#endif
class MOZ_RAII AutoSECMODListReadLock final
{
public:
AutoSECMODListReadLock()
: mLock(SECMOD_GetDefaultModuleListLock())
{
MOZ_ASSERT(mLock, "Should have the default SECMOD lock");
SECMOD_GetReadLock(mLock);
}
~AutoSECMODListReadLock()
{
SECMOD_ReleaseReadLock(mLock);
}
private:
SECMODListLock* mLock;
};
#endif // nsPKCS11Slot_h

View File

@ -16,6 +16,9 @@ Cc["@mozilla.org/psm;1"].getService(Ci.nsISupports);
const gExpectedTokenLabel = "Test PKCS11 Tokeñ Label";
const gTokenDB = Cc["@mozilla.org/security/pk11tokendb;1"]
.getService(Ci.nsIPK11TokenDB);
function SmartcardObserver(type) {
this.type = type;
do_test_pending();
@ -26,6 +29,25 @@ SmartcardObserver.prototype = {
equal(topic, this.type, "Observed and expected types should match");
equal(gExpectedTokenLabel, data,
"Expected and observed token labels should match");
// Test that the token list contains the test token only when the test
// module is loaded.
// Note: This test is located here out of convenience. In particular,
// observing the "smartcard-insert" event is the only time where it
// is reasonably certain for the test token to be present (see the top
// level comment for this file for why).
let tokenList = gTokenDB.listTokens();
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",
"Should find test token only when the test module is loaded");
Services.obs.removeObserver(this, this.type);
do_test_finished();
}

View File

@ -0,0 +1,94 @@
/* -*- 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.
// 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'");
}
}
/**
* Checks that the test module exists in the module list.
*
* @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");
let testModule = null;
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");
return testModule;
}
function run_test() {
let libraryName = ctypes.libraryName("pkcs11testmodule");
let libraryFile = Services.dirsvc.get("CurWorkD", Ci.nsILocalFile);
libraryFile.append("pkcs11testmodule");
libraryFile.append(libraryName);
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);
do_register_cleanup(() => {
try {
pkcs11.deleteModule("PKCS11 Test Module");
} catch (e) {
// deleteModule() throws if the module we tell it to delete is missing,
// or if some other thing went wrong. Since we're just cleaning up,
// there's nothing to do even if the call fails. In addition, we delete
// the test module during a normal run of this test file, so we need to
// catch the exception that is raised to not have the test fail.
}
});
pkcs11.addModule("PKCS11 Test Module", libraryFile.path, 0, 0);
let testModule = checkTestModuleExists();
// Check that listing the slots for the test module works.
let slots = testModule.listSlots();
let testModuleSlotCount = 0;
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 deleting the test module makes it disappear from the module list.
pkcs11.deleteModule("PKCS11 Test Module");
checkTestModuleNotPresent();
}

View File

@ -8,6 +8,9 @@ support-files =
[test_pkcs11_insert_remove.js]
# Bug 1049969: this test doesn't work on windows
skip-if = os == "win"
[test_pkcs11_list.js]
# Bug 1049969: this test doesn't work on windows
skip-if = os == "win"
[test_pkcs11_no_events_after_removal.js]
# Bug 1049969: this test doesn't work on windows
skip-if = os == "win"