Bug 1323339 - Add U2FTokenManager class and support IPC Parent classes draft
authorKyle Machulis <kyle@nonpolynomial.com>
Thu, 06 Apr 2017 15:38:22 -0700
changeset 563021 f247067155e4abb8df1ce31803547b598e0ff886
parent 563020 f3de4a8744bd5a3f7a6411a4d6d8cae501c331d8
child 563022 149f1bdbacae6d64696b2c9a584951aa77d1c0c5
push id54191
push userbmo:kyle@nonpolynomial.com
push dateFri, 14 Apr 2017 21:52:13 +0000
bugs1323339
milestone55.0a1
Bug 1323339 - Add U2FTokenManager class and support IPC Parent classes Takes functionaliy once in the WebAuthentication class that now needs to be handled by the parent process, and moves it to the U2FTokenManager singleton class. U2FTokenManager is created on PBackground during the first WebAuthn transaction, and manages hardware access and transaction management for the lifetime of the browser session. Patch also adds parent classes for WebAuthn IPC protocol. MozReview-Commit-ID: FupAj5qBl6v
dom/webauthn/U2FTokenManager.cpp
dom/webauthn/U2FTokenManager.h
dom/webauthn/U2FTokenTransport.h
dom/webauthn/WebAuthnTransactionParent.cpp
dom/webauthn/WebAuthnTransactionParent.h
dom/webauthn/moz.build
ipc/glue/BackgroundParentImpl.cpp
ipc/glue/BackgroundParentImpl.h
new file mode 100644
--- /dev/null
+++ b/dom/webauthn/U2FTokenManager.cpp
@@ -0,0 +1,193 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim:set ts=2 sw=2 sts=2 et cindent: */
+/* 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 "mozilla/dom/U2FTokenManager.h"
+#include "mozilla/dom/U2FTokenTransport.h"
+#include "mozilla/dom/WebAuthnTransactionParent.h"
+#include "mozilla/MozPromise.h"
+#include "mozilla/dom/WebAuthnUtil.h"
+#include "mozilla/ClearOnShutdown.h"
+#include "mozilla/Unused.h"
+#include "hasht.h"
+#include "nsICryptoHash.h"
+#include "pkix/Input.h"
+#include "pkixutil.h"
+
+namespace mozilla {
+namespace dom {
+
+/***********************************************************************
+ * Statics
+ **********************************************************************/
+
+static mozilla::LazyLogModule gU2FTokenManagerLog("u2fkeymanager");
+StaticRefPtr<U2FTokenManager> gU2FTokenManager;
+
+/***********************************************************************
+ * Utility Functions
+ **********************************************************************/
+
+static nsresult
+ReadToCryptoBuffer(pkix::Reader& aSrc, /* out */ CryptoBuffer& aDest,
+                   uint32_t aLen)
+{
+  if (aSrc.EnsureLength(aLen) != pkix::Success) {
+    return NS_ERROR_DOM_UNKNOWN_ERR;
+  }
+
+  aDest.ClearAndRetainStorage();
+
+  for (uint32_t offset = 0; offset < aLen; ++offset) {
+    uint8_t b;
+    if (aSrc.Read(b) != pkix::Success) {
+      return NS_ERROR_DOM_UNKNOWN_ERR;
+    }
+    if (!aDest.AppendElement(b, mozilla::fallible)) {
+      return NS_ERROR_OUT_OF_MEMORY;
+    }
+  }
+
+  return NS_OK;
+}
+
+/***********************************************************************
+ * U2FManager Implementation
+ **********************************************************************/
+
+class BackgroundDeleter
+{
+public:
+  NS_INLINE_DECL_REFCOUNTING(BackgroundDeleter);
+  RefPtr<MozPromise<bool, bool, false>>
+  GetPromise() {
+    return mDeletionPromise.Ensure(__func__);
+  }
+private:
+  virtual ~BackgroundDeleter() {
+    mDeletionPromise.Resolve(true, __func__);
+  }
+  MozPromiseHolder<MozPromise<bool, bool, false>> mDeletionPromise;
+};
+
+StaticRefPtr<BackgroundDeleter> gBG;
+
+U2FTokenManager::U2FTokenManager() :
+  mOwningThread(AbstractThread::CreateXPCOMThreadWrapper(NS_GetCurrentThread(), false))
+{
+  MOZ_ASSERT(XRE_IsParentProcess());
+  InvokeAsync(AbstractThread::MainThread(), __func__, []() {
+      gBG = new BackgroundDeleter();
+      ClearOnShutdown(&gBG, ShutdownPhase::ShutdownThreads);
+      return gBG->GetPromise();
+    })->Then(mOwningThread, __func__, []() {
+        gU2FTokenManager = nullptr;
+      },
+      []() {
+      });
+}
+
+U2FTokenManager::~U2FTokenManager()
+{
+}
+
+void
+U2FTokenManager::Init()
+{
+}
+
+//static
+U2FTokenManager*
+U2FTokenManager::GetOrCreate()
+{
+  MOZ_ASSERT(XRE_IsParentProcess());
+  if (!gU2FTokenManager) {
+    gU2FTokenManager = new U2FTokenManager();
+  }
+  return gU2FTokenManager;
+}
+
+//static
+U2FTokenManager*
+U2FTokenManager::Get()
+{
+  MOZ_ASSERT(XRE_IsParentProcess());
+  return gU2FTokenManager;
+}
+
+void
+U2FTokenManager::Register(WebAuthnTransactionParent* aTransactionParent,
+                          const WebAuthnTransactionInfo& aTransactionInfo)
+{
+  this->Run(aTransactionParent,
+            U2FTokenManager::TransactionType::RegisterTransaction,
+            aTransactionInfo);
+}
+
+void
+U2FTokenManager::Sign(WebAuthnTransactionParent* aTransactionParent,
+                      const WebAuthnTransactionInfo& aTransactionInfo)
+{
+  this->Run(aTransactionParent,
+            U2FTokenManager::TransactionType::SignTransaction,
+            aTransactionInfo);
+}
+
+void
+U2FTokenManager::Run(WebAuthnTransactionParent* aTransactionParent,
+                     TransactionType aTransactionType,
+                     const WebAuthnTransactionInfo& aTransactionInfo)
+{
+  MOZ_LOG(gU2FTokenManagerLog, LogLevel::Debug, ("U2FAuthMakeCredential"));
+
+  mTransactionParent = aTransactionParent;
+  mInfo = Some(aTransactionInfo);
+
+  InvokeAsync(AbstractThread::MainThread(), __func__, []() {
+      MOZ_ASSERT(XRE_IsParentProcess());
+      MOZ_ASSERT(NS_IsMainThread());
+      nsTArray<bool> prefs;
+      //TODO: Get preferences for token managers we should use.
+      return PrefPromise::CreateAndResolve(prefs, __func__);
+    })->Then(mOwningThread, __func__,
+             [aTransactionType](const nsTArray<bool>& bools) {
+               U2FTokenManager* mgr = U2FTokenManager::Get();
+               // If the manager disappears before we finish out the promise,
+               // it'll have already cancelled the operation. Just return.
+               if (!mgr) {
+                 return;
+               }
+               mgr->Init();
+               if (aTransactionType == TransactionType::RegisterTransaction) {
+                 mgr->DoRegister();
+               } else if (aTransactionType == TransactionType::SignTransaction) {
+                 mgr->DoSign();
+               } else {
+                 MOZ_CRASH("We shouldn't be here!");
+               }
+             },
+             [](nsresult rv) {
+               MOZ_CRASH("We shouldn't be here!");
+             }
+      );
+}
+
+void
+U2FTokenManager::DoRegister()
+{
+  MOZ_LOG(gU2FTokenManagerLog, LogLevel::Debug, ("U2FAuthRegister"));
+  MOZ_ASSERT(mInfo.isSome());
+  Unused << mTransactionParent->SendCancel(NS_ERROR_DOM_NOT_ALLOWED_ERR);
+}
+
+void U2FTokenManager::DoSign()
+{
+  MOZ_LOG(gU2FTokenManagerLog, LogLevel::Debug, ("U2FAuthSign"));
+  MOZ_ASSERT(mInfo.isSome());
+  Unused << mTransactionParent->SendCancel(NS_ERROR_DOM_NOT_ALLOWED_ERR);
+}
+
+}
+}
new file mode 100644
--- /dev/null
+++ b/dom/webauthn/U2FTokenManager.h
@@ -0,0 +1,53 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim:set ts=2 sw=2 sts=2 et cindent: */
+/* 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 mozilla_dom_U2FTokenManager_h
+#define mozilla_dom_U2FTokenManager_h
+
+#include "mozilla/dom/PWebAuthnTransaction.h"
+#include "mozilla/MozPromise.h"
+
+namespace mozilla {
+namespace dom {
+
+class U2FTokenTransport;
+class WebAuthnTransactionParent;
+
+class U2FTokenManager final {
+  typedef MozPromise<nsTArray<bool>, nsresult, false> PrefPromise;
+public:
+  enum TransactionType {
+    RegisterTransaction = 0,
+    SignTransaction,
+    NumTransactionTypes
+  };
+  NS_INLINE_DECL_REFCOUNTING(U2FTokenManager)
+  static U2FTokenManager* GetOrCreate();
+  static U2FTokenManager* Get();
+  void Init();
+  void Register(WebAuthnTransactionParent* aTransactionParent,
+                const WebAuthnTransactionInfo& aTransactionInfo);
+  void Sign(WebAuthnTransactionParent* aTransactionParent,
+            const WebAuthnTransactionInfo& aTransactionInfo);
+  void DoRegister();
+  void DoSign();
+private:
+  U2FTokenManager();
+  ~U2FTokenManager();
+  void Run(WebAuthnTransactionParent* aTransactionParent,
+           TransactionType aTransactionType,
+           const WebAuthnTransactionInfo& aTransactionInfo);
+  RefPtr<PrefPromise> mPrefPromise;
+  nsTArray<RefPtr<U2FTokenTransport>> mTransports;
+  RefPtr<WebAuthnTransactionParent> mTransactionParent;
+  RefPtr<AbstractThread> mOwningThread;
+  Maybe<WebAuthnTransactionInfo> mInfo;
+};
+
+} // namespace dom
+} // namespace mozilla
+
+#endif // mozilla_dom_U2FTokenManager_h
new file mode 100644
--- /dev/null
+++ b/dom/webauthn/U2FTokenTransport.h
@@ -0,0 +1,32 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim:set ts=2 sw=2 sts=2 et cindent: */
+/* 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 mozilla_dom_U2FTokenTransport_h
+#define mozilla_dom_U2FTokenTransport_h
+
+namespace mozilla {
+namespace dom {
+
+class U2FTokenTransport {
+public:
+  NS_INLINE_DECL_REFCOUNTING(U2FTokenTransport);
+  U2FTokenTransport() {}
+  virtual nsresult Register(nsTArray<uint8_t>& aApplication,
+                            nsTArray<uint8_t>& aChallenge,
+                            /* out */ nsTArray<uint8_t>& aRegistration,
+                            /* out */ nsTArray<uint8_t>& aSignature) = 0;
+  virtual nsresult Sign(nsTArray<uint8_t>& aApplication,
+                        nsTArray<uint8_t>& aChallenge,
+                        nsTArray<uint8_t>& aKeyHandle,
+                        /* out */ nsTArray<uint8_t>& aSignature) = 0;
+protected:
+  virtual ~U2FTokenTransport() {}
+};
+
+} // namespace dom
+} // namespace mozilla
+
+#endif // mozilla_dom_U2FTokenTransport_h
new file mode 100644
--- /dev/null
+++ b/dom/webauthn/WebAuthnTransactionParent.cpp
@@ -0,0 +1,36 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim:set ts=2 sw=2 sts=2 et cindent: */
+/* 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 "mozilla/dom/WebAuthnTransactionParent.h"
+#include "mozilla/dom/U2FTokenManager.h"
+
+namespace mozilla {
+namespace dom {
+
+mozilla::ipc::IPCResult
+WebAuthnTransactionParent::RecvRequestRegister(const WebAuthnTransactionInfo& aTransactionInfo)
+{
+  U2FTokenManager* mgr = U2FTokenManager::GetOrCreate();
+  mgr->Register(this, aTransactionInfo);
+  return IPC_OK();
+}
+
+mozilla::ipc::IPCResult
+WebAuthnTransactionParent::RecvRequestSign(const WebAuthnTransactionInfo& aTransactionInfo)
+{
+  U2FTokenManager* mgr = U2FTokenManager::GetOrCreate();
+  mgr->Sign(this, aTransactionInfo);
+  return IPC_OK();
+}
+
+mozilla::ipc::IPCResult
+WebAuthnTransactionParent::RecvRequestCancel()
+{
+  return IPC_OK();
+}
+
+}
+}
new file mode 100644
--- /dev/null
+++ b/dom/webauthn/WebAuthnTransactionParent.h
@@ -0,0 +1,32 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim:set ts=2 sw=2 sts=2 et cindent: */
+/* 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 mozilla_dom_WebAuthnTransactionParent_h
+#define mozilla_dom_WebAuthnTransactionParent_h
+
+#include "mozilla/dom/PWebAuthnTransactionParent.h"
+
+namespace mozilla {
+namespace dom {
+
+class WebAuthnTransactionParent final : public PWebAuthnTransactionParent {
+public:
+  NS_INLINE_DECL_REFCOUNTING(WebAuthnTransactionParent);
+  WebAuthnTransactionParent() {}
+  virtual mozilla::ipc::IPCResult
+  RecvRequestRegister(const WebAuthnTransactionInfo& aTransactionInfo) override;
+  virtual mozilla::ipc::IPCResult
+  RecvRequestSign(const WebAuthnTransactionInfo& aTransactionInfo) override;
+  virtual mozilla::ipc::IPCResult RecvRequestCancel() override;
+  virtual void ActorDestroy(ActorDestroyReason aWhy) override {}
+private:
+  virtual ~WebAuthnTransactionParent() {}
+};
+
+}
+}
+
+#endif //mozilla_dom_WebAuthnTransactionParent_h
--- a/dom/webauthn/moz.build
+++ b/dom/webauthn/moz.build
@@ -10,34 +10,39 @@ with Files("**"):
 IPDL_SOURCES += [
     'PWebAuthnTransaction.ipdl'
 ]
 
 EXPORTS.mozilla.dom += [
     'NSSU2FTokenRemote.h',
     'ScopedCredential.h',
     'ScopedCredentialInfo.h',
+    'U2FTokenManager.h',
+    'U2FTokenTransport.h',
     'WebAuthentication.h',
     'WebAuthnAssertion.h',
     'WebAuthnAttestation.h',
     'WebAuthnManager.h',
     'WebAuthnRequest.h',
     'WebAuthnTransactionChild.h',
+    'WebAuthnTransactionParent.h',
     'WebAuthnUtil.h'
 ]
 
 UNIFIED_SOURCES += [
     'NSSU2FTokenRemote.cpp',
     'ScopedCredential.cpp',
     'ScopedCredentialInfo.cpp',
+    'U2FTokenManager.cpp',
     'WebAuthentication.cpp',
     'WebAuthnAssertion.cpp',
     'WebAuthnAttestation.cpp',
     'WebAuthnManager.cpp',
     'WebAuthnTransactionChild.cpp',
+    'WebAuthnTransactionParent.cpp',
     'WebAuthnUtil.cpp'
 ]
 
 include('/ipc/chromium/chromium-config.mozbuild')
 
 FINAL_LIBRARY = 'xul'
 
 LOCAL_INCLUDES += [
--- a/ipc/glue/BackgroundParentImpl.cpp
+++ b/ipc/glue/BackgroundParentImpl.cpp
@@ -34,16 +34,17 @@
 #include "mozilla/ipc/BackgroundUtils.h"
 #include "mozilla/ipc/IPCStreamAlloc.h"
 #include "mozilla/ipc/PBackgroundSharedTypes.h"
 #include "mozilla/ipc/PBackgroundTestParent.h"
 #include "mozilla/ipc/PChildToParentStreamParent.h"
 #include "mozilla/ipc/PParentToChildStreamParent.h"
 #include "mozilla/layout/VsyncParent.h"
 #include "mozilla/dom/network/UDPSocketParent.h"
+#include "mozilla/dom/WebAuthnTransactionParent.h"
 #include "mozilla/Preferences.h"
 #include "nsNetUtil.h"
 #include "nsIScriptSecurityManager.h"
 #include "nsProxyRelease.h"
 #include "mozilla/RefPtr.h"
 #include "nsThreadUtils.h"
 #include "nsTraceRefcnt.h"
 #include "nsXULAppAPI.h"
@@ -60,16 +61,17 @@ using mozilla::dom::asmjscache::PAsmJSCa
 using mozilla::dom::cache::PCacheParent;
 using mozilla::dom::cache::PCacheStorageParent;
 using mozilla::dom::cache::PCacheStreamControlParent;
 using mozilla::dom::FileSystemBase;
 using mozilla::dom::FileSystemRequestParent;
 using mozilla::dom::MessagePortParent;
 using mozilla::dom::PMessagePortParent;
 using mozilla::dom::UDPSocketParent;
+using mozilla::dom::WebAuthnTransactionParent;
 
 namespace {
 
 void
 AssertIsOnMainThread()
 {
   MOZ_ASSERT(NS_IsMainThread());
 }
@@ -864,16 +866,34 @@ bool
 BackgroundParentImpl::DeallocPGamepadTestChannelParent(dom::PGamepadTestChannelParent *aActor)
 {
   MOZ_ASSERT(aActor);
   RefPtr<dom::GamepadTestChannelParent> parent =
     dont_AddRef(static_cast<dom::GamepadTestChannelParent*>(aActor));
   return true;
 }
 
+dom::PWebAuthnTransactionParent*
+BackgroundParentImpl::AllocPWebAuthnTransactionParent()
+{
+  RefPtr<dom::WebAuthnTransactionParent> parent =
+    new dom::WebAuthnTransactionParent();
+
+  return parent.forget().take();
+}
+
+bool
+BackgroundParentImpl::DeallocPWebAuthnTransactionParent(dom::PWebAuthnTransactionParent *aActor)
+{
+  MOZ_ASSERT(aActor);
+  RefPtr<dom::WebAuthnTransactionParent> parent =
+    dont_AddRef(static_cast<dom::WebAuthnTransactionParent*>(aActor));
+  return true;
+}
+
 } // namespace ipc
 } // namespace mozilla
 
 void
 TestParent::ActorDestroy(ActorDestroyReason aWhy)
 {
   mozilla::ipc::AssertIsInMainProcess();
   AssertIsOnBackgroundThread();
--- a/ipc/glue/BackgroundParentImpl.h
+++ b/ipc/glue/BackgroundParentImpl.h
@@ -213,14 +213,20 @@ protected:
   virtual bool
   DeallocPGamepadEventChannelParent(PGamepadEventChannelParent *aActor) override;
 
   virtual PGamepadTestChannelParent*
   AllocPGamepadTestChannelParent() override;
 
   virtual bool
   DeallocPGamepadTestChannelParent(PGamepadTestChannelParent* aActor) override;
+
+  virtual PWebAuthnTransactionParent*
+  AllocPWebAuthnTransactionParent() override;
+
+  virtual bool
+  DeallocPWebAuthnTransactionParent(PWebAuthnTransactionParent* aActor) override;
 };
 
 } // namespace ipc
 } // namespace mozilla
 
 #endif // mozilla_ipc_backgroundparentimpl_h__