1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "PKCS11ModuleDB.h"
9 #include "CertVerifier.h"
10 #include "ScopedNSSTypes.h"
11 #include "mozilla/glean/GleanMetrics.h"
12 #include "nsComponentManagerUtils.h"
13 #include "nsIMutableArray.h"
14 #include "nsNSSCertHelper.h"
15 #include "nsNSSComponent.h"
16 #include "nsNativeCharsetUtils.h"
17 #include "nsPKCS11Slot.h"
18 #include "nsServiceManagerUtils.h"
23 NS_IMPL_ISUPPORTS(PKCS11ModuleDB
, nsIPKCS11ModuleDB
)
25 // Convert the UTF16 name of the module as it appears to the user to the
26 // internal representation. For most modules this just involves converting from
27 // UTF16 to UTF8. For the builtin root module, it also involves mapping from the
28 // localized name to the internal, non-localized name.
29 static nsresult
NormalizeModuleNameIn(const nsAString
& moduleNameIn
,
30 nsCString
& moduleNameOut
) {
31 nsAutoString localizedRootModuleName
;
33 GetPIPNSSBundleString("RootCertModuleName", localizedRootModuleName
);
37 if (moduleNameIn
.Equals(localizedRootModuleName
)) {
38 moduleNameOut
.Assign(kRootModuleName
.get());
41 moduleNameOut
.Assign(NS_ConvertUTF16toUTF8(moduleNameIn
));
45 // Delete a PKCS11 module from the user's profile.
47 PKCS11ModuleDB::DeleteModule(const nsAString
& aModuleName
) {
48 if (aModuleName
.IsEmpty()) {
49 return NS_ERROR_INVALID_ARG
;
52 nsAutoCString moduleNameNormalized
;
53 nsresult rv
= NormalizeModuleNameIn(aModuleName
, moduleNameNormalized
);
57 // modType is an output variable. We ignore it.
59 SECStatus srv
= SECMOD_DeleteModule(moduleNameNormalized
.get(), &modType
);
60 if (srv
!= SECSuccess
) {
61 return NS_ERROR_FAILURE
;
64 RefPtr
<SharedCertVerifier
> certVerifier(GetDefaultCertVerifier());
66 return NS_ERROR_FAILURE
;
68 certVerifier
->ClearTrustCache();
70 CollectThirdPartyPKCS11ModuleTelemetry();
75 // Add a new PKCS11 module to the user's profile.
77 PKCS11ModuleDB::AddModule(const nsAString
& aModuleName
,
78 const nsAString
& aLibraryFullPath
,
79 int32_t aCryptoMechanismFlags
, int32_t aCipherFlags
) {
80 if (aModuleName
.IsEmpty()) {
81 return NS_ERROR_INVALID_ARG
;
84 // "Root Certs" is the name some NSS command-line utilities will give the
85 // roots module if they decide to load it when there happens to be a
86 // `MOZ_DLL_PREFIX "nssckbi" MOZ_DLL_SUFFIX` file in the directory being
87 // operated on. This causes failures, so as a workaround, the PSM
88 // initialization code will unconditionally remove any module named "Root
89 // Certs". We should prevent the user from adding an unrelated module named
90 // "Root Certs" in the first place so PSM doesn't delete it. See bug 1406396.
91 if (aModuleName
.EqualsLiteral("Root Certs")) {
92 return NS_ERROR_ILLEGAL_VALUE
;
95 // There appears to be a deadlock if we try to load modules concurrently, so
96 // just wait until the loadable roots module has been loaded.
97 nsresult rv
= BlockUntilLoadableCertsLoaded();
102 nsAutoCString moduleNameNormalized
;
103 rv
= NormalizeModuleNameIn(aModuleName
, moduleNameNormalized
);
108 CopyUTF16toUTF8(aLibraryFullPath
, fullPath
);
109 uint32_t mechFlags
= SECMOD_PubMechFlagstoInternal(aCryptoMechanismFlags
);
110 uint32_t cipherFlags
= SECMOD_PubCipherFlagstoInternal(aCipherFlags
);
111 SECStatus srv
= SECMOD_AddNewModule(moduleNameNormalized
.get(),
112 fullPath
.get(), mechFlags
, cipherFlags
);
113 if (srv
!= SECSuccess
) {
114 return NS_ERROR_FAILURE
;
117 RefPtr
<SharedCertVerifier
> certVerifier(GetDefaultCertVerifier());
119 return NS_ERROR_FAILURE
;
121 certVerifier
->ClearTrustCache();
123 CollectThirdPartyPKCS11ModuleTelemetry();
129 PKCS11ModuleDB::ListModules(nsISimpleEnumerator
** _retval
) {
130 NS_ENSURE_ARG_POINTER(_retval
);
132 nsresult rv
= BlockUntilLoadableCertsLoaded();
137 nsCOMPtr
<nsIMutableArray
> array
= do_CreateInstance(NS_ARRAY_CONTRACTID
);
139 return NS_ERROR_FAILURE
;
142 /* lock down the list for reading */
143 AutoSECMODListReadLock lock
;
144 for (SECMODModuleList
* list
= SECMOD_GetDefaultModuleList(); list
;
146 nsCOMPtr
<nsIPKCS11Module
> module
= new nsPKCS11Module(list
->module
);
147 nsresult rv
= array
->AppendElement(module
);
153 /* Get the modules in the database that didn't load */
154 for (SECMODModuleList
* list
= SECMOD_GetDeadModuleList(); list
;
156 nsCOMPtr
<nsIPKCS11Module
> module
= new nsPKCS11Module(list
->module
);
157 nsresult rv
= array
->AppendElement(module
);
163 return array
->Enumerate(_retval
, NS_GET_IID(nsIPKCS11Module
));
167 PKCS11ModuleDB::GetCanToggleFIPS(bool* aCanToggleFIPS
) {
168 NS_ENSURE_ARG_POINTER(aCanToggleFIPS
);
170 *aCanToggleFIPS
= SECMOD_CanDeleteInternalModule();
175 PKCS11ModuleDB::ToggleFIPSMode() {
176 // The way to toggle FIPS mode in NSS is extremely obscure. Basically, we
177 // delete the internal module, and it gets replaced with the opposite module
178 // (i.e. if it was FIPS before, then it becomes non-FIPS next).
179 // SECMOD_GetInternalModule() returns a pointer to a local copy of the
180 // internal module stashed in NSS. We don't want to delete it since it will
181 // cause much pain in NSS.
182 SECMODModule
* internal
= SECMOD_GetInternalModule();
184 return NS_ERROR_FAILURE
;
187 if (SECMOD_DeleteInternalModule(internal
->commonName
) != SECSuccess
) {
188 return NS_ERROR_FAILURE
;
195 PKCS11ModuleDB::GetIsFIPSEnabled(bool* aIsFIPSEnabled
) {
196 NS_ENSURE_ARG_POINTER(aIsFIPSEnabled
);
198 *aIsFIPSEnabled
= PK11_IsFIPS();
202 const nsLiteralCString kBuiltInModuleNames
[] = {
203 kNSSInternalModuleName
,
205 kOSClientCertsModuleName
,
206 kIPCClientCertsModuleName
,
209 void CollectThirdPartyPKCS11ModuleTelemetry() {
210 size_t thirdPartyModulesLoaded
= 0;
211 AutoSECMODListReadLock lock
;
212 for (SECMODModuleList
* list
= SECMOD_GetDefaultModuleList(); list
;
214 bool isThirdParty
= true;
215 for (const auto& builtInModuleName
: kBuiltInModuleNames
) {
216 if (builtInModuleName
.Equals(list
->module
->commonName
)) {
217 isThirdParty
= false;
222 thirdPartyModulesLoaded
++;
225 mozilla::glean::pkcs11::third_party_modules_loaded
.Set(
226 thirdPartyModulesLoaded
);
230 } // namespace mozilla