bug 1369911 - gather telemetry on the prevalence of 3rd party PKCS#11 modules r?Cykesiopka data-review=bsmedberg
MozReview-Commit-ID: Dw99Jm64QNU
--- a/security/manager/ssl/PKCS11.cpp
+++ b/security/manager/ssl/PKCS11.cpp
@@ -2,16 +2,18 @@
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* 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 "PKCS11.h"
#include "ScopedNSSTypes.h"
+#include "mozilla/Telemetry.h"
+#include "nsCRTGlue.h"
#include "nsNSSComponent.h"
#include "nsNativeCharsetUtils.h"
#include "nsServiceManagerUtils.h"
namespace mozilla { namespace psm {
NS_INTERFACE_MAP_BEGIN(PKCS11)
NS_INTERFACE_MAP_ENTRY(nsIPKCS11)
@@ -67,16 +69,44 @@ PKCS11::DeleteModule(const nsAString& aM
SECStatus srv = SECMOD_DeleteModule(moduleName.get(), &modType);
if (srv != SECSuccess) {
return NS_ERROR_FAILURE;
}
return NS_OK;
}
+// Given a PKCS#11 module, determines an appropriate name to identify it for the
+// purposes of gathering telemetry. For 3rd party PKCS#11 modules, this should
+// be the name of the dynamic library that implements the module. For built-in
+// NSS modules, it will be the common name of the module.
+// Because the result will be used as a telemetry scalar key (which must be less
+// than 70 characters), this function will also truncate the result if it
+// exceeds this limit. (Note that unfortunately telemetry doesn't expose a way
+// to programmatically query the scalar key length limit, so we have to
+// hard-code the value here.)
+void
+GetModuleNameForTelemetry(/*in*/ const SECMODModule* module,
+ /*out*/nsString& result)
+{
+ result.Truncate();
+ if (module->dllName) {
+ result.AssignWithConversion(module->dllName);
+ int32_t separatorIndex = result.RFind(FILE_PATH_SEPARATOR);
+ if (separatorIndex != kNotFound) {
+ result = Substring(result, separatorIndex + 1);
+ }
+ } else {
+ result.AssignWithConversion(module->commonName);
+ }
+ if (result.Length() >= 70) {
+ result.Truncate(69);
+ }
+}
+
// Add a new PKCS11 module to the user's profile.
NS_IMETHODIMP
PKCS11::AddModule(const nsAString& aModuleName,
const nsAString& aLibraryFullPath,
int32_t aCryptoMechanismFlags,
int32_t aCipherFlags)
{
nsNSSShutDownPreventionLock locker;
@@ -95,22 +125,34 @@ PKCS11::AddModule(const nsAString& aModu
uint32_t mechFlags = SECMOD_PubMechFlagstoInternal(aCryptoMechanismFlags);
uint32_t cipherFlags = SECMOD_PubCipherFlagstoInternal(aCipherFlags);
SECStatus srv = SECMOD_AddNewModule(moduleName.get(), fullPath.get(),
mechFlags, cipherFlags);
if (srv != SECSuccess) {
return NS_ERROR_FAILURE;
}
-#ifndef MOZ_NO_SMART_CARDS
UniqueSECMODModule module(SECMOD_FindModule(moduleName.get()));
if (!module) {
return NS_ERROR_FAILURE;
}
+
+#ifndef MOZ_NO_SMART_CARDS
nsCOMPtr<nsINSSComponent> nssComponent(
do_GetService(PSM_COMPONENT_CONTRACTID));
nssComponent->LaunchSmartCardThread(module.get());
#endif
+ nsAutoString scalarKey;
+ GetModuleNameForTelemetry(module.get(), scalarKey);
+ // Scalar keys must be between 0 and 70 characters (exclusive).
+ // GetModuleNameForTelemetry takes care of keys that are too long.
+ // If for some reason it couldn't come up with an appropriate name and
+ // returned an empty result, however, we need to not attempt to record this
+ // (it wouldn't give us anything useful anyway).
+ if (scalarKey.Length() > 0) {
+ Telemetry::ScalarSet(Telemetry::ScalarID::SECURITY_PKCS11_MODULES_LOADED,
+ scalarKey, true);
+ }
return NS_OK;
}
} } // namespace mozilla::psm
--- a/security/manager/ssl/PKCS11.h
+++ b/security/manager/ssl/PKCS11.h
@@ -4,16 +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 PKCS11_h
#define PKCS11_h
#include "nsIPKCS11.h"
#include "nsNSSShutDown.h"
+#include "nsString.h"
namespace mozilla { namespace psm {
#define NS_PKCS11_CID \
{0x74b7a390, 0x3b41, 0x11d4, { 0x8a, 0x80, 0x00, 0x60, 0x08, 0xc8, 0x44, 0xc3} }
class PKCS11 : public nsIPKCS11
, public nsNSSShutDownObject
@@ -26,11 +27,14 @@ public:
protected:
virtual ~PKCS11();
private:
virtual void virtualDestroyNSSReference() override {}
};
+void GetModuleNameForTelemetry(/*in*/ const SECMODModule* module,
+ /*out*/nsString& result);
+
} } // namespace mozilla::psm
#endif // PKCS11_h
--- a/security/manager/ssl/nsNSSComponent.cpp
+++ b/security/manager/ssl/nsNSSComponent.cpp
@@ -3,16 +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 "nsNSSComponent.h"
#include "ExtendedValidation.h"
#include "NSSCertDBTrustDomain.h"
+#include "PKCS11.h"
#include "ScopedNSSTypes.h"
#include "SharedSSLState.h"
#include "cert.h"
#include "certdb.h"
#include "mozilla/ArrayUtils.h"
#include "mozilla/Assertions.h"
#include "mozilla/Casting.h"
#include "mozilla/Preferences.h"
@@ -1944,16 +1945,35 @@ nsNSSComponent::InitializeNSS()
LaunchSmartCardThreads();
#endif
mozilla::pkix::RegisterErrorTable();
if (PK11_IsFIPS()) {
Telemetry::Accumulate(Telemetry::FIPS_ENABLED, true);
}
+
+ { // Introduce scope for the AutoSECMODListReadLock.
+ AutoSECMODListReadLock lock;
+ for (SECMODModuleList* list = SECMOD_GetDefaultModuleList(); list;
+ list = list->next) {
+ nsAutoString scalarKey;
+ GetModuleNameForTelemetry(list->module, scalarKey);
+ // Scalar keys must be between 0 and 70 characters (exclusive).
+ // GetModuleNameForTelemetry takes care of keys that are too long. If for
+ // some reason it couldn't come up with an appropriate name and returned
+ // an empty result, however, we need to not attempt to record this (it
+ // wouldn't give us anything useful anyway).
+ if (scalarKey.Length() > 0) {
+ Telemetry::ScalarSet(
+ Telemetry::ScalarID::SECURITY_PKCS11_MODULES_LOADED, scalarKey, true);
+ }
+ }
+ }
+
MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("NSS Initialization done\n"));
mNSSInitialized = true;
return NS_OK;
}
void
nsNSSComponent::ShutdownNSS()
--- a/security/manager/ssl/tests/unit/test_pkcs11_module.js
+++ b/security/manager/ssl/tests/unit/test_pkcs11_module.js
@@ -53,23 +53,54 @@ function checkTestModuleExists() {
"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 checkModuleTelemetry(additionalExpectedModule = undefined) {
+ let expectedModules = [
+ "NSS Internal PKCS #11 Module",
+ `${AppConstants.DLL_PREFIX}nssckbi${AppConstants.DLL_SUFFIX}`,
+ ];
+ if (additionalExpectedModule) {
+ expectedModules.push(additionalExpectedModule);
+ }
+ expectedModules.sort();
+ let telemetryService = Cc["@mozilla.org/base/telemetry;1"]
+ .getService(Ci.nsITelemetry);
+ let telemetry = telemetryService.snapshotKeyedScalars(
+ Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTOUT).parent;
+ let moduleTelemetry = telemetry["security.pkcs11_modules_loaded"];
+ let actualModules = [];
+ Object.keys(moduleTelemetry).forEach((key) => {
+ ok(moduleTelemetry[key], "each keyed scalar should be true");
+ actualModules.push(key);
+ });
+ actualModules.sort();
+ equal(actualModules.length, expectedModules.length,
+ "the number of actual and expected loaded modules should be the same");
+ for (let i in actualModules) {
+ equal(actualModules[i], expectedModules[i],
+ "actual and expected module names should match");
+ }
+}
+
function run_test() {
// Check that if we have never added the test module, that we don't find it
// in the module list.
checkTestModuleNotPresent();
+ checkModuleTelemetry();
// Check that adding the test module makes it appear in the module list.
loadPKCS11TestModule(true);
+ checkModuleTelemetry(
+ `${AppConstants.DLL_PREFIX}pkcs11testmodule${AppConstants.DLL_SUFFIX}`);
let testModule = checkTestModuleExists();
// Check that listing the slots for the test module works.
let slots = testModule.listSlots();
let testModuleSlotNames = [];
while (slots.hasMoreElements()) {
let slot = slots.getNext().QueryInterface(Ci.nsIPKCS11Slot);
testModuleSlotNames.push(slot.name);
--- a/toolkit/components/telemetry/Scalars.yaml
+++ b/toolkit/components/telemetry/Scalars.yaml
@@ -278,16 +278,32 @@ services.sync:
kind: string
keyed: false
notification_emails:
- sync-staff@mozilla.com
release_channel_collection: opt-out
record_in_processes:
- main
+security:
+ pkcs11_modules_loaded:
+ bug_numbers:
+ - 1369911
+ description: >
+ A keyed boolean indicating the library names of the PKCS#11 modules that
+ have been loaded by the browser.
+ expires: "62"
+ kind: boolean
+ keyed: true
+ notification_emails:
+ - seceng-telemetry@mozilla.com
+ release_channel_collection: opt-out
+ record_in_processes:
+ - main
+
# The following section contains WebRTC nICEr scalars
# For more info on ICE, see https://tools.ietf.org/html/rfc5245
# For more info on STUN, see https://tools.ietf.org/html/rfc5389
# For more info on TURN, see https://tools.ietf.org/html/rfc5766
webrtc.nicer:
stun_retransmits:
bug_numbers:
- 1325536