bug 1498351 - add interface to allow OS-specific user re-authentication r=franziskus
authorDana Keeler <dkeeler@mozilla.com>
Tue, 16 Oct 2018 16:06:30 +0000
changeset 499950 6fc4224069b26bb408ee1b835a74fe1df9c676ed
parent 499949 f992e8a4e7e61a599e8007bf6dfdcb15a3b132f8
child 499951 8eaeb557ba9f438afb0d6a7bd3bfc19f7b6df098
push id1864
push userffxbld-merge
push dateMon, 03 Dec 2018 15:51:40 +0000
treeherdermozilla-release@f040763d99ad [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersfranziskus
bugs1498351
milestone64.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
bug 1498351 - add interface to allow OS-specific user re-authentication r=franziskus This patch introduces the interface with a stub implementation that does nothing. Follow-up bugs will add platform-specific implementations. Differential Revision: https://phabricator.services.mozilla.com/D8480
security/manager/ssl/OSKeyStore.cpp
security/manager/ssl/OSKeyStore.h
security/manager/ssl/OSReauthenticator.cpp
security/manager/ssl/OSReauthenticator.h
security/manager/ssl/moz.build
security/manager/ssl/nsIOSReauthenticator.idl
security/manager/ssl/nsNSSCertTrust.cpp
security/manager/ssl/nsNSSCertTrust.h
security/manager/ssl/nsNSSModule.cpp
security/manager/ssl/tests/unit/test_osreauthenticator.js
security/manager/ssl/tests/unit/xpcshell.ini
--- a/security/manager/ssl/OSKeyStore.cpp
+++ b/security/manager/ssl/OSKeyStore.cpp
@@ -230,17 +230,17 @@ OSKeyStore::GetIsNSSKeyStore(bool* aNSSK
   NS_ENSURE_STATE(mKs);
   *aNSSKeyStore = mKs->IsNSSKeyStore();
   return NS_OK;
 }
 
 // Async interfaces that return promises because the key store implementation
 // might block, e.g. asking for a password.
 
-static nsresult
+nsresult
 GetPromise(JSContext* aCx, /* out */ RefPtr<Promise>& aPromise)
 {
   nsIGlobalObject* globalObject = xpc::CurrentNativeGlobal(aCx);
   if (NS_WARN_IF(!globalObject)) {
     return NS_ERROR_UNEXPECTED;
   }
   ErrorResult result;
   aPromise = Promise::Create(globalObject, result);
--- a/security/manager/ssl/OSKeyStore.h
+++ b/security/manager/ssl/OSKeyStore.h
@@ -63,16 +63,18 @@ private:
   const size_t mKeyByteLength = 16;
   const size_t mIVLength = 12;
 };
 
 #define NS_OSKEYSTORE_CONTRACTID "@mozilla.org/security/oskeystore;1"
 #define NS_OSKEYSTORE_CID \
   { 0x57972956, 0x5718, 0x42d2, { 0x80, 0x70, 0xb3, 0xfc, 0x72, 0x21, 0x2e, 0xaf } }
 
+nsresult GetPromise(JSContext* aCx, /* out */ RefPtr<mozilla::dom::Promise>& aPromise);
+
 class OSKeyStore : public nsIOSKeyStore
 {
 public:
   NS_DECL_THREADSAFE_ISUPPORTS
   NS_DECL_NSIOSKEYSTORE
 
   OSKeyStore();
   nsresult GenerateSecret(const nsACString& aLabel,
new file mode 100644
--- /dev/null
+++ b/security/manager/ssl/OSReauthenticator.cpp
@@ -0,0 +1,72 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ *
+ * 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 "OSReauthenticator.h"
+
+#include "OSKeyStore.h"
+
+NS_IMPL_ISUPPORTS(OSReauthenticator, nsIOSReauthenticator)
+
+using namespace mozilla;
+using dom::Promise;
+
+static nsresult
+ReauthenticateUser(const nsACString& prompt, /* out */ bool& reauthenticated)
+{
+  reauthenticated = false;
+  return NS_OK;
+}
+
+static void
+BackgroundReauthenticateUser(RefPtr<Promise>& aPromise,
+                             const nsACString& aPrompt)
+{
+  nsAutoCString recovery;
+  bool reauthenticated;
+  nsresult rv = ReauthenticateUser(aPrompt, reauthenticated);
+  nsCOMPtr<nsIRunnable> runnable(NS_NewRunnableFunction(
+    "BackgroundReauthenticateUserResolve",
+    [rv, reauthenticated, aPromise = std::move(aPromise)]() {
+      if (NS_FAILED(rv)) {
+        aPromise->MaybeReject(rv);
+      } else {
+        aPromise->MaybeResolve(reauthenticated);
+      }
+    }));
+  NS_DispatchToMainThread(runnable.forget());
+}
+
+NS_IMETHODIMP
+OSReauthenticator::AsyncReauthenticateUser(const nsACString& aPrompt,
+                                           JSContext* aCx,
+                                           Promise** promiseOut)
+{
+  NS_ENSURE_ARG_POINTER(aCx);
+
+  RefPtr<Promise> promiseHandle;
+  nsresult rv = GetPromise(aCx, promiseHandle);
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
+
+  nsCOMPtr<nsIRunnable> runnable(
+    NS_NewRunnableFunction("BackgroundReauthenticateUser",
+      [promiseHandle, aPrompt = nsAutoCString(aPrompt)]() mutable {
+        BackgroundReauthenticateUser(promiseHandle, aPrompt);
+      }
+    )
+  );
+
+  nsCOMPtr<nsIThread> thread;
+  rv = NS_NewNamedThread(NS_LITERAL_CSTRING("ReauthenticateUserThread"),
+                         getter_AddRefs(thread), runnable);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+
+  promiseHandle.forget(promiseOut);
+  return NS_OK;
+}
new file mode 100644
--- /dev/null
+++ b/security/manager/ssl/OSReauthenticator.h
@@ -0,0 +1,26 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ *
+ * 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/. */
+
+#ifndef OSReauthenticator_h
+#define OSReauthenticator_h
+
+#include "nsIOSReauthenticator.h"
+
+#define NS_OSREAUTHENTICATOR_CONTRACTID "@mozilla.org/security/osreauthenticator;1"
+#define NS_OSREAUTHENTICATOR_CID \
+  { 0x4fe082ae, 0x6ff0, 0x4b41, { 0xb2, 0x4f, 0xea, 0xa6, 0x64, 0xf6, 0xe4, 0x6a } }
+
+class OSReauthenticator : public nsIOSReauthenticator
+{
+public:
+  NS_DECL_THREADSAFE_ISUPPORTS
+  NS_DECL_NSIOSREAUTHENTICATOR
+
+private:
+  virtual ~OSReauthenticator() = default;
+};
+
+#endif // OSReauthenticator_h
--- a/security/manager/ssl/moz.build
+++ b/security/manager/ssl/moz.build
@@ -21,16 +21,17 @@ XPIDL_SOURCES += [
     'nsIGenKeypairInfoDlg.idl',
     'nsIKeygenThread.idl',
     'nsIKeyModule.idl',
     'nsILocalCertService.idl',
     'nsINSSComponent.idl',
     'nsINSSErrorsService.idl',
     'nsINSSVersion.idl',
     'nsIOSKeyStore.idl',
+    'nsIOSReauthenticator.idl',
     'nsIPK11Token.idl',
     'nsIPK11TokenDB.idl',
     'nsIPKCS11Module.idl',
     'nsIPKCS11ModuleDB.idl',
     'nsIPKCS11Slot.idl',
     'nsIProtectedAuthThread.idl',
     'nsISecretDecoderRing.idl',
     'nsISecurityUITelemetry.idl',
@@ -121,16 +122,17 @@ UNIFIED_SOURCES += [
     'nsSecureBrowserUIImpl.cpp',
     'nsSecurityHeaderParser.cpp',
     'NSSErrorsService.cpp',
     'nsSiteSecurityService.cpp',
     'NSSKeyStore.cpp',
     'nsSSLSocketProvider.cpp',
     'nsTLSSocketProvider.cpp',
     'OSKeyStore.cpp',
+    'OSReauthenticator.cpp',
     'PKCS11ModuleDB.cpp',
     'PSMContentListener.cpp',
     'PSMRunnable.cpp',
     'PublicKeyPinningService.cpp',
     'RootCertificateTelemetryUtils.cpp',
     'SecretDecoderRing.cpp',
     'SharedSSLState.cpp',
     'SSLServerCertVerification.cpp',
new file mode 100644
--- /dev/null
+++ b/security/manager/ssl/nsIOSReauthenticator.idl
@@ -0,0 +1,41 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* 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.idl"
+
+[scriptable, uuid(4fe082ae-6ff0-4b41-b24f-eaa664f6e46a)]
+interface nsIOSReauthenticator: nsISupports {
+  /**
+   * This interface provides an abstract way to request that the user
+   * reauthenticate themselves to the operating system. It may be useful in
+   * conjunction with nsIOSKeyStore, whereby consumers of these APIs may
+   * consider some secrets too sensitive to access without first
+   * reauthenticating the user.
+   *
+   * Usage:
+   *
+   * // obtain the singleton nsIOSReauthenticator instance
+   * const reauthenticator = Cc["@mozilla.org/security/osreauthenticator;1"]
+   *                           .getService(Ci.nsIOSReauthenticator);
+   * if (await reauthenticator.asyncReauthenticate()) {
+   *   // do something only authenticated users are allowed to do...
+   * } else {
+   *   // show a "sorry, this isn't allowed" error
+   * }
+   */
+
+  /**
+   * Asynchronously cause the operating system to request that the user
+   * reauthenticate. This is typically in the form of a dialog box asking the
+   * user for their login password. The actual behaviour of this depends on the
+   * OS.
+   *
+   * @param prompt A short string that may be incorporated in the dialog
+   * @return Promise resolving to true if the user successfully authenticated
+   *         and false otherwise.
+   */
+  [implicit_jscontext, must_use]
+  Promise asyncReauthenticateUser(in ACString prompt);
+};
--- a/security/manager/ssl/nsNSSCertTrust.cpp
+++ b/security/manager/ssl/nsNSSCertTrust.cpp
@@ -1,14 +1,16 @@
 /* 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 "nsNSSCertTrust.h"
 
+#include "certdb.h"
+
 void
 nsNSSCertTrust::AddCATrust(bool ssl, bool email)
 {
   if (ssl) {
     addTrust(&mTrust.sslFlags, CERTDB_TRUSTED_CA);
     addTrust(&mTrust.sslFlags, CERTDB_TRUSTED_CLIENT_CA);
   }
   if (email) {
--- a/security/manager/ssl/nsNSSCertTrust.h
+++ b/security/manager/ssl/nsNSSCertTrust.h
@@ -1,16 +1,15 @@
 /* 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/. */
 
 #ifndef nsNSSCertTrust_h
 #define nsNSSCertTrust_h
 
-#include "certdb.h"
 #include "certt.h"
 
 /*
  * Class for maintaining trust flags for an NSS certificate.
  */
 class nsNSSCertTrust
 {
 public:
--- a/security/manager/ssl/nsNSSModule.cpp
+++ b/security/manager/ssl/nsNSSModule.cpp
@@ -29,16 +29,17 @@
 #include "nsPKCS11Slot.h"
 #include "nsRandomGenerator.h"
 #include "nsSSLSocketProvider.h"
 #include "nsSecureBrowserUIImpl.h"
 #include "nsSiteSecurityService.h"
 #include "nsTLSSocketProvider.h"
 #include "nsXULAppAPI.h"
 #include "OSKeyStore.h"
+#include "OSReauthenticator.h"
 
 #ifdef MOZ_XUL
 #include "nsCertTree.h"
 #endif
 
 namespace mozilla { namespace psm {
 
 // Many of the implementations in this module call NSS functions and as a result
@@ -155,16 +156,17 @@ NS_DEFINE_NAMED_CID(NS_CERTOVERRIDE_CID)
 NS_DEFINE_NAMED_CID(NS_RANDOMGENERATOR_CID);
 NS_DEFINE_NAMED_CID(TRANSPORTSECURITYINFO_CID);
 NS_DEFINE_NAMED_CID(NS_NSSERRORSSERVICE_CID);
 NS_DEFINE_NAMED_CID(NS_NSSVERSION_CID);
 NS_DEFINE_NAMED_CID(NS_SECURE_BROWSER_UI_CID);
 NS_DEFINE_NAMED_CID(NS_SITE_SECURITY_SERVICE_CID);
 NS_DEFINE_NAMED_CID(NS_CERT_BLOCKLIST_CID);
 NS_DEFINE_NAMED_CID(NS_OSKEYSTORE_CID);
+NS_DEFINE_NAMED_CID(NS_OSREAUTHENTICATOR_CID);
 
 // Components that require main thread initialization could cause a deadlock
 // in necko code (bug 1418752). To prevent it we initialize all such components
 // on main thread in advance in net_EnsurePSMInit(). Update that function when
 // new component with ThreadRestriction::MainThreadOnly is added.
 static const mozilla::Module::CIDEntry kNSSCIDs[] = {
   { &kNS_NSSCOMPONENT_CID, false, nullptr, nsNSSComponentConstructor },
   { &kNS_SSLSOCKETPROVIDER_CID, false, nullptr,
@@ -216,16 +218,20 @@ static const mozilla::Module::CIDEntry k
   { &kNS_CERT_BLOCKLIST_CID, false, nullptr,
     Constructor<CertBlocklist, &CertBlocklist::Init,
                 ProcessRestriction::ParentProcessOnly,
                 ThreadRestriction::MainThreadOnly> },
   { &kNS_OSKEYSTORE_CID, false, nullptr, Constructor<OSKeyStore,
                 nullptr,
                 ProcessRestriction::ParentProcessOnly,
                 ThreadRestriction::MainThreadOnly> },
+  { &kNS_OSREAUTHENTICATOR_CID, false, nullptr, Constructor<OSReauthenticator,
+                nullptr,
+                ProcessRestriction::ParentProcessOnly,
+                ThreadRestriction::MainThreadOnly> },
   { nullptr }
 };
 
 static const mozilla::Module::ContractIDEntry kNSSContracts[] = {
   { PSM_COMPONENT_CONTRACTID, &kNS_NSSCOMPONENT_CID },
   { NS_NSS_ERRORS_SERVICE_CONTRACTID, &kNS_NSSERRORSSERVICE_CID },
   { NS_NSSVERSION_CONTRACTID, &kNS_NSSVERSION_CID },
   { NS_SSLSOCKETPROVIDER_CONTRACTID, &kNS_SSLSOCKETPROVIDER_CID },
@@ -248,16 +254,17 @@ static const mozilla::Module::ContractID
   { NS_KEYMODULEOBJECTFACTORY_CONTRACTID, &kNS_KEYMODULEOBJECTFACTORY_CID },
   { NS_CONTENTSIGNATUREVERIFIER_CONTRACTID, &kNS_CONTENTSIGNATUREVERIFIER_CID },
   { NS_CERTOVERRIDE_CONTRACTID, &kNS_CERTOVERRIDE_CID },
   { NS_RANDOMGENERATOR_CONTRACTID, &kNS_RANDOMGENERATOR_CID },
   { NS_SECURE_BROWSER_UI_CONTRACTID, &kNS_SECURE_BROWSER_UI_CID },
   { NS_SSSERVICE_CONTRACTID, &kNS_SITE_SECURITY_SERVICE_CID },
   { NS_CERTBLOCKLIST_CONTRACTID, &kNS_CERT_BLOCKLIST_CID },
   { NS_OSKEYSTORE_CONTRACTID, &kNS_OSKEYSTORE_CID},
+  { NS_OSREAUTHENTICATOR_CONTRACTID, &kNS_OSREAUTHENTICATOR_CID},
   { nullptr }
 };
 
 static const mozilla::Module::CategoryEntry kNSSCategories[] = {
   { NS_CONTENT_LISTENER_CATEGORYMANAGER_ENTRY, "application/x-x509-ca-cert", "@mozilla.org/uriloader/psm-external-content-listener;1" },
   { NS_CONTENT_LISTENER_CATEGORYMANAGER_ENTRY, "application/x-x509-server-cert", "@mozilla.org/uriloader/psm-external-content-listener;1" },
   { NS_CONTENT_LISTENER_CATEGORYMANAGER_ENTRY, "application/x-x509-user-cert", "@mozilla.org/uriloader/psm-external-content-listener;1" },
   { NS_CONTENT_LISTENER_CATEGORYMANAGER_ENTRY, "application/x-x509-email-cert", "@mozilla.org/uriloader/psm-external-content-listener;1" },
new file mode 100644
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_osreauthenticator.js
@@ -0,0 +1,16 @@
+/* -*- 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 nsIOSReauthenticator.asyncReauthenticateUser().
+// Currently this always resolves to false on all platforms. As this gets implemented on various
+// platforms, running this rest will result in a prompt from the OS. Consequently, we won't be able
+// to run this in automation, but it will help in testing locally.
+add_task(async function test_asyncReauthenticateUser() {
+  const reauthenticator = Cc["@mozilla.org/security/osreauthenticator;1"]
+                            .getService(Ci.nsIOSReauthenticator);
+  ok(reauthenticator, "nsIOSReauthenticator should be available");
+  ok(!await reauthenticator.asyncReauthenticateUser("this is the prompt string"),
+     "nsIOSReauthenticator.asyncReauthenticateUser always resolves to false for now");
+});
--- a/security/manager/ssl/tests/unit/xpcshell.ini
+++ b/security/manager/ssl/tests/unit/xpcshell.ini
@@ -136,16 +136,17 @@ run-sequentially = hardcoded ports
 run-sequentially = hardcoded ports
 [test_ocsp_stapling_with_intermediate.js]
 run-sequentially = hardcoded ports
 [test_ocsp_timeout.js]
 run-sequentially = hardcoded ports
 [test_ocsp_url.js]
 run-sequentially = hardcoded ports
 [test_oskeystore.js]
+[test_osreauthenticator.js]
 [test_password_prompt.js]
 [test_pinning.js]
 run-sequentially = hardcoded ports
 # This test can take longer than 300 seconds on B2G emulator debug builds, so
 # give it enough time to finish. See bug 1081128.
 requesttimeoutfactor = 2
 [test_pinning_dynamic.js]
 [test_pinning_header_parsing.js]