LCOV - code coverage report
Current view: top level - dom/webauthn - U2FTokenManager.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 36 157 22.9 %
Date: 2017-07-14 16:53:18 Functions: 8 30 26.7 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2             : /* vim:set ts=2 sw=2 sts=2 et cindent: */
       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 file,
       5             :  * You can obtain one at http://mozilla.org/MPL/2.0/. */
       6             : 
       7             : #include "mozilla/dom/U2FTokenManager.h"
       8             : #include "mozilla/dom/U2FTokenTransport.h"
       9             : #include "mozilla/dom/U2FHIDTokenManager.h"
      10             : #include "mozilla/dom/U2FSoftTokenManager.h"
      11             : #include "mozilla/dom/WebAuthnTransactionParent.h"
      12             : #include "mozilla/MozPromise.h"
      13             : #include "mozilla/dom/WebAuthnUtil.h"
      14             : #include "mozilla/ClearOnShutdown.h"
      15             : #include "mozilla/Unused.h"
      16             : #include "hasht.h"
      17             : #include "nsICryptoHash.h"
      18             : #include "pkix/Input.h"
      19             : #include "pkixutil.h"
      20             : 
      21             : // Not named "security.webauth.u2f_softtoken_counter" because setting that
      22             : // name causes the window.u2f object to disappear until preferences get
      23             : // reloaded, as its pref is a substring!
      24             : #define PREF_U2F_NSSTOKEN_COUNTER "security.webauth.softtoken_counter"
      25             : #define PREF_WEBAUTHN_SOFTTOKEN_ENABLED "security.webauth.webauthn_enable_softtoken"
      26             : #define PREF_WEBAUTHN_USBTOKEN_ENABLED "security.webauth.webauthn_enable_usbtoken"
      27             : 
      28             : namespace mozilla {
      29             : namespace dom {
      30             : 
      31             : /***********************************************************************
      32             :  * Statics
      33             :  **********************************************************************/
      34             : 
      35             : class U2FPrefManager;
      36             : 
      37             : namespace {
      38             : static mozilla::LazyLogModule gU2FTokenManagerLog("u2fkeymanager");
      39           3 : StaticRefPtr<U2FTokenManager> gU2FTokenManager;
      40           3 : StaticRefPtr<U2FPrefManager> gPrefManager;
      41             : }
      42             : 
      43             : class U2FPrefManager final : public nsIObserver
      44             : {
      45             : private:
      46           1 :   U2FPrefManager() :
      47           1 :     mPrefMutex("U2FPrefManager Mutex")
      48             :   {
      49           1 :     UpdateValues();
      50           1 :   }
      51           0 :   ~U2FPrefManager() = default;
      52             : 
      53             : public:
      54             :   NS_DECL_ISUPPORTS
      55             : 
      56           1 :   static U2FPrefManager* GetOrCreate()
      57             :   {
      58           1 :     MOZ_ASSERT(NS_IsMainThread());
      59           1 :     if (!gPrefManager) {
      60           1 :       gPrefManager = new U2FPrefManager();
      61           1 :       Preferences::AddStrongObserver(gPrefManager, PREF_WEBAUTHN_SOFTTOKEN_ENABLED);
      62           1 :       Preferences::AddStrongObserver(gPrefManager, PREF_U2F_NSSTOKEN_COUNTER);
      63           1 :       Preferences::AddStrongObserver(gPrefManager, PREF_WEBAUTHN_USBTOKEN_ENABLED);
      64           1 :       ClearOnShutdown(&gPrefManager, ShutdownPhase::ShutdownThreads);
      65             :     }
      66           1 :     return gPrefManager;
      67             :   }
      68             : 
      69           0 :   static U2FPrefManager* Get()
      70             :   {
      71           0 :     return gPrefManager;
      72             :   }
      73             : 
      74           0 :   bool GetSoftTokenEnabled()
      75             :   {
      76           0 :     MutexAutoLock lock(mPrefMutex);
      77           0 :     return mSoftTokenEnabled;
      78             :   }
      79             : 
      80           0 :   int GetSoftTokenCounter()
      81             :   {
      82           0 :     MutexAutoLock lock(mPrefMutex);
      83           0 :     return mSoftTokenCounter;
      84             :   }
      85             : 
      86           0 :   bool GetUsbTokenEnabled()
      87             :   {
      88           0 :     MutexAutoLock lock(mPrefMutex);
      89           0 :     return mUsbTokenEnabled;
      90             :   }
      91             : 
      92             :   NS_IMETHODIMP
      93           0 :   Observe(nsISupports* aSubject,
      94             :           const char* aTopic,
      95             :           const char16_t* aData) override
      96             :   {
      97           0 :     UpdateValues();
      98           0 :     return NS_OK;
      99             :   }
     100             : private:
     101           1 :   void UpdateValues() {
     102           1 :     MOZ_ASSERT(NS_IsMainThread());
     103           2 :     MutexAutoLock lock(mPrefMutex);
     104           1 :     mSoftTokenEnabled = Preferences::GetBool(PREF_WEBAUTHN_SOFTTOKEN_ENABLED);
     105           1 :     mSoftTokenCounter = Preferences::GetUint(PREF_U2F_NSSTOKEN_COUNTER);
     106           1 :     mUsbTokenEnabled = Preferences::GetBool(PREF_WEBAUTHN_USBTOKEN_ENABLED);
     107           1 :   }
     108             : 
     109             :   Mutex mPrefMutex;
     110             :   bool mSoftTokenEnabled;
     111             :   int mSoftTokenCounter;
     112             :   bool mUsbTokenEnabled;
     113             : };
     114             : 
     115          25 : NS_IMPL_ISUPPORTS(U2FPrefManager, nsIObserver);
     116             : 
     117             : /***********************************************************************
     118             :  * U2FManager Implementation
     119             :  **********************************************************************/
     120             : 
     121           1 : U2FTokenManager::U2FTokenManager()
     122             :   : mTransactionParent(nullptr)
     123           1 :   , mTransactionId(0)
     124             : {
     125           1 :   MOZ_ASSERT(XRE_IsParentProcess());
     126             :   // Create on the main thread to make sure ClearOnShutdown() works.
     127           1 :   MOZ_ASSERT(NS_IsMainThread());
     128             :   // Create the preference manager while we're initializing.
     129           1 :   U2FPrefManager::GetOrCreate();
     130           1 : }
     131             : 
     132           0 : U2FTokenManager::~U2FTokenManager()
     133             : {
     134           0 :   MOZ_ASSERT(NS_IsMainThread());
     135           0 : }
     136             : 
     137             : //static
     138             : void
     139           3 : U2FTokenManager::Initialize()
     140             : {
     141           3 :   if (!XRE_IsParentProcess()) {
     142           2 :     return;
     143             :   }
     144           1 :   MOZ_ASSERT(NS_IsMainThread());
     145           1 :   MOZ_ASSERT(!gU2FTokenManager);
     146           1 :   gU2FTokenManager = new U2FTokenManager();
     147           1 :   ClearOnShutdown(&gU2FTokenManager);
     148             : }
     149             : 
     150             : //static
     151             : U2FTokenManager*
     152           0 : U2FTokenManager::Get()
     153             : {
     154           0 :   MOZ_ASSERT(XRE_IsParentProcess());
     155             :   // We should only be accessing this on the background thread
     156           0 :   MOZ_ASSERT(!NS_IsMainThread());
     157           0 :   return gU2FTokenManager;
     158             : }
     159             : 
     160             : void
     161           0 : U2FTokenManager::MaybeAbortTransaction(uint64_t aTransactionId,
     162             :                                        const nsresult& aError)
     163             : {
     164           0 :   if (mTransactionId != aTransactionId) {
     165           0 :     return;
     166             :   }
     167             : 
     168           0 :   AbortTransaction(aError);
     169             : }
     170             : 
     171             : void
     172           0 : U2FTokenManager::AbortTransaction(const nsresult& aError)
     173             : {
     174           0 :   Unused << mTransactionParent->SendCancel(aError);
     175           0 :   ClearTransaction();
     176           0 : }
     177             : 
     178             : void
     179           0 : U2FTokenManager::MaybeClearTransaction(WebAuthnTransactionParent* aParent)
     180             : {
     181             :   // Only clear if we've been requested to do so by our current transaction
     182             :   // parent.
     183           0 :   if (mTransactionParent == aParent) {
     184           0 :     ClearTransaction();
     185             :   }
     186           0 : }
     187             : 
     188             : void
     189           0 : U2FTokenManager::ClearTransaction()
     190             : {
     191           0 :   mTransactionParent = nullptr;
     192             :   // Drop managers at the end of all transactions
     193           0 :   mTokenManagerImpl = nullptr;
     194             :   // Drop promises.
     195           0 :   mRegisterPromise = nullptr;
     196           0 :   mSignPromise = nullptr;
     197             :   // Increase in case we're called by the WebAuthnTransactionParent.
     198           0 :   mTransactionId++;
     199           0 : }
     200             : 
     201             : RefPtr<U2FTokenTransport>
     202           0 : U2FTokenManager::GetTokenManagerImpl()
     203             : {
     204           0 :   if (mTokenManagerImpl) {
     205           0 :     return mTokenManagerImpl;
     206             :   }
     207             : 
     208           0 :   auto pm = U2FPrefManager::Get();
     209           0 :   bool useSoftToken = pm->GetSoftTokenEnabled();
     210           0 :   bool useUsbToken = pm->GetUsbTokenEnabled();
     211             : 
     212             :   // At least one token type must be enabled.
     213             :   // We currently don't support soft and USB tokens enabled at
     214             :   // the same time as the softtoken would always win the race to register.
     215             :   // We could support it for signing though...
     216           0 :   if (!(useSoftToken ^ useUsbToken)) {
     217           0 :     return nullptr;
     218             :   }
     219             : 
     220           0 :   if (useSoftToken) {
     221           0 :     return new U2FSoftTokenManager(pm->GetSoftTokenCounter());
     222             :   }
     223             : 
     224             :   // TODO Use WebAuthnRequest to aggregate results from all transports,
     225             :   //      once we have multiple HW transport types.
     226           0 :   return new U2FHIDTokenManager();
     227             : }
     228             : 
     229             : void
     230           0 : U2FTokenManager::Register(WebAuthnTransactionParent* aTransactionParent,
     231             :                           const WebAuthnTransactionInfo& aTransactionInfo)
     232             : {
     233           0 :   MOZ_LOG(gU2FTokenManagerLog, LogLevel::Debug, ("U2FAuthRegister"));
     234           0 :   MOZ_ASSERT(U2FPrefManager::Get());
     235             : 
     236           0 :   uint64_t tid = ++mTransactionId;
     237           0 :   mTransactionParent = aTransactionParent;
     238           0 :   mTokenManagerImpl = GetTokenManagerImpl();
     239             : 
     240           0 :   if (!mTokenManagerImpl) {
     241           0 :     AbortTransaction(NS_ERROR_DOM_NOT_ALLOWED_ERR);
     242           0 :     return;
     243             :   }
     244             : 
     245             :   // Check if all the supplied parameters are syntactically well-formed and
     246             :   // of the correct length. If not, return an error code equivalent to
     247             :   // UnknownError and terminate the operation.
     248             : 
     249           0 :   if ((aTransactionInfo.RpIdHash().Length() != SHA256_LENGTH) ||
     250           0 :       (aTransactionInfo.ClientDataHash().Length() != SHA256_LENGTH)) {
     251           0 :     AbortTransaction(NS_ERROR_DOM_UNKNOWN_ERR);
     252           0 :     return;
     253             :   }
     254             : 
     255           0 :   mRegisterPromise = mTokenManagerImpl->Register(aTransactionInfo.Descriptors(),
     256             :                                                  aTransactionInfo.RpIdHash(),
     257           0 :                                                  aTransactionInfo.ClientDataHash());
     258             : 
     259             :   mRegisterPromise->Then(GetCurrentThreadSerialEventTarget(), __func__,
     260           0 :                          [tid](U2FRegisterResult&& aResult) {
     261           0 :                            U2FTokenManager* mgr = U2FTokenManager::Get();
     262           0 :                            mgr->MaybeConfirmRegister(tid, aResult);
     263           0 :                          },
     264           0 :                          [tid](nsresult rv) {
     265           0 :                            MOZ_ASSERT(NS_FAILED(rv));
     266           0 :                            U2FTokenManager* mgr = U2FTokenManager::Get();
     267           0 :                            mgr->MaybeAbortTransaction(tid, rv);
     268           0 :                          });
     269             : }
     270             : 
     271             : void
     272           0 : U2FTokenManager::MaybeConfirmRegister(uint64_t aTransactionId,
     273             :                                       U2FRegisterResult& aResult)
     274             : {
     275           0 :   if (mTransactionId != aTransactionId) {
     276           0 :     return;
     277             :   }
     278             : 
     279           0 :   nsTArray<uint8_t> registration;
     280           0 :   aResult.ConsumeRegistration(registration);
     281             : 
     282           0 :   Unused << mTransactionParent->SendConfirmRegister(registration);
     283           0 :   ClearTransaction();
     284             : }
     285             : 
     286             : void
     287           0 : U2FTokenManager::Sign(WebAuthnTransactionParent* aTransactionParent,
     288             :                       const WebAuthnTransactionInfo& aTransactionInfo)
     289             : {
     290           0 :   MOZ_LOG(gU2FTokenManagerLog, LogLevel::Debug, ("U2FAuthSign"));
     291           0 :   MOZ_ASSERT(U2FPrefManager::Get());
     292             : 
     293           0 :   uint64_t tid = ++mTransactionId;
     294           0 :   mTransactionParent = aTransactionParent;
     295           0 :   mTokenManagerImpl = GetTokenManagerImpl();
     296             : 
     297           0 :   if (!mTokenManagerImpl) {
     298           0 :     AbortTransaction(NS_ERROR_DOM_NOT_ALLOWED_ERR);
     299           0 :     return;
     300             :   }
     301             : 
     302           0 :   if ((aTransactionInfo.RpIdHash().Length() != SHA256_LENGTH) ||
     303           0 :       (aTransactionInfo.ClientDataHash().Length() != SHA256_LENGTH)) {
     304           0 :     AbortTransaction(NS_ERROR_DOM_UNKNOWN_ERR);
     305           0 :     return;
     306             :   }
     307             : 
     308           0 :   mSignPromise = mTokenManagerImpl->Sign(aTransactionInfo.Descriptors(),
     309             :                                          aTransactionInfo.RpIdHash(),
     310           0 :                                          aTransactionInfo.ClientDataHash());
     311             : 
     312             :   mSignPromise->Then(GetCurrentThreadSerialEventTarget(), __func__,
     313           0 :                      [tid](U2FSignResult&& aResult) {
     314           0 :                        U2FTokenManager* mgr = U2FTokenManager::Get();
     315           0 :                        mgr->MaybeConfirmSign(tid, aResult);
     316           0 :                      },
     317           0 :                      [tid](nsresult rv) {
     318           0 :                        MOZ_ASSERT(NS_FAILED(rv));
     319           0 :                        U2FTokenManager* mgr = U2FTokenManager::Get();
     320           0 :                        mgr->MaybeAbortTransaction(tid, rv);
     321           0 :                      });
     322             : }
     323             : 
     324             : void
     325           0 : U2FTokenManager::MaybeConfirmSign(uint64_t aTransactionId,
     326             :                                   U2FSignResult& aResult)
     327             : {
     328           0 :   if (mTransactionId != aTransactionId) {
     329           0 :     return;
     330             :   }
     331             : 
     332           0 :   nsTArray<uint8_t> keyHandle;
     333           0 :   aResult.ConsumeKeyHandle(keyHandle);
     334           0 :   nsTArray<uint8_t> signature;
     335           0 :   aResult.ConsumeSignature(signature);
     336             : 
     337           0 :   Unused << mTransactionParent->SendConfirmSign(keyHandle, signature);
     338           0 :   ClearTransaction();
     339             : }
     340             : 
     341             : void
     342           0 : U2FTokenManager::Cancel(WebAuthnTransactionParent* aParent)
     343             : {
     344           0 :   if (mTransactionParent == aParent) {
     345           0 :     mTokenManagerImpl->Cancel();
     346           0 :     ClearTransaction();
     347             :   }
     348           0 : }
     349             : 
     350             : }
     351             : }

Generated by: LCOV version 1.13