LCOV - code coverage report
Current view: top level - dom/u2f - U2F.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 4 533 0.8 %
Date: 2017-07-14 16:53:18 Functions: 2 72 2.8 %
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
       5             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       6             : 
       7             : #include "hasht.h"
       8             : #include "mozilla/dom/CallbackFunction.h"
       9             : #include "mozilla/dom/ContentChild.h"
      10             : #include "mozilla/dom/CryptoBuffer.h"
      11             : #include "mozilla/dom/NSSU2FTokenRemote.h"
      12             : #include "mozilla/dom/U2F.h"
      13             : #include "mozilla/Preferences.h"
      14             : #include "mozilla/ReentrantMonitor.h"
      15             : #include "mozilla/SizePrintfMacros.h"
      16             : #include "nsContentUtils.h"
      17             : #include "nsINSSU2FToken.h"
      18             : #include "nsNetCID.h"
      19             : #include "nsNSSComponent.h"
      20             : #include "nsThreadUtils.h"
      21             : #include "nsURLParsers.h"
      22             : #include "nsXPCOMCIDInternal.h"
      23             : #include "pk11pub.h"
      24             : 
      25             : using mozilla::dom::ContentChild;
      26             : 
      27             : namespace mozilla {
      28             : namespace dom {
      29             : 
      30             : #define PREF_U2F_SOFTTOKEN_ENABLED "security.webauth.u2f_enable_softtoken"
      31             : #define PREF_U2F_USBTOKEN_ENABLED  "security.webauth.u2f_enable_usbtoken"
      32             : 
      33           3 : NS_NAMED_LITERAL_CSTRING(kPoolName, "WebAuth_U2F-IO");
      34           3 : NS_NAMED_LITERAL_STRING(kFinishEnrollment, "navigator.id.finishEnrollment");
      35           3 : NS_NAMED_LITERAL_STRING(kGetAssertion, "navigator.id.getAssertion");
      36             : 
      37           0 : NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(U2F)
      38           0 :   NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
      39           0 :   NS_INTERFACE_MAP_ENTRY(nsISupports)
      40           0 : NS_INTERFACE_MAP_END
      41             : 
      42           0 : NS_IMPL_CYCLE_COLLECTING_ADDREF(U2F)
      43           0 : NS_IMPL_CYCLE_COLLECTING_RELEASE(U2F)
      44             : 
      45           0 : NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(U2F, mParent)
      46             : 
      47             : static mozilla::LazyLogModule gU2FLog("u2f");
      48             : 
      49             : static nsresult
      50           0 : AssembleClientData(const nsAString& aOrigin, const nsAString& aTyp,
      51             :                    const nsAString& aChallenge, CryptoBuffer& aClientData)
      52             : {
      53           0 :   MOZ_ASSERT(NS_IsMainThread());
      54           0 :   U2FClientData clientDataObject;
      55           0 :   clientDataObject.mTyp.Construct(aTyp); // "Typ" from the U2F specification
      56           0 :   clientDataObject.mChallenge.Construct(aChallenge);
      57           0 :   clientDataObject.mOrigin.Construct(aOrigin);
      58             : 
      59           0 :   nsAutoString json;
      60           0 :   if (NS_WARN_IF(!clientDataObject.ToJSON(json))) {
      61           0 :     return NS_ERROR_FAILURE;
      62             :   }
      63             : 
      64           0 :   if (NS_WARN_IF(!aClientData.Assign(NS_ConvertUTF16toUTF8(json)))) {
      65           0 :     return NS_ERROR_OUT_OF_MEMORY;
      66             :   }
      67             : 
      68           0 :   return NS_OK;
      69             : }
      70             : 
      71           0 : U2FStatus::U2FStatus()
      72             :   : mCount(0)
      73             :   , mIsStopped(false)
      74           0 :   , mReentrantMonitor("U2FStatus")
      75           0 : {}
      76             : 
      77           0 : U2FStatus::~U2FStatus()
      78           0 : {}
      79             : 
      80             : void
      81           0 : U2FStatus::WaitGroupAdd()
      82             : {
      83           0 :   ReentrantMonitorAutoEnter mon(mReentrantMonitor);
      84             : 
      85           0 :   mCount += 1;
      86           0 :   MOZ_LOG(gU2FLog, LogLevel::Debug,
      87             :           ("U2FStatus::WaitGroupAdd, now %d", mCount));
      88           0 : }
      89             : 
      90             : void
      91           0 : U2FStatus::WaitGroupDone()
      92             : {
      93           0 :   ReentrantMonitorAutoEnter mon(mReentrantMonitor);
      94             : 
      95           0 :   MOZ_ASSERT(mCount > 0);
      96           0 :   mCount -= 1;
      97           0 :   MOZ_LOG(gU2FLog, LogLevel::Debug,
      98             :           ("U2FStatus::WaitGroupDone, now %d", mCount));
      99           0 :   if (mCount == 0) {
     100           0 :     mReentrantMonitor.NotifyAll();
     101             :   }
     102           0 : }
     103             : 
     104             : void
     105           0 : U2FStatus::WaitGroupWait()
     106             : {
     107           0 :   ReentrantMonitorAutoEnter mon(mReentrantMonitor);
     108           0 :   MOZ_LOG(gU2FLog, LogLevel::Debug,
     109             :           ("U2FStatus::WaitGroupWait, now %d", mCount));
     110             : 
     111           0 :   while (mCount > 0) {
     112           0 :     mReentrantMonitor.Wait();
     113             :   }
     114             : 
     115           0 :   MOZ_ASSERT(mCount == 0);
     116           0 :   MOZ_LOG(gU2FLog, LogLevel::Debug,
     117             :           ("U2FStatus::Wait completed, now count=%d stopped=%d", mCount,
     118             :            mIsStopped));
     119           0 : }
     120             : 
     121             : void
     122           0 : U2FStatus::Stop(const ErrorCode aErrorCode)
     123             : {
     124           0 :   ReentrantMonitorAutoEnter mon(mReentrantMonitor);
     125           0 :   MOZ_ASSERT(!mIsStopped);
     126           0 :   mIsStopped = true;
     127           0 :   mErrorCode = aErrorCode;
     128             : 
     129             :   // TODO: Let WaitGroupWait exit early upon a Stop. Requires consideration of
     130             :   // threads calling IsStopped() followed by WaitGroupDone(). Right now, Stop
     131             :   // prompts work tasks to end early, but it could also prompt an immediate
     132             :   // "Go ahead" to the thread waiting at WaitGroupWait.
     133           0 : }
     134             : 
     135             : void
     136           0 : U2FStatus::Stop(const ErrorCode aErrorCode, const nsAString& aResponse)
     137             : {
     138           0 :   ReentrantMonitorAutoEnter mon(mReentrantMonitor);
     139           0 :   Stop(aErrorCode);
     140           0 :   mResponse = aResponse;
     141           0 : }
     142             : 
     143             : bool
     144           0 : U2FStatus::IsStopped()
     145             : {
     146           0 :   ReentrantMonitorAutoEnter mon(mReentrantMonitor);
     147           0 :   return mIsStopped;
     148             : }
     149             : 
     150             : ErrorCode
     151           0 : U2FStatus::GetErrorCode()
     152             : {
     153           0 :   ReentrantMonitorAutoEnter mon(mReentrantMonitor);
     154           0 :   MOZ_ASSERT(mIsStopped);
     155           0 :   return mErrorCode;
     156             : }
     157             : 
     158             : nsString
     159           0 : U2FStatus::GetResponse()
     160             : {
     161           0 :   ReentrantMonitorAutoEnter mon(mReentrantMonitor);
     162           0 :   MOZ_ASSERT(mIsStopped);
     163           0 :   return mResponse;
     164             : }
     165             : 
     166           0 : U2FTask::U2FTask(const nsAString& aOrigin,
     167             :                  const nsAString& aAppId,
     168             :                  const Authenticator& aAuthenticator,
     169           0 :                  nsISerialEventTarget* aEventTarget)
     170             :   : Runnable("dom::U2FTask")
     171             :   , mOrigin(aOrigin)
     172             :   , mAppId(aAppId)
     173             :   , mAuthenticator(aAuthenticator)
     174           0 :   , mEventTarget(aEventTarget)
     175           0 : {}
     176             : 
     177           0 : U2FTask::~U2FTask()
     178           0 : {}
     179             : 
     180             : RefPtr<U2FPromise>
     181           0 : U2FTask::Execute()
     182             : {
     183           0 :   RefPtr<U2FPromise> p = mPromise.Ensure(__func__);
     184             : 
     185           0 :   nsCOMPtr<nsIRunnable> r(this);
     186             : 
     187             :   // TODO: Use a thread pool here, but we have to solve the PContentChild issues
     188             :   // of being in a worker thread.
     189           0 :   mEventTarget->Dispatch(r.forget());
     190           0 :   return p;
     191             : }
     192             : 
     193           0 : U2FPrepTask::U2FPrepTask(const Authenticator& aAuthenticator,
     194           0 :                          nsISerialEventTarget* aEventTarget)
     195             :   : Runnable("dom::U2FPrepTask")
     196             :   , mAuthenticator(aAuthenticator)
     197           0 :   , mEventTarget(aEventTarget)
     198           0 : {}
     199             : 
     200           0 : U2FPrepTask::~U2FPrepTask()
     201           0 : {}
     202             : 
     203             : RefPtr<U2FPrepPromise>
     204           0 : U2FPrepTask::Execute()
     205             : {
     206           0 :   RefPtr<U2FPrepPromise> p = mPromise.Ensure(__func__);
     207             : 
     208           0 :   nsCOMPtr<nsIRunnable> r(this);
     209             : 
     210             :   // TODO: Use a thread pool here, but we have to solve the PContentChild issues
     211             :   // of being in a worker thread.
     212           0 :   mEventTarget->Dispatch(r.forget());
     213           0 :   return p;
     214             : }
     215             : 
     216           0 : U2FIsRegisteredTask::U2FIsRegisteredTask(const Authenticator& aAuthenticator,
     217             :                                          const LocalRegisteredKey& aRegisteredKey,
     218             :                                          const CryptoBuffer& aAppParam,
     219           0 :                                          nsISerialEventTarget* aEventTarget)
     220             :   : U2FPrepTask(aAuthenticator, aEventTarget)
     221             :   , mRegisteredKey(aRegisteredKey)
     222           0 :   , mAppParam(aAppParam)
     223           0 : {}
     224             : 
     225           0 : U2FIsRegisteredTask::~U2FIsRegisteredTask()
     226           0 : {}
     227             : 
     228             : NS_IMETHODIMP
     229           0 : U2FIsRegisteredTask::Run()
     230             : {
     231           0 :   bool isCompatible = false;
     232           0 :   nsresult rv = mAuthenticator->IsCompatibleVersion(mRegisteredKey.mVersion,
     233           0 :                                                     &isCompatible);
     234           0 :   if (NS_FAILED(rv)) {
     235           0 :     mPromise.Reject(ErrorCode::OTHER_ERROR, __func__);
     236           0 :     return NS_ERROR_FAILURE;
     237             :   }
     238             : 
     239           0 :   if (!isCompatible) {
     240           0 :     mPromise.Reject(ErrorCode::BAD_REQUEST, __func__);
     241           0 :     return NS_ERROR_FAILURE;
     242             :   }
     243             : 
     244             :   // Decode the key handle
     245           0 :   CryptoBuffer keyHandle;
     246           0 :   rv = keyHandle.FromJwkBase64(mRegisteredKey.mKeyHandle);
     247           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
     248           0 :     mPromise.Reject(ErrorCode::BAD_REQUEST, __func__);
     249           0 :     return NS_ERROR_FAILURE;
     250             :   }
     251             : 
     252             :   // We ignore mTransports, as it is intended to be used for sorting the
     253             :   // available devices by preference, but is not an exclusion factor.
     254             : 
     255           0 :   bool isRegistered = false;
     256           0 :   rv = mAuthenticator->IsRegistered(keyHandle.Elements(), keyHandle.Length(),
     257           0 :                                     mAppParam.Elements(), mAppParam.Length(),
     258           0 :                                     &isRegistered);
     259           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
     260           0 :     mPromise.Reject(ErrorCode::OTHER_ERROR, __func__);
     261           0 :     return NS_ERROR_FAILURE;
     262             :   }
     263             : 
     264           0 :   if (isRegistered) {
     265           0 :     mPromise.Reject(ErrorCode::DEVICE_INELIGIBLE, __func__);
     266           0 :     return NS_OK;
     267             :   }
     268             : 
     269           0 :   mPromise.Resolve(mAuthenticator, __func__);
     270           0 :   return NS_OK;
     271             : }
     272             : 
     273           0 : U2FRegisterTask::U2FRegisterTask(const nsAString& aOrigin,
     274             :                                  const nsAString& aAppId,
     275             :                                  const Authenticator& aAuthenticator,
     276             :                                  const CryptoBuffer& aAppParam,
     277             :                                  const CryptoBuffer& aChallengeParam,
     278             :                                  const LocalRegisterRequest& aRegisterEntry,
     279           0 :                                  nsISerialEventTarget* aEventTarget)
     280             :   : U2FTask(aOrigin, aAppId, aAuthenticator, aEventTarget)
     281             :   , mAppParam(aAppParam)
     282             :   , mChallengeParam(aChallengeParam)
     283           0 :   , mRegisterEntry(aRegisterEntry)
     284           0 : {}
     285             : 
     286           0 : U2FRegisterTask::~U2FRegisterTask()
     287           0 : {}
     288             : 
     289             : NS_IMETHODIMP
     290           0 : U2FRegisterTask::Run()
     291             : {
     292           0 :   bool isCompatible = false;
     293           0 :   nsresult rv = mAuthenticator->IsCompatibleVersion(mRegisterEntry.mVersion,
     294           0 :                                                     &isCompatible);
     295           0 :   if (NS_FAILED(rv)) {
     296           0 :     mPromise.Reject(ErrorCode::OTHER_ERROR, __func__);
     297           0 :     return NS_ERROR_FAILURE;
     298             :   }
     299             : 
     300           0 :   if (!isCompatible) {
     301           0 :     mPromise.Reject(ErrorCode::BAD_REQUEST, __func__);
     302           0 :     return NS_ERROR_FAILURE;
     303             :   }
     304             : 
     305             :   uint8_t* buffer;
     306             :   uint32_t bufferlen;
     307           0 :   rv = mAuthenticator->Register(mAppParam.Elements(),
     308           0 :                                 mAppParam.Length(),
     309             :                                 mChallengeParam.Elements(),
     310           0 :                                 mChallengeParam.Length(),
     311           0 :                                 &buffer, &bufferlen);
     312           0 :   if (NS_WARN_IF(NS_FAILED(rv)))  {
     313           0 :     mPromise.Reject(ErrorCode::OTHER_ERROR, __func__);
     314           0 :     return NS_ERROR_FAILURE;
     315             :   }
     316             : 
     317           0 :   MOZ_ASSERT(buffer);
     318           0 :   CryptoBuffer regData;
     319           0 :   if (NS_WARN_IF(!regData.Assign(buffer, bufferlen))) {
     320           0 :     free(buffer);
     321           0 :     mPromise.Reject(ErrorCode::OTHER_ERROR, __func__);
     322           0 :     return NS_ERROR_OUT_OF_MEMORY;
     323             :   }
     324           0 :   free(buffer);
     325             : 
     326             :   // Assemble a response object to return
     327           0 :   nsString clientDataBase64;
     328           0 :   nsString registrationDataBase64;
     329           0 :   nsresult rvClientData = mRegisterEntry.mClientData.ToJwkBase64(clientDataBase64);
     330           0 :   nsresult rvRegistrationData = regData.ToJwkBase64(registrationDataBase64);
     331             : 
     332           0 :   if (NS_WARN_IF(NS_FAILED(rvClientData)) ||
     333           0 :       NS_WARN_IF(NS_FAILED(rvRegistrationData))) {
     334           0 :     mPromise.Reject(ErrorCode::OTHER_ERROR, __func__);
     335           0 :     return NS_ERROR_FAILURE;
     336             :   }
     337             : 
     338           0 :   RegisterResponse response;
     339           0 :   response.mClientData.Construct(clientDataBase64);
     340           0 :   response.mRegistrationData.Construct(registrationDataBase64);
     341           0 :   response.mErrorCode.Construct(static_cast<uint32_t>(ErrorCode::OK));
     342             : 
     343           0 :   nsString responseStr;
     344           0 :   if (NS_WARN_IF(!response.ToJSON(responseStr))) {
     345           0 :     return NS_ERROR_FAILURE;
     346             :   }
     347           0 :   mPromise.Resolve(responseStr, __func__);
     348           0 :   return NS_OK;
     349             : }
     350             : 
     351           0 : U2FSignTask::U2FSignTask(const nsAString& aOrigin,
     352             :                          const nsAString& aAppId,
     353             :                          const nsAString& aVersion,
     354             :                          const Authenticator& aAuthenticator,
     355             :                          const CryptoBuffer& aAppParam,
     356             :                          const CryptoBuffer& aChallengeParam,
     357             :                          const CryptoBuffer& aClientData,
     358             :                          const CryptoBuffer& aKeyHandle,
     359           0 :                          nsISerialEventTarget* aEventTarget)
     360             :   : U2FTask(aOrigin, aAppId, aAuthenticator, aEventTarget)
     361             :   , mVersion(aVersion)
     362             :   , mAppParam(aAppParam)
     363             :   , mChallengeParam(aChallengeParam)
     364             :   , mClientData(aClientData)
     365           0 :   , mKeyHandle(aKeyHandle)
     366           0 : {}
     367             : 
     368           0 : U2FSignTask::~U2FSignTask()
     369           0 : {}
     370             : 
     371             : NS_IMETHODIMP
     372           0 : U2FSignTask::Run()
     373             : {
     374           0 :   bool isCompatible = false;
     375           0 :   nsresult rv = mAuthenticator->IsCompatibleVersion(mVersion, &isCompatible);
     376           0 :   if (NS_FAILED(rv)) {
     377           0 :     mPromise.Reject(ErrorCode::OTHER_ERROR, __func__);
     378           0 :     return NS_ERROR_FAILURE;
     379             :   }
     380             : 
     381           0 :   if (!isCompatible) {
     382           0 :     mPromise.Reject(ErrorCode::BAD_REQUEST, __func__);
     383           0 :     return NS_ERROR_FAILURE;
     384             :   }
     385             : 
     386           0 :   bool isRegistered = false;
     387           0 :   rv = mAuthenticator->IsRegistered(mKeyHandle.Elements(), mKeyHandle.Length(),
     388           0 :                                     mAppParam.Elements(), mAppParam.Length(),
     389           0 :                                     &isRegistered);
     390           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
     391           0 :     mPromise.Reject(ErrorCode::OTHER_ERROR, __func__);
     392           0 :     return NS_ERROR_FAILURE;
     393             :   }
     394             : 
     395           0 :   if (!isRegistered) {
     396           0 :     mPromise.Reject(ErrorCode::DEVICE_INELIGIBLE, __func__);
     397           0 :     return NS_OK;
     398             :   }
     399             : 
     400           0 :   CryptoBuffer signatureData;
     401             :   uint8_t* buffer;
     402             :   uint32_t bufferlen;
     403           0 :   rv = mAuthenticator->Sign(mAppParam.Elements(), mAppParam.Length(),
     404           0 :                             mChallengeParam.Elements(), mChallengeParam.Length(),
     405           0 :                             mKeyHandle.Elements(), mKeyHandle.Length(),
     406           0 :                             &buffer, &bufferlen);
     407           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
     408           0 :     mPromise.Reject(ErrorCode::OTHER_ERROR, __func__);
     409           0 :     return NS_ERROR_FAILURE;
     410             :   }
     411             : 
     412           0 :   MOZ_ASSERT(buffer);
     413           0 :   if (NS_WARN_IF(!signatureData.Assign(buffer, bufferlen))) {
     414           0 :     free(buffer);
     415           0 :     mPromise.Reject(ErrorCode::OTHER_ERROR, __func__);
     416           0 :     return NS_ERROR_OUT_OF_MEMORY;
     417             :   }
     418           0 :   free(buffer);
     419             : 
     420             :   // Assemble a response object to return
     421           0 :   nsString clientDataBase64;
     422           0 :   nsString signatureDataBase64;
     423           0 :   nsString keyHandleBase64;
     424           0 :   nsresult rvClientData = mClientData.ToJwkBase64(clientDataBase64);
     425           0 :   nsresult rvSignatureData = signatureData.ToJwkBase64(signatureDataBase64);
     426           0 :   nsresult rvKeyHandle = mKeyHandle.ToJwkBase64(keyHandleBase64);
     427           0 :   if (NS_WARN_IF(NS_FAILED(rvClientData)) ||
     428           0 :       NS_WARN_IF(NS_FAILED(rvSignatureData) ||
     429             :       NS_WARN_IF(NS_FAILED(rvKeyHandle)))) {
     430           0 :     mPromise.Reject(ErrorCode::OTHER_ERROR, __func__);
     431           0 :     return NS_ERROR_FAILURE;
     432             :   }
     433             : 
     434           0 :   SignResponse response;
     435           0 :   response.mKeyHandle.Construct(keyHandleBase64);
     436           0 :   response.mClientData.Construct(clientDataBase64);
     437           0 :   response.mSignatureData.Construct(signatureDataBase64);
     438           0 :   response.mErrorCode.Construct(static_cast<uint32_t>(ErrorCode::OK));
     439             : 
     440           0 :   nsString responseStr;
     441           0 :   if (NS_WARN_IF(!response.ToJSON(responseStr))) {
     442           0 :     return NS_ERROR_FAILURE;
     443             :   }
     444           0 :   mPromise.Resolve(responseStr, __func__);
     445           0 :   return NS_OK;
     446             : }
     447             : 
     448           0 : U2FRunnable::U2FRunnable(const nsAString& aOrigin, const nsAString& aAppId,
     449           0 :                          nsISerialEventTarget* aEventTarget)
     450             :   : Runnable("dom::U2FRunnable")
     451             :   , mOrigin(aOrigin)
     452             :   , mAppId(aAppId)
     453           0 :   , mEventTarget(aEventTarget)
     454           0 : {}
     455             : 
     456           0 : U2FRunnable::~U2FRunnable()
     457           0 : {}
     458             : 
     459             : // EvaluateAppIDAndRunTask determines whether the supplied FIDO AppID is valid for
     460             : // the current FacetID, e.g., the current origin.
     461             : // See https://fidoalliance.org/specs/fido-u2f-v1.0-nfc-bt-amendment-20150514/fido-appid-and-facets.html
     462             : // for a description of the algorithm.
     463             : ErrorCode
     464           0 : U2FRunnable::EvaluateAppID()
     465             : {
     466             :   nsCOMPtr<nsIURLParser> urlParser =
     467           0 :       do_GetService(NS_STDURLPARSER_CONTRACTID);
     468             : 
     469           0 :   MOZ_ASSERT(urlParser);
     470             : 
     471             :   uint32_t facetSchemePos;
     472             :   int32_t facetSchemeLen;
     473             :   uint32_t facetAuthPos;
     474             :   int32_t facetAuthLen;
     475             :   // Facet is the specification's way of referring to the web origin.
     476           0 :   nsAutoCString facetUrl = NS_ConvertUTF16toUTF8(mOrigin);
     477           0 :   nsresult rv = urlParser->ParseURL(facetUrl.get(), mOrigin.Length(),
     478             :                                     &facetSchemePos, &facetSchemeLen,
     479             :                                     &facetAuthPos, &facetAuthLen,
     480           0 :                                     nullptr, nullptr);      // ignore path
     481           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
     482           0 :     return ErrorCode::BAD_REQUEST;
     483             :   }
     484             : 
     485           0 :   nsAutoCString facetScheme(Substring(facetUrl, facetSchemePos, facetSchemeLen));
     486           0 :   nsAutoCString facetAuth(Substring(facetUrl, facetAuthPos, facetAuthLen));
     487             : 
     488             :   uint32_t appIdSchemePos;
     489             :   int32_t appIdSchemeLen;
     490             :   uint32_t appIdAuthPos;
     491             :   int32_t appIdAuthLen;
     492             :   // AppID is user-supplied. It's quite possible for this parse to fail.
     493           0 :   nsAutoCString appIdUrl = NS_ConvertUTF16toUTF8(mAppId);
     494           0 :   rv = urlParser->ParseURL(appIdUrl.get(), mAppId.Length(),
     495             :                            &appIdSchemePos, &appIdSchemeLen,
     496             :                            &appIdAuthPos, &appIdAuthLen,
     497           0 :                            nullptr, nullptr);      // ignore path
     498           0 :   if (NS_FAILED(rv)) {
     499           0 :     return ErrorCode::BAD_REQUEST;
     500             :   }
     501             : 
     502           0 :   nsAutoCString appIdScheme(Substring(appIdUrl, appIdSchemePos, appIdSchemeLen));
     503           0 :   nsAutoCString appIdAuth(Substring(appIdUrl, appIdAuthPos, appIdAuthLen));
     504             : 
     505             :   // If the facetId (origin) is not HTTPS, reject
     506           0 :   if (!facetScheme.LowerCaseEqualsLiteral("https")) {
     507           0 :     return ErrorCode::BAD_REQUEST;
     508             :   }
     509             : 
     510             :   // If the appId is empty or null, overwrite it with the facetId and accept
     511           0 :   if (mAppId.IsEmpty() || mAppId.EqualsLiteral("null")) {
     512           0 :     mAppId.Assign(mOrigin);
     513           0 :     return ErrorCode::OK;
     514             :   }
     515             : 
     516             :   // if the appId URL is not HTTPS, reject.
     517           0 :   if (!appIdScheme.LowerCaseEqualsLiteral("https")) {
     518           0 :     return ErrorCode::BAD_REQUEST;
     519             :   }
     520             : 
     521             :   // If the facetId and the appId auths match, accept
     522           0 :   if (facetAuth == appIdAuth) {
     523           0 :     return ErrorCode::OK;
     524             :   }
     525             : 
     526             :   // TODO(Bug 1244959) Implement the remaining algorithm.
     527           0 :   return ErrorCode::BAD_REQUEST;
     528             : }
     529             : 
     530           0 : U2FRegisterRunnable::U2FRegisterRunnable(const nsAString& aOrigin,
     531             :                                          const nsAString& aAppId,
     532             :                                          const Sequence<RegisterRequest>& aRegisterRequests,
     533             :                                          const Sequence<RegisteredKey>& aRegisteredKeys,
     534             :                                          const Sequence<Authenticator>& aAuthenticators,
     535             :                                          U2FRegisterCallback* aCallback,
     536           0 :                                          nsISerialEventTarget* aEventTarget)
     537             :   : U2FRunnable(aOrigin, aAppId, aEventTarget)
     538             :   , mAuthenticators(aAuthenticators)
     539             :   // U2FRegisterCallback does not support threadsafe refcounting, and must be
     540             :   // used and destroyed on main.
     541             :   , mCallback(new nsMainThreadPtrHolder<U2FRegisterCallback>(
     542           0 :       "U2FRegisterRunnable::mCallback", aCallback))
     543             : {
     544           0 :   MOZ_ASSERT(NS_IsMainThread());
     545             : 
     546             :   // The WebIDL dictionary types RegisterRequest and RegisteredKey cannot
     547             :   // be copied to this thread, so store them serialized.
     548           0 :   for (const RegisterRequest& req : aRegisterRequests) {
     549             :     // Check for required attributes
     550           0 :     if (!req.mChallenge.WasPassed() || !req.mVersion.WasPassed()) {
     551           0 :       continue;
     552             :     }
     553             : 
     554           0 :     LocalRegisterRequest localReq;
     555           0 :     localReq.mVersion = req.mVersion.Value();
     556           0 :     localReq.mChallenge = req.mChallenge.Value();
     557             : 
     558           0 :     nsresult rv = AssembleClientData(mOrigin, kFinishEnrollment,
     559           0 :                                      localReq.mChallenge, localReq.mClientData);
     560           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
     561           0 :       continue;
     562             :     }
     563             : 
     564           0 :     mRegisterRequests.AppendElement(localReq);
     565             :   }
     566             : 
     567           0 :   for (const RegisteredKey& key : aRegisteredKeys) {
     568             :     // Check for required attributes
     569           0 :     if (!key.mVersion.WasPassed() || !key.mKeyHandle.WasPassed()) {
     570           0 :       continue;
     571             :     }
     572             : 
     573           0 :     LocalRegisteredKey localKey;
     574           0 :     localKey.mVersion = key.mVersion.Value();
     575           0 :     localKey.mKeyHandle = key.mKeyHandle.Value();
     576           0 :     if (key.mAppId.WasPassed()) {
     577           0 :       localKey.mAppId.SetValue(key.mAppId.Value());
     578             :     }
     579             : 
     580           0 :     mRegisteredKeys.AppendElement(localKey);
     581             :   }
     582           0 : }
     583             : 
     584           0 : U2FRegisterRunnable::~U2FRegisterRunnable()
     585             : {
     586           0 :   nsNSSShutDownPreventionLock locker;
     587             : 
     588           0 :   if (isAlreadyShutDown()) {
     589           0 :     return;
     590             :   }
     591           0 :   shutdown(ShutdownCalledFrom::Object);
     592           0 : }
     593             : 
     594             : void
     595           0 : U2FRegisterRunnable::SetTimeout(const int32_t aTimeoutMillis)
     596             : {
     597           0 :   opt_mTimeoutSeconds.SetValue(aTimeoutMillis);
     598           0 : }
     599             : 
     600             : void
     601           0 : U2FRegisterRunnable::SendResponse(const RegisterResponse& aResponse)
     602             : {
     603           0 :   MOZ_ASSERT(NS_IsMainThread());
     604             : 
     605           0 :   ErrorResult rv;
     606           0 :   mCallback->Call(aResponse, rv);
     607           0 :   NS_WARNING_ASSERTION(!rv.Failed(), "callback failed");
     608             :   // Useful exceptions already got reported.
     609           0 :   rv.SuppressException();
     610           0 : }
     611             : 
     612             : NS_IMETHODIMP
     613           0 : U2FRegisterRunnable::Run()
     614             : {
     615           0 :   MOZ_ASSERT(!NS_IsMainThread());
     616             : 
     617           0 :   nsNSSShutDownPreventionLock locker;
     618           0 :   if (isAlreadyShutDown()) {
     619           0 :     return NS_ERROR_FAILURE;
     620             :   }
     621             : 
     622             :   // Create a Status object to keep track of when we're done
     623           0 :   RefPtr<U2FStatus> status = new U2FStatus();
     624             : 
     625             :   // Evaluate the AppID
     626           0 :   ErrorCode appIdResult = EvaluateAppID();
     627           0 :   if (appIdResult != ErrorCode::OK) {
     628           0 :     status->Stop(appIdResult);
     629             :   }
     630             : 
     631             :   // Produce the AppParam from the current AppID
     632           0 :   nsCString cAppId = NS_ConvertUTF16toUTF8(mAppId);
     633           0 :   CryptoBuffer appParam;
     634           0 :   if (!appParam.SetLength(SHA256_LENGTH, fallible)) {
     635           0 :     return NS_ERROR_OUT_OF_MEMORY;
     636             :   }
     637             : 
     638             :   // Note: This could use nsICryptoHash to avoid having to interact with NSS
     639             :   // directly.
     640             :   SECStatus srv;
     641           0 :   srv = PK11_HashBuf(SEC_OID_SHA256, appParam.Elements(),
     642           0 :                      reinterpret_cast<const uint8_t*>(cAppId.BeginReading()),
     643           0 :                      cAppId.Length());
     644           0 :   if (srv != SECSuccess) {
     645           0 :     return NS_ERROR_FAILURE;
     646             :   }
     647             : 
     648             :   // First, we must determine if any of the RegisteredKeys are already
     649             :   // registered, e.g., in the whitelist.
     650           0 :   for (LocalRegisteredKey key : mRegisteredKeys) {
     651           0 :     nsTArray<RefPtr<U2FPrepPromise>> prepPromiseList;
     652           0 :     for (const Authenticator& token : mAuthenticators) {
     653             :       RefPtr<U2FIsRegisteredTask> compTask =
     654           0 :         new U2FIsRegisteredTask(token, key, appParam, mEventTarget);
     655           0 :       prepPromiseList.AppendElement(compTask->Execute());
     656             :     }
     657             : 
     658             :     // Treat each call to Promise::All as a work unit, as it completes together
     659           0 :     status->WaitGroupAdd();
     660             : 
     661           0 :     U2FPrepPromise::All(mEventTarget, prepPromiseList)
     662             :     ->Then(mEventTarget, __func__,
     663           0 :       [&status] (const nsTArray<Authenticator>& aTokens) {
     664           0 :         MOZ_LOG(gU2FLog, LogLevel::Debug,
     665             :                 ("ALL: None of the RegisteredKeys were recognized. n=%" PRIuSIZE,
     666             :                  aTokens.Length()));
     667             : 
     668           0 :         status->WaitGroupDone();
     669           0 :       },
     670           0 :       [&status] (ErrorCode aErrorCode) {
     671           0 :         status->Stop(aErrorCode);
     672           0 :         status->WaitGroupDone();
     673           0 :     });
     674             :   }
     675             : 
     676             :   // Wait for all the IsRegistered tasks to complete
     677           0 :   status->WaitGroupWait();
     678             : 
     679             :   // Check to see whether we're supposed to stop, because one of the keys was
     680             :   // recognized.
     681           0 :   if (status->IsStopped()) {
     682           0 :     status->WaitGroupAdd();
     683           0 :     mEventTarget->Dispatch(NS_NewRunnableFunction(
     684             :       "dom::U2FRegisterRunnable::Run",
     685           0 :       [&status, this] () {
     686           0 :         RegisterResponse response;
     687             :         response.mErrorCode.Construct(
     688           0 :             static_cast<uint32_t>(status->GetErrorCode()));
     689           0 :         SendResponse(response);
     690           0 :         status->WaitGroupDone();
     691           0 :       }));
     692             : 
     693             :     // Don't exit until the main thread runnable completes
     694           0 :     status->WaitGroupWait();
     695           0 :     return NS_OK;
     696             :   }
     697             : 
     698             :   // Now proceed to actually register a new key.
     699           0 :   for (LocalRegisterRequest req : mRegisterRequests) {
     700             :     // Hash the ClientData into the ChallengeParam
     701           0 :     CryptoBuffer challengeParam;
     702           0 :     if (!challengeParam.SetLength(SHA256_LENGTH, fallible)) {
     703           0 :       continue;
     704             :     }
     705             : 
     706           0 :     srv = PK11_HashBuf(SEC_OID_SHA256, challengeParam.Elements(),
     707           0 :                        req.mClientData.Elements(), req.mClientData.Length());
     708           0 :     if (srv != SECSuccess) {
     709           0 :       continue;
     710             :     }
     711             : 
     712           0 :     for (const Authenticator& token : mAuthenticators) {
     713             :       RefPtr<U2FRegisterTask> registerTask = new U2FRegisterTask(mOrigin, mAppId,
     714             :                                                                  token, appParam,
     715             :                                                                  challengeParam,
     716             :                                                                  req,
     717           0 :                                                                  mEventTarget);
     718           0 :       status->WaitGroupAdd();
     719             : 
     720           0 :       registerTask->Execute()->Then(mEventTarget, __func__,
     721           0 :         [&status] (nsString aResponse) {
     722           0 :           if (!status->IsStopped()) {
     723           0 :             status->Stop(ErrorCode::OK, aResponse);
     724             :           }
     725           0 :           status->WaitGroupDone();
     726           0 :         },
     727           0 :         [&status] (ErrorCode aErrorCode) {
     728             :           // Ignore the failing error code, as we only want the first success.
     729             :           // U2F devices don't provide much for error codes anyway, so if
     730             :           // they all fail we'll return DEVICE_INELIGIBLE.
     731           0 :           status->WaitGroupDone();
     732           0 :      });
     733             :     }
     734             :   }
     735             : 
     736             :   // Wait until the first key is successfuly generated
     737           0 :   status->WaitGroupWait();
     738             : 
     739             :   // If none of the tasks completed, then nothing could satisfy.
     740           0 :   if (!status->IsStopped()) {
     741           0 :     status->Stop(ErrorCode::BAD_REQUEST);
     742             :   }
     743             : 
     744             :   // Transmit back to the JS engine from the Main Thread
     745           0 :   status->WaitGroupAdd();
     746           0 :   mEventTarget->Dispatch(NS_NewRunnableFunction(
     747             :     "dom::U2FRegisterRunnable::Run",
     748           0 :     [&status, this] () {
     749           0 :       RegisterResponse response;
     750           0 :       if (status->GetErrorCode() == ErrorCode::OK) {
     751           0 :         response.Init(status->GetResponse());
     752             :       } else {
     753             :         response.mErrorCode.Construct(
     754           0 :             static_cast<uint32_t>(status->GetErrorCode()));
     755             :       }
     756           0 :       SendResponse(response);
     757           0 :       status->WaitGroupDone();
     758           0 :     }));
     759             : 
     760             :   // TODO: Add timeouts, Bug 1301793
     761           0 :   status->WaitGroupWait();
     762           0 :   return NS_OK;
     763             : }
     764             : 
     765           0 : U2FSignRunnable::U2FSignRunnable(const nsAString& aOrigin,
     766             :                                  const nsAString& aAppId,
     767             :                                  const nsAString& aChallenge,
     768             :                                  const Sequence<RegisteredKey>& aRegisteredKeys,
     769             :                                  const Sequence<Authenticator>& aAuthenticators,
     770             :                                  U2FSignCallback* aCallback,
     771           0 :                                  nsISerialEventTarget* aEventTarget)
     772             :   : U2FRunnable(aOrigin, aAppId, aEventTarget)
     773             :   , mAuthenticators(aAuthenticators)
     774             :   // U2FSignCallback does not support threadsafe refcounting, and must be used
     775             :   // and destroyed on main.
     776             :   , mCallback(new nsMainThreadPtrHolder<U2FSignCallback>(
     777           0 :       "U2FSignRunnable::mCallback", aCallback))
     778             : {
     779           0 :   MOZ_ASSERT(NS_IsMainThread());
     780             : 
     781             :   // Convert WebIDL objects to generic structs to pass between threads
     782           0 :   for (const RegisteredKey& key : aRegisteredKeys) {
     783             :     // Check for required attributes
     784           0 :     if (!key.mVersion.WasPassed() || !key.mKeyHandle.WasPassed()) {
     785           0 :       continue;
     786             :     }
     787             : 
     788           0 :     LocalRegisteredKey localKey;
     789           0 :     localKey.mVersion = key.mVersion.Value();
     790           0 :     localKey.mKeyHandle = key.mKeyHandle.Value();
     791           0 :     if (key.mAppId.WasPassed()) {
     792           0 :       localKey.mAppId.SetValue(key.mAppId.Value());
     793             :     }
     794             : 
     795           0 :     mRegisteredKeys.AppendElement(localKey);
     796             :   }
     797             : 
     798             :   // Assemble a clientData object
     799           0 :   nsresult rv = AssembleClientData(aOrigin, kGetAssertion, aChallenge,
     800           0 :                                    mClientData);
     801           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
     802           0 :     MOZ_LOG(gU2FLog, LogLevel::Warning,
     803             :             ("Failed to AssembleClientData for the U2FSignRunnable."));
     804           0 :     return;
     805             :   }
     806             : }
     807             : 
     808           0 : U2FSignRunnable::~U2FSignRunnable()
     809             : {
     810           0 :   nsNSSShutDownPreventionLock locker;
     811             : 
     812           0 :   if (isAlreadyShutDown()) {
     813           0 :     return;
     814             :   }
     815           0 :   shutdown(ShutdownCalledFrom::Object);
     816           0 : }
     817             : 
     818             : void
     819           0 : U2FSignRunnable::SetTimeout(const int32_t aTimeoutMillis)
     820             : {
     821           0 :   opt_mTimeoutSeconds.SetValue(aTimeoutMillis);
     822           0 : }
     823             : 
     824             : void
     825           0 : U2FSignRunnable::SendResponse(const SignResponse& aResponse)
     826             : {
     827           0 :   MOZ_ASSERT(NS_IsMainThread());
     828             : 
     829           0 :   ErrorResult rv;
     830           0 :   mCallback->Call(aResponse, rv);
     831           0 :   NS_WARNING_ASSERTION(!rv.Failed(), "callback failed");
     832             :   // Useful exceptions already got reported.
     833           0 :   rv.SuppressException();
     834           0 : }
     835             : 
     836             : NS_IMETHODIMP
     837           0 : U2FSignRunnable::Run()
     838             : {
     839           0 :   MOZ_ASSERT(!NS_IsMainThread());
     840             : 
     841           0 :   nsNSSShutDownPreventionLock locker;
     842           0 :   if (isAlreadyShutDown()) {
     843           0 :     return NS_ERROR_FAILURE;
     844             :   }
     845             : 
     846             :   // Create a Status object to keep track of when we're done
     847           0 :   RefPtr<U2FStatus> status = new U2FStatus();
     848             : 
     849             :   // Evaluate the AppID
     850           0 :   ErrorCode appIdResult = EvaluateAppID();
     851           0 :   if (appIdResult != ErrorCode::OK) {
     852           0 :     status->Stop(appIdResult);
     853             :   }
     854             : 
     855             :   // Hash the AppID and the ClientData into the AppParam and ChallengeParam
     856           0 :   nsCString cAppId = NS_ConvertUTF16toUTF8(mAppId);
     857           0 :   CryptoBuffer appParam;
     858           0 :   CryptoBuffer challengeParam;
     859           0 :   if (!appParam.SetLength(SHA256_LENGTH, fallible) ||
     860           0 :       !challengeParam.SetLength(SHA256_LENGTH, fallible)) {
     861           0 :     return NS_ERROR_OUT_OF_MEMORY;
     862             :   }
     863             : 
     864             :   SECStatus srv;
     865           0 :   srv = PK11_HashBuf(SEC_OID_SHA256, appParam.Elements(),
     866           0 :                      reinterpret_cast<const uint8_t*>(cAppId.BeginReading()),
     867           0 :                      cAppId.Length());
     868           0 :   if (srv != SECSuccess) {
     869           0 :     return NS_ERROR_FAILURE;
     870             :   }
     871             : 
     872           0 :   srv = PK11_HashBuf(SEC_OID_SHA256, challengeParam.Elements(),
     873           0 :                      mClientData.Elements(), mClientData.Length());
     874           0 :   if (srv != SECSuccess) {
     875           0 :     return NS_ERROR_FAILURE;
     876             :   }
     877             : 
     878             :   // Search the signing requests for one a token can fulfill
     879           0 :   for (LocalRegisteredKey key : mRegisteredKeys) {
     880             :     // Do not permit an individual RegisteredKey to assert a different AppID
     881           0 :     if (!key.mAppId.IsNull() && mAppId != key.mAppId.Value()) {
     882           0 :       continue;
     883             :     }
     884             : 
     885             :     // Decode the key handle
     886           0 :     CryptoBuffer keyHandle;
     887           0 :     nsresult rv = keyHandle.FromJwkBase64(key.mKeyHandle);
     888           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
     889           0 :       continue;
     890             :     }
     891             : 
     892             :     // We ignore mTransports, as it is intended to be used for sorting the
     893             :     // available devices by preference, but is not an exclusion factor.
     894             : 
     895           0 :     for (const Authenticator& token : mAuthenticators) {
     896             :       RefPtr<U2FSignTask> signTask = new U2FSignTask(mOrigin, mAppId,
     897             :                                                      key.mVersion, token,
     898             :                                                      appParam, challengeParam,
     899             :                                                      mClientData, keyHandle,
     900           0 :                                                      mEventTarget);
     901           0 :       status->WaitGroupAdd();
     902             : 
     903           0 :       signTask->Execute()->Then(mEventTarget, __func__,
     904           0 :         [&status] (nsString aResponse) {
     905           0 :           if (!status->IsStopped()) {
     906           0 :             status->Stop(ErrorCode::OK, aResponse);
     907             :           }
     908           0 :           status->WaitGroupDone();
     909           0 :         },
     910           0 :         [&status] (ErrorCode aErrorCode) {
     911             :           // Ignore the failing error code, as we only want the first success.
     912             :           // U2F devices don't provide much for error codes anyway, so if
     913             :           // they all fail we'll return DEVICE_INELIGIBLE.
     914           0 :           status->WaitGroupDone();
     915           0 :       });
     916             :     }
     917             :   }
     918             : 
     919             :   // Wait for the authenticators to finish
     920           0 :   status->WaitGroupWait();
     921             : 
     922             :   // If none of the tasks completed, then nothing could satisfy.
     923           0 :   if (!status->IsStopped()) {
     924           0 :     status->Stop(ErrorCode::DEVICE_INELIGIBLE);
     925             :   }
     926             : 
     927             :   // Transmit back to the JS engine from the Main Thread
     928           0 :   status->WaitGroupAdd();
     929           0 :   mEventTarget->Dispatch(NS_NewRunnableFunction(
     930             :     "dom::U2FSignRunnable::Run",
     931           0 :     [&status, this] () {
     932           0 :       SignResponse response;
     933           0 :       if (status->GetErrorCode() == ErrorCode::OK) {
     934           0 :         response.Init(status->GetResponse());
     935             :       } else {
     936             :         response.mErrorCode.Construct(
     937           0 :           static_cast<uint32_t>(status->GetErrorCode()));
     938             :       }
     939           0 :       SendResponse(response);
     940           0 :       status->WaitGroupDone();
     941           0 :     }));
     942             : 
     943             :   // TODO: Add timeouts, Bug 1301793
     944           0 :   status->WaitGroupWait();
     945           0 :   return NS_OK;
     946             : }
     947             : 
     948           0 : U2F::U2F()
     949           0 :   : mInitialized(false)
     950           0 : {}
     951             : 
     952           0 : U2F::~U2F()
     953             : {
     954           0 :   nsNSSShutDownPreventionLock locker;
     955             : 
     956           0 :   if (isAlreadyShutDown()) {
     957           0 :     return;
     958             :   }
     959           0 :   shutdown(ShutdownCalledFrom::Object);
     960           0 : }
     961             : 
     962             : /* virtual */ JSObject*
     963           0 : U2F::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
     964             : {
     965           0 :   return U2FBinding::Wrap(aCx, this, aGivenProto);
     966             : }
     967             : 
     968             : void
     969           0 : U2F::Init(nsPIDOMWindowInner* aParent, ErrorResult& aRv)
     970             : {
     971           0 :   MOZ_ASSERT(!mInitialized);
     972           0 :   MOZ_ASSERT(!mParent);
     973           0 :   mParent = do_QueryInterface(aParent);
     974           0 :   MOZ_ASSERT(mParent);
     975             : 
     976           0 :   nsCOMPtr<nsIDocument> doc = mParent->GetDoc();
     977           0 :   MOZ_ASSERT(doc);
     978             : 
     979           0 :   nsIPrincipal* principal = doc->NodePrincipal();
     980           0 :   aRv = nsContentUtils::GetUTFOrigin(principal, mOrigin);
     981           0 :   if (NS_WARN_IF(aRv.Failed())) {
     982           0 :     return;
     983             :   }
     984             : 
     985           0 :   if (NS_WARN_IF(mOrigin.IsEmpty())) {
     986           0 :     aRv.Throw(NS_ERROR_FAILURE);
     987           0 :     return;
     988             :   }
     989             : 
     990           0 :   if (!EnsureNSSInitializedChromeOrContent()) {
     991           0 :     MOZ_LOG(gU2FLog, LogLevel::Debug,
     992             :             ("Failed to get NSS context for U2F"));
     993           0 :     aRv.Throw(NS_ERROR_FAILURE);
     994           0 :     return;
     995             :   }
     996             : 
     997             :   // This only functions in e10s mode
     998           0 :   if (XRE_IsParentProcess()) {
     999           0 :     MOZ_LOG(gU2FLog, LogLevel::Debug,
    1000             :             ("Is non-e10s Process, U2F not available"));
    1001           0 :     aRv.Throw(NS_ERROR_FAILURE);
    1002           0 :     return;
    1003             :   }
    1004             : 
    1005             :   // Monolithically insert compatible nsIU2FToken objects into mAuthenticators.
    1006             :   // In future functionality expansions, this is where we could add a dynamic
    1007             :   // add/remove interface.
    1008           0 :   if (Preferences::GetBool(PREF_U2F_SOFTTOKEN_ENABLED)) {
    1009           0 :     if (!mAuthenticators.AppendElement(new NSSU2FTokenRemote(),
    1010             :                                        mozilla::fallible)) {
    1011           0 :       aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
    1012           0 :       return;
    1013             :     }
    1014             :   }
    1015             : 
    1016           0 :   mEventTarget = doc->EventTargetFor(TaskCategory::Other);
    1017             : 
    1018           0 :   mInitialized = true;
    1019             : }
    1020             : 
    1021             : void
    1022           0 : U2F::Register(const nsAString& aAppId,
    1023             :               const Sequence<RegisterRequest>& aRegisterRequests,
    1024             :               const Sequence<RegisteredKey>& aRegisteredKeys,
    1025             :               U2FRegisterCallback& aCallback,
    1026             :               const Optional<Nullable<int32_t>>& opt_aTimeoutSeconds,
    1027             :               ErrorResult& aRv)
    1028             : {
    1029           0 :   MOZ_ASSERT(NS_IsMainThread());
    1030             : 
    1031           0 :   if (!mInitialized) {
    1032           0 :     aRv.Throw(NS_ERROR_NOT_AVAILABLE);
    1033           0 :     return;
    1034             :   }
    1035             : 
    1036           0 :   RefPtr<SharedThreadPool> pool = SharedThreadPool::Get(kPoolName);
    1037             :   RefPtr<U2FRegisterRunnable> task = new U2FRegisterRunnable(mOrigin, aAppId,
    1038             :                                                              aRegisterRequests,
    1039             :                                                              aRegisteredKeys,
    1040             :                                                              mAuthenticators,
    1041             :                                                              &aCallback,
    1042           0 :                                                              mEventTarget);
    1043           0 :   pool->Dispatch(task.forget(), NS_DISPATCH_NORMAL);
    1044             : }
    1045             : 
    1046             : void
    1047           0 : U2F::Sign(const nsAString& aAppId,
    1048             :           const nsAString& aChallenge,
    1049             :           const Sequence<RegisteredKey>& aRegisteredKeys,
    1050             :           U2FSignCallback& aCallback,
    1051             :           const Optional<Nullable<int32_t>>& opt_aTimeoutSeconds,
    1052             :           ErrorResult& aRv)
    1053             : {
    1054           0 :   MOZ_ASSERT(NS_IsMainThread());
    1055             : 
    1056           0 :   if (!mInitialized) {
    1057           0 :     aRv.Throw(NS_ERROR_NOT_AVAILABLE);
    1058           0 :     return;
    1059             :   }
    1060             : 
    1061           0 :   RefPtr<SharedThreadPool> pool = SharedThreadPool::Get(kPoolName);
    1062             :   RefPtr<U2FSignRunnable> task = new U2FSignRunnable(mOrigin, aAppId, aChallenge,
    1063             :                                                      aRegisteredKeys,
    1064             :                                                      mAuthenticators, &aCallback,
    1065           0 :                                                      mEventTarget);
    1066           0 :   pool->Dispatch(task.forget(), NS_DISPATCH_NORMAL);
    1067             : }
    1068             : 
    1069             : } // namespace dom
    1070           9 : } // namespace mozilla

Generated by: LCOV version 1.13