/* 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 "PKCS11ModuleDB.h" #include "CertVerifier.h" #include "PKCS11Module.h" #include "ScopedNSSTypes.h" #include "mozilla/ClearOnShutdown.h" #include "mozilla/ErrorResult.h" #include "mozilla/StaticPrefs_security.h" #include "mozilla/dom/Promise.h" #include "mozilla/dom/ScriptSettings.h" #include "mozilla/glean/SecurityManagerSslMetrics.h" #include "nsComponentManagerUtils.h" #include "nsIWindowWatcher.h" #include "nsIWritablePropertyBag2.h" #include "nsNSSCertHelper.h" #include "nsNSSComponent.h" #include "nsNativeCharsetUtils.h" #include "nsServiceManagerUtils.h" #include "nsThreadUtils.h" #include "nss.h" #include "pk11pub.h" #include "xpcpublic.h" #if defined(XP_MACOSX) # include "nsIFile.h" # include "nsMacUtilsImpl.h" #endif // defined(XP_MACOSX) using mozilla::ErrorResult; using mozilla::dom::Promise; namespace mozilla { namespace psm { NS_IMPL_ISUPPORTS(PKCS11ModuleDB, nsIPKCS11ModuleDB) PKCS11ModuleDB::PKCS11ModuleDB() { MOZ_ASSERT(NS_IsMainThread()); #if defined(NIGHTLY_BUILD) && !defined(MOZ_NO_SMART_CARDS) if (StaticPrefs::security_utility_pkcs11_module_process_enabled() && !GetInSafeMode()) { auto manager = ipc::UtilityProcessManager::GetSingleton(); MOZ_ASSERT(manager); if (manager) { // It would be nice to simply say // `mPKCS11ModuleProcessPromise = manager->StartPKCS11Module();` here, but // `StartPKCS11Module()` is an exclusive promise, whereas what's needed // here is a non-exclusive promise. mPKCS11ModuleProcessPromise = manager->StartPKCS11Module()->Then( GetCurrentSerialEventTarget(), __func__, [](RefPtr&& parent) { MOZ_RELEASE_ASSERT(parent); return PKCS11ModuleProcessPromise::CreateAndResolve( std::move(parent), __func__); }, [](base::LaunchError&& _) { return PKCS11ModuleProcessPromise::CreateAndReject(NS_ERROR_FAILURE, __func__); }); } } #endif // NIGHTLY_BUILD && !MOZ_NO_SMART_CARDS } StaticRefPtr sPKCS11ModuleDB; already_AddRefed PKCS11ModuleDB::GetSingleton() { MOZ_ASSERT(NS_IsMainThread()); if (!NS_IsMainThread()) { return nullptr; } if (!sPKCS11ModuleDB) { sPKCS11ModuleDB = new PKCS11ModuleDB(); ClearOnShutdown(&sPKCS11ModuleDB); } return do_AddRef(sPKCS11ModuleDB); } // Using the NSS serial task queue avoids threading issues in NSS' // implementation of module loading and unloading. nsresult DispatchToNSSTaskQueue(already_AddRefed aRunnable) { nsCOMPtr runnable(aRunnable); nsCOMPtr nss(do_GetService(PSM_COMPONENT_CONTRACTID)); if (!nss) { return NS_ERROR_NOT_AVAILABLE; } nsCOMPtr nssTaskQueue; nsresult rv = nss->GetNssTaskQueue(getter_AddRefs(nssTaskQueue)); if (NS_FAILED(rv)) { return rv; } return nssTaskQueue->Dispatch(runnable.forget()); } // Convert the UTF16 name of the module as it appears to the user to the // internal representation. For most modules this just involves converting from // UTF16 to UTF8. For the builtin root module, it also involves mapping from the // localized name to the internal, non-localized name. static nsresult NormalizeModuleNameIn(const nsAString& moduleNameIn, nsCString& moduleNameOut) { nsAutoString localizedRootModuleName; nsresult rv = GetPIPNSSBundleString("RootCertModuleName", localizedRootModuleName); if (NS_FAILED(rv)) { return rv; } if (moduleNameIn.Equals(localizedRootModuleName)) { moduleNameOut.Assign(kRootModuleName.get()); return NS_OK; } moduleNameOut.Assign(NS_ConvertUTF16toUTF8(moduleNameIn)); return NS_OK; } nsresult PKCS11ModuleDB::DoDeleteModule(const nsCString& moduleName) { if (!NSS_IsInitialized()) { return NS_ERROR_NOT_AVAILABLE; } // modType is an output variable. We ignore it. int32_t modType; SECStatus srv = SECMOD_DeleteModule(moduleName.get(), &modType); if (srv != SECSuccess) { return NS_ERROR_FAILURE; } CollectThirdPartyPKCS11ModuleTelemetry(); return NS_OK; } // Delete a PKCS11 module from the user's profile. NS_IMETHODIMP PKCS11ModuleDB::DeleteModule(const nsAString& aModuleName, JSContext* aCx, Promise** aPromise) { MOZ_ASSERT(NS_IsMainThread()); if (!NS_IsMainThread()) { return NS_ERROR_NOT_SAME_THREAD; } if (aModuleName.IsEmpty()) { return NS_ERROR_INVALID_ARG; } nsAutoCString moduleNameNormalized; nsresult rv = NormalizeModuleNameIn(aModuleName, moduleNameNormalized); if (NS_FAILED(rv)) { return rv; } ErrorResult result; RefPtr promise = Promise::Create(xpc::CurrentNativeGlobal(aCx), result); if (result.Failed()) { return result.StealNSResult(); } auto promiseHolder = MakeRefPtr>( "DeleteModule promise", promise); #if defined(NIGHTLY_BUILD) && !defined(MOZ_NO_SMART_CARDS) if (StaticPrefs::security_utility_pkcs11_module_process_enabled()) { if (!mPKCS11ModuleProcessPromise) { return NS_ERROR_NOT_AVAILABLE; } mPKCS11ModuleProcessPromise->Then( GetCurrentSerialEventTarget(), __func__, [promiseHolder, moduleNameNormalized = std::move(moduleNameNormalized)]( const RefPtr& parent) { MOZ_RELEASE_ASSERT(parent); parent->SendDeleteModule(moduleNameNormalized) ->Then(GetCurrentSerialEventTarget(), __func__, [promiseHolder]( const PPKCS11ModuleParent::DeleteModulePromise:: ResolveOrRejectValue& value) { RefPtr certVerifier( GetDefaultCertVerifier()); if (certVerifier) { certVerifier->ClearTrustCache(); } if (value.IsResolve()) { nsresult rv = value.ResolveValue(); if (NS_SUCCEEDED(rv)) { promiseHolder->get()->MaybeResolveWithUndefined(); } else { promiseHolder->get()->MaybeReject(rv); } } else { promiseHolder->get()->MaybeReject(NS_ERROR_FAILURE); } }); }, [promiseHolder](nsresult rv) { promiseHolder->get()->MaybeReject(rv); }); promise.forget(aPromise); return NS_OK; } #endif // NIGHTLY_BUILD && !MOZ_NO_SMART_CARDS nsCOMPtr runnable(NS_NewRunnableFunction( "DeleteModule runnable", [promiseHolder, moduleNameNormalized = std::move( moduleNameNormalized)]() { nsresult rv = DoDeleteModule(moduleNameNormalized); RefPtr certVerifier(GetDefaultCertVerifier()); if (certVerifier) { certVerifier->ClearTrustCache(); } NS_DispatchToMainThread(NS_NewRunnableFunction( "DeleteModule callback", [rv, promiseHolder] { if (NS_SUCCEEDED(rv)) { promiseHolder->get()->MaybeResolveWithUndefined(); } else { promiseHolder->get()->MaybeReject(rv); } })); })); promise.forget(aPromise); return DispatchToNSSTaskQueue(runnable.forget()); } #if defined(XP_MACOSX) // Given a path to a module, return the filename in `aFilename`. nsresult ModulePathToFilename(const nsCString& aModulePath, nsCString& aFilename) { nsCOMPtr file; nsresult rv = NS_NewLocalFile(NS_ConvertUTF8toUTF16(aModulePath), getter_AddRefs(file)); NS_ENSURE_SUCCESS(rv, rv); nsAutoString filename; rv = file->GetLeafName(filename); NS_ENSURE_SUCCESS(rv, rv); aFilename = NS_ConvertUTF16toUTF8(filename); return NS_OK; } // Collect the signature type and filename of a third-party PKCS11 module to // inform future decisions about module loading restrictions on macOS. void CollectThirdPartyModuleSignatureType(const nsCString& aModulePath) { using mozilla::glean::pkcs11::third_party_module_signature_type; using mozilla::glean::pkcs11::ThirdPartyModuleSignatureTypeExtra; using nsMacUtilsImpl::CodeSignatureTypeToString; nsMacUtilsImpl::CodeSignatureType signatureType = nsMacUtilsImpl::GetSignatureType(aModulePath); nsCString filename; nsresult rv = ModulePathToFilename(aModulePath, filename); NS_ENSURE_SUCCESS_VOID(rv); nsCString signatureTypeStr(CodeSignatureTypeToString(signatureType)); third_party_module_signature_type.Record( Some(ThirdPartyModuleSignatureTypeExtra{ Some(filename), Some(signatureTypeStr), })); } // Collect the filename of a third-party PKCS11 module to inform future // decisions about module loading restrictions on macOS. void CollectThirdPartyModuleFilename(const nsCString& aModulePath) { using mozilla::glean::pkcs11::third_party_module_profile_entries; nsCString filename; nsresult rv = ModulePathToFilename(aModulePath, filename); NS_ENSURE_SUCCESS_VOID(rv); third_party_module_profile_entries.Add(filename); } #endif // defined(XP_MACOSX) nsresult PKCS11ModuleDB::DoAddModule(const nsCString& moduleName, const nsCString& libraryPath, uint32_t mechanismFlags, uint32_t cipherFlags) { if (!NSS_IsInitialized()) { return NS_ERROR_NOT_AVAILABLE; } uint32_t internalMechanismFlags = SECMOD_PubMechFlagstoInternal(mechanismFlags); uint32_t internalCipherFlags = SECMOD_PubCipherFlagstoInternal(cipherFlags); SECStatus srv = SECMOD_AddNewModule(moduleName.get(), libraryPath.get(), internalMechanismFlags, internalCipherFlags); if (srv != SECSuccess) { return NS_ERROR_FAILURE; } #if defined(XP_MACOSX) CollectThirdPartyModuleSignatureType(libraryPath); #endif // defined(XP_MACOSX) CollectThirdPartyPKCS11ModuleTelemetry(); return NS_OK; } // Add a new PKCS11 module to the user's profile. NS_IMETHODIMP PKCS11ModuleDB::AddModule(const nsAString& aModuleName, const nsAString& aLibraryPath, uint32_t aMechanismFlags, uint32_t aCipherFlags, JSContext* aCx, Promise** aPromise) { MOZ_ASSERT(NS_IsMainThread()); if (!NS_IsMainThread()) { return NS_ERROR_NOT_SAME_THREAD; } if (aModuleName.IsEmpty()) { return NS_ERROR_INVALID_ARG; } // "Root Certs" is the name some NSS command-line utilities will give the // roots module if they decide to load it when there happens to be a // `MOZ_DLL_PREFIX "nssckbi" MOZ_DLL_SUFFIX` file in the directory being // operated on. This causes failures, so as a workaround, the PSM // initialization code will unconditionally remove any module named "Root // Certs". We should prevent the user from adding an unrelated module named // "Root Certs" in the first place so PSM doesn't delete it. See bug 1406396. if (aModuleName.EqualsLiteral("Root Certs")) { return NS_ERROR_ILLEGAL_VALUE; } nsAutoCString moduleNameNormalized; nsresult rv = NormalizeModuleNameIn(aModuleName, moduleNameNormalized); if (NS_FAILED(rv)) { return rv; } nsAutoCString libraryPath; CopyUTF16toUTF8(aLibraryPath, libraryPath); ErrorResult result; RefPtr promise = Promise::Create(xpc::CurrentNativeGlobal(aCx), result); if (result.Failed()) { return result.StealNSResult(); } auto promiseHolder = MakeRefPtr>("AddModule promise", promise); #if defined(NIGHTLY_BUILD) && !defined(MOZ_NO_SMART_CARDS) if (StaticPrefs::security_utility_pkcs11_module_process_enabled()) { if (!mPKCS11ModuleProcessPromise) { return NS_ERROR_NOT_AVAILABLE; } mPKCS11ModuleProcessPromise->Then( GetCurrentSerialEventTarget(), __func__, [promiseHolder, moduleNameNormalized, libraryPath, aMechanismFlags, aCipherFlags](const RefPtr& parent) { parent ->SendAddModule(moduleNameNormalized, libraryPath, aMechanismFlags, aCipherFlags) ->Then( GetCurrentSerialEventTarget(), __func__, [promiseHolder](const PPKCS11ModuleParent::AddModulePromise:: ResolveOrRejectValue& value) { RefPtr certVerifier( GetDefaultCertVerifier()); if (certVerifier) { certVerifier->ClearTrustCache(); } if (value.IsResolve()) { nsresult rv = value.ResolveValue(); if (NS_SUCCEEDED(rv)) { promiseHolder->get()->MaybeResolveWithUndefined(); } else { promiseHolder->get()->MaybeReject(rv); } } else { promiseHolder->get()->MaybeReject(NS_ERROR_FAILURE); } }); }, [promiseHolder](nsresult rv) { promiseHolder->get()->MaybeReject(rv); }); promise.forget(aPromise); return NS_OK; } #endif // NIGHTLY_BUILD && !MOZ_NO_SMART_CARDS nsCOMPtr runnable(NS_NewRunnableFunction( "AddModule runnable", [promiseHolder, moduleNameNormalized = std::move(moduleNameNormalized), libraryPath = std::move(libraryPath), mechanismFlags = aMechanismFlags, cipherFlags = aCipherFlags]() { nsresult rv = DoAddModule(moduleNameNormalized, libraryPath, mechanismFlags, cipherFlags); RefPtr certVerifier(GetDefaultCertVerifier()); if (certVerifier) { certVerifier->ClearTrustCache(); } NS_DispatchToMainThread( NS_NewRunnableFunction("AddModule callback", [rv, promiseHolder] { if (NS_SUCCEEDED(rv)) { promiseHolder->get()->MaybeResolveWithUndefined(); } else { promiseHolder->get()->MaybeReject(rv); } })); })); promise.forget(aPromise); return DispatchToNSSTaskQueue(runnable.forget()); } nsresult CollectModules(nsTArray& modules) { if (!NSS_IsInitialized()) { return NS_ERROR_NOT_AVAILABLE; } modules.Clear(); AutoSECMODListReadLock lock; for (SECMODModuleList* list = SECMOD_GetDefaultModuleList(); list; list = list->next) { modules.AppendElement(SECMOD_ReferenceModule(list->module)); } for (SECMODModuleList* list = SECMOD_GetDeadModuleList(); list; list = list->next) { modules.AppendElement(SECMOD_ReferenceModule(list->module)); } return NS_OK; } #if defined(NIGHTLY_BUILD) && !defined(MOZ_NO_SMART_CARDS) // Called in the utility process to list modules loaded there. nsresult PKCS11ModuleDB::DoListModules(nsTArray& modules) { modules.Clear(); nsTArray rawModules; nsresult rv = CollectModules(rawModules); if (NS_FAILED(rv)) { return rv; } for (const auto& rawModule : rawModules) { // Don't list the internal module loaded in the utility process. if (rawModule.get() == SECMOD_GetInternalModule()) { continue; } RefPtr module(new PKCS11Module(rawModule.get())); ModuleInfo moduleInfo; rv = module->GetModuleInfo(moduleInfo); if (NS_FAILED(rv)) { return rv; } modules.AppendElement(std::move(moduleInfo)); } return NS_OK; } #endif // NIGHTLY_BUILD && !MOZ_NO_SMART_CARDS RefPtr PKCS11ModuleDB::ListMainProcessModules() { nsCOMPtr nss(do_GetService(PSM_COMPONENT_CONTRACTID)); if (!nss) { return ListModulesPromise::CreateAndReject(NS_ERROR_NOT_AVAILABLE, __func__); } nsCOMPtr nssTaskQueue; nsresult rv = nss->GetNssTaskQueue(getter_AddRefs(nssTaskQueue)); if (NS_FAILED(rv)) { return ListModulesPromise::CreateAndReject(rv, __func__); } nsCOMPtr mainThread(do_GetMainThread()); using ListRawModulesPromise = MozPromise, nsresult, true>; return InvokeAsync(nssTaskQueue, __func__, []() -> RefPtr { nsTArray rawModules; nsresult rv = CollectModules(rawModules); if (NS_FAILED(rv)) { return ListRawModulesPromise::CreateAndReject( rv, __func__); } return ListRawModulesPromise::CreateAndResolve( std::move(rawModules), __func__); }) ->Then( mainThread, __func__, [](nsTArray rawModules) { nsTArray> modules; for (const auto& rawModule : rawModules) { modules.AppendElement(new PKCS11Module(rawModule.get())); } return ListModulesPromise::CreateAndResolve(std::move(modules), __func__); }, [](nsresult rv) { return ListModulesPromise::CreateAndReject(rv, __func__); }); } #if defined(NIGHTLY_BUILD) && !defined(MOZ_NO_SMART_CARDS) RefPtr PKCS11ModuleDB::ListRemoteProcessModulesGivenParent( const RefPtr& parent) { using ReturnType = std::tuple&&>; return parent->SendListModules()->Then( GetCurrentSerialEventTarget(), __func__, [](ReturnType rv) { if (NS_FAILED(std::get<0>(rv))) { return ListModulesPromise::CreateAndReject(std::get<0>(rv), __func__); } nsTArray> modules; for (const auto& moduleInfo : std::get<1>(rv)) { modules.AppendElement(new RemotePKCS11Module(moduleInfo)); } return ListModulesPromise::CreateAndResolve(std::move(modules), __func__); }, [](ipc::ResponseRejectReason reason) { return ListModulesPromise::CreateAndReject(NS_ERROR_FAILURE, __func__); }); } RefPtr PKCS11ModuleDB::ListRemoteProcessModules() { if (!mPKCS11ModuleProcessPromise) { return ListModulesPromise::CreateAndReject(NS_ERROR_NOT_AVAILABLE, __func__); } return mPKCS11ModuleProcessPromise->Then( GetCurrentSerialEventTarget(), __func__, [](const RefPtr& parent) { MOZ_RELEASE_ASSERT(parent); return ListRemoteProcessModulesGivenParent(parent); }, [](nsresult rv) { return ListModulesPromise::CreateAndReject(rv, __func__); }); } RefPtr PKCS11ModuleDB::ResetTokenGivenParent( const RefPtr& parent, SECMODModuleID moduleID, CK_SLOT_ID slotID) { using ReturnType = std::tuple; return parent->SendResetToken(moduleID, slotID) ->Then( GetCurrentSerialEventTarget(), __func__, [](ReturnType rv) { if (NS_FAILED(std::get<0>(rv))) { return TokenInfoPromise::CreateAndReject(std::get<0>(rv), __func__); } return TokenInfoPromise::CreateAndResolve( std::move(std::get<1>(rv)), __func__); }, [](ipc::ResponseRejectReason reason) { return TokenInfoPromise::CreateAndReject(NS_ERROR_FAILURE, __func__); }); } RefPtr PKCS11ModuleDB::LoginTokenGivenParent( const RefPtr& parent, SECMODModuleID moduleID, CK_SLOT_ID slotID) { using ReturnType = std::tuple; return parent->SendLoginToken(moduleID, slotID) ->Then( GetCurrentSerialEventTarget(), __func__, [](ReturnType rv) { if (NS_FAILED(std::get<0>(rv))) { return TokenInfoPromise::CreateAndReject(std::get<0>(rv), __func__); } return TokenInfoPromise::CreateAndResolve( std::move(std::get<1>(rv)), __func__); }, [](ipc::ResponseRejectReason reason) { return TokenInfoPromise::CreateAndReject(NS_ERROR_FAILURE, __func__); }); } RefPtr PKCS11ModuleDB::LogoutTokenGivenParent( const RefPtr& parent, SECMODModuleID moduleID, CK_SLOT_ID slotID) { using ReturnType = std::tuple; return parent->SendLogoutToken(moduleID, slotID) ->Then( GetCurrentSerialEventTarget(), __func__, [](ReturnType rv) { if (NS_FAILED(std::get<0>(rv))) { return TokenInfoPromise::CreateAndReject(std::get<0>(rv), __func__); } return TokenInfoPromise::CreateAndResolve( std::move(std::get<1>(rv)), __func__); }, [](ipc::ResponseRejectReason reason) { return TokenInfoPromise::CreateAndReject(NS_ERROR_FAILURE, __func__); }); } RefPtr PKCS11ModuleDB::ChangeTokenPasswordGivenParent( const RefPtr& parent, SECMODModuleID moduleID, CK_SLOT_ID slotID, const nsCString& oldPassword, const nsCString& newPassword) { using ReturnType = std::tuple; return parent ->SendChangeTokenPassword(moduleID, slotID, oldPassword, newPassword) ->Then( GetCurrentSerialEventTarget(), __func__, [](ReturnType rv) { if (NS_FAILED(std::get<0>(rv))) { return TokenInfoPromise::CreateAndReject(std::get<0>(rv), __func__); } return TokenInfoPromise::CreateAndResolve( std::move(std::get<1>(rv)), __func__); }, [](ipc::ResponseRejectReason reason) { return TokenInfoPromise::CreateAndReject(NS_ERROR_FAILURE, __func__); }); } #endif // NIGHTLY_BUILD && !MOZ_NO_SMART_CARDS NS_IMETHODIMP PKCS11ModuleDB::ListModules(JSContext* aCx, Promise** aPromise) { MOZ_ASSERT(NS_IsMainThread()); if (!NS_IsMainThread()) { return NS_ERROR_NOT_SAME_THREAD; } nsTArray> promises; promises.AppendElement(ListMainProcessModules()); #if defined(NIGHTLY_BUILD) && !defined(MOZ_NO_SMART_CARDS) if (StaticPrefs::security_utility_pkcs11_module_process_enabled()) { promises.AppendElement(ListRemoteProcessModules()); } #endif // NIGHTLY_BUILD && !MOZ_NO_SMART_CARDS ErrorResult result; RefPtr promise = Promise::Create(xpc::CurrentNativeGlobal(aCx), result); if (result.Failed()) { return result.StealNSResult(); } auto promiseHolder = MakeRefPtr>( "ListModules promise", promise); ListModulesPromise::All(GetCurrentSerialEventTarget(), promises) ->Then( GetCurrentSerialEventTarget(), __func__, [promiseHolder]( const nsTArray>>& moduleLists) { nsTArray> modules; for (const auto& moduleList : moduleLists) { modules.AppendElements(moduleList); } promiseHolder->get()->MaybeResolve(modules); }, [promiseHolder]() { promiseHolder->get()->MaybeReject(NS_ERROR_FAILURE); }); promise.forget(aPromise); return NS_OK; } const nsLiteralCString kBuiltInModuleNames[] = { kNSSInternalModuleName, kRootModuleName, kOSClientCertsModuleName, kIPCClientCertsModuleName, }; void CollectThirdPartyPKCS11ModuleTelemetry(bool aIsInitialization) { size_t thirdPartyModulesLoaded = 0; AutoSECMODListReadLock lock; for (SECMODModuleList* list = SECMOD_GetDefaultModuleList(); list; list = list->next) { bool isThirdParty = true; for (const auto& builtInModuleName : kBuiltInModuleNames) { if (builtInModuleName.Equals(list->module->commonName)) { isThirdParty = false; break; } } if (isThirdParty) { thirdPartyModulesLoaded++; #if defined(XP_MACOSX) // Collect third party module filenames once per launch. // We collect signature type when adding a module. It would be wasteful // and duplicative to collect signature information on each launch given // that it requires file I/O. Combining the filename of modules collected // here with signature type and filename collected when adding a module // provides information about existing modules already in use and new // modules. No I/O is required to obtain the filename given the path on // macOS, but defer it to idle-time to avoid adding more work at startup. if (aIsInitialization) { nsCString modulePath(list->module->dllName); NS_DispatchToMainThreadQueue( NS_NewRunnableFunction("CollectThirdPartyModuleFilenameIdle", [modulePath]() { CollectThirdPartyModuleFilename( modulePath); }), EventQueuePriority::Idle); } #endif // defined(XP_MACOSX) } } mozilla::glean::pkcs11::third_party_modules_loaded.Set( thirdPartyModulesLoaded); } #if defined(NIGHTLY_BUILD) && !defined(MOZ_NO_SMART_CARDS) RefPtr PKCS11ModuleDB::ResetToken( SECMODModuleID moduleID, CK_SLOT_ID slotID) { if (!mPKCS11ModuleProcessPromise) { return TokenInfoPromise::CreateAndReject(NS_ERROR_NOT_AVAILABLE, __func__); } return mPKCS11ModuleProcessPromise->Then( GetCurrentSerialEventTarget(), __func__, [moduleID, slotID](const RefPtr& parent) { MOZ_RELEASE_ASSERT(parent); return ResetTokenGivenParent(parent, moduleID, slotID); }, [](nsresult rv) { return TokenInfoPromise::CreateAndReject(rv, __func__); }); } RefPtr PKCS11ModuleDB::LoginToken( SECMODModuleID moduleID, CK_SLOT_ID slotID) { if (!mPKCS11ModuleProcessPromise) { return TokenInfoPromise::CreateAndReject(NS_ERROR_NOT_AVAILABLE, __func__); } return mPKCS11ModuleProcessPromise->Then( GetCurrentSerialEventTarget(), __func__, [moduleID, slotID](const RefPtr& parent) { MOZ_RELEASE_ASSERT(parent); return LoginTokenGivenParent(parent, moduleID, slotID); }, [](nsresult rv) { return TokenInfoPromise::CreateAndReject(rv, __func__); }); } RefPtr PKCS11ModuleDB::LogoutToken( SECMODModuleID moduleID, CK_SLOT_ID slotID) { if (!mPKCS11ModuleProcessPromise) { return TokenInfoPromise::CreateAndReject(NS_ERROR_NOT_AVAILABLE, __func__); } return mPKCS11ModuleProcessPromise->Then( GetCurrentSerialEventTarget(), __func__, [moduleID, slotID](const RefPtr& parent) { MOZ_RELEASE_ASSERT(parent); return LogoutTokenGivenParent(parent, moduleID, slotID); }, [](nsresult rv) { return TokenInfoPromise::CreateAndReject(rv, __func__); }); } RefPtr PKCS11ModuleDB::ChangeTokenPassword( SECMODModuleID moduleID, CK_SLOT_ID slotID, const nsCString& oldPassword, const nsCString& newPassword) { if (!mPKCS11ModuleProcessPromise) { return TokenInfoPromise::CreateAndReject(NS_ERROR_NOT_AVAILABLE, __func__); } return mPKCS11ModuleProcessPromise->Then( GetCurrentSerialEventTarget(), __func__, [moduleID, slotID, oldPassword, newPassword](const RefPtr& parent) { MOZ_RELEASE_ASSERT(parent); return ChangeTokenPasswordGivenParent(parent, moduleID, slotID, oldPassword, newPassword); }, [](nsresult rv) { return TokenInfoPromise::CreateAndReject(rv, __func__); }); } #endif // NIGHTLY_BUILD && !MOZ_NO_SMART_CARDS void ShowProtectedAuthDialog(const nsCString& tokenName, const nsString& promptId) { nsCOMPtr ww = do_GetService("@mozilla.org/embedcomp/window-watcher;1"); if (!ww) { return; } nsCOMPtr activeWindow; if (NS_FAILED(ww->GetActiveWindow(getter_AddRefs(activeWindow))) || !activeWindow) { return; } // Open a modal informational dialog that auto-closes when authentication // completes. It has only a Cancel button - out-of-band PIN entry on the // device itself is the sole confirmation mechanism. nsCOMPtr dialogArgs = do_CreateInstance("@mozilla.org/hash-property-bag;1"); if (!dialogArgs) { return; } if (NS_FAILED(dialogArgs->SetPropertyAsAString( u"tokenName"_ns, NS_ConvertUTF8toUTF16(tokenName)))) { return; } if (NS_FAILED(dialogArgs->SetPropertyAsAString(u"promptId"_ns, promptId))) { return; } // Open the chrome XUL dialog directly via the window watcher. // AutoNoJSAPI ensures that the new window gets a system principal. mozilla::dom::AutoNoJSAPI nojsapi; nsCOMPtr newWindow; (void)ww->OpenWindow(activeWindow, "chrome://pippki/content/protectedAuth.xhtml"_ns, u"_blank"_ns, "centerscreen,chrome,modal,titlebar"_ns, dialogArgs, getter_AddRefs(newWindow)); } } // namespace psm } // namespace mozilla