diff options
Diffstat (limited to 'dom/u2f/U2F.h')
-rw-r--r-- | dom/u2f/U2F.h | 327 |
1 files changed, 327 insertions, 0 deletions
diff --git a/dom/u2f/U2F.h b/dom/u2f/U2F.h new file mode 100644 index 000000000..9035ae2df --- /dev/null +++ b/dom/u2f/U2F.h @@ -0,0 +1,327 @@ +/* -*- 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_U2F_h +#define mozilla_dom_U2F_h + +#include "js/TypeDecls.h" +#include "mozilla/Attributes.h" +#include "mozilla/dom/BindingDeclarations.h" +#include "mozilla/dom/Nullable.h" +#include "mozilla/dom/U2FBinding.h" +#include "mozilla/ErrorResult.h" +#include "mozilla/MozPromise.h" +#include "mozilla/ReentrantMonitor.h" +#include "mozilla/SharedThreadPool.h" +#include "nsCycleCollectionParticipant.h" +#include "nsIU2FToken.h" +#include "nsNSSShutDown.h" +#include "nsPIDOMWindow.h" +#include "nsProxyRelease.h" +#include "nsWrapperCache.h" + +#include "USBToken.h" + +namespace mozilla { +namespace dom { + +class U2FRegisterCallback; +class U2FSignCallback; + +// Defined in U2FBinding.h by the U2F.webidl; their use requires a JSContext. +struct RegisterRequest; +struct RegisteredKey; + +// These structs are analogs to the WebIDL versions, but can be used on worker +// threads which lack a JSContext. +struct LocalRegisterRequest +{ + nsString mChallenge; + nsString mVersion; + CryptoBuffer mClientData; +}; + +struct LocalRegisteredKey +{ + nsString mKeyHandle; + nsString mVersion; + Nullable<nsString> mAppId; + // TODO: Support transport preferences + // Nullable<nsTArray<Transport>> mTransports; +}; + +// These enumerations are defined in the FIDO U2F Javascript API under the +// interface "ErrorCode" as constant integers, and thus in the U2F.webidl file. +// Any changes to these must occur in both locations. +enum class ErrorCode { + OK = 0, + OTHER_ERROR = 1, + BAD_REQUEST = 2, + CONFIGURATION_UNSUPPORTED = 3, + DEVICE_INELIGIBLE = 4, + TIMEOUT = 5 +}; + +typedef nsCOMPtr<nsIU2FToken> Authenticator; +typedef MozPromise<nsString, ErrorCode, false> U2FPromise; +typedef MozPromise<Authenticator, ErrorCode, false> U2FPrepPromise; + +// U2FPrepTasks return lists of Authenticators that are OK to +// proceed; they're useful for culling incompatible Authenticators. +// Currently, only IsRegistered is supported. +class U2FPrepTask : public Runnable +{ +public: + explicit U2FPrepTask(const Authenticator& aAuthenticator); + + RefPtr<U2FPrepPromise> Execute(); + +protected: + virtual ~U2FPrepTask(); + + Authenticator mAuthenticator; + MozPromiseHolder<U2FPrepPromise> mPromise; +}; + +// Determine whether the provided Authenticator already knows +// of the provided Registered Key. +class U2FIsRegisteredTask final : public U2FPrepTask +{ +public: + U2FIsRegisteredTask(const Authenticator& aAuthenticator, + const LocalRegisteredKey& aRegisteredKey); + + NS_DECL_NSIRUNNABLE +private: + ~U2FIsRegisteredTask(); + + LocalRegisteredKey mRegisteredKey; +}; + +class U2FTask : public Runnable +{ +public: + U2FTask(const nsAString& aOrigin, + const nsAString& aAppId, + const Authenticator& aAuthenticator); + + RefPtr<U2FPromise> Execute(); + + nsString mOrigin; + nsString mAppId; + Authenticator mAuthenticator; + +protected: + virtual ~U2FTask(); + + MozPromiseHolder<U2FPromise> mPromise; +}; + +// Use the provided Authenticator to Register a new scoped credential +// for the provided application. +class U2FRegisterTask final : public U2FTask +{ +public: + U2FRegisterTask(const nsAString& aOrigin, + const nsAString& aAppId, + const Authenticator& aAuthenticator, + const CryptoBuffer& aAppParam, + const CryptoBuffer& aChallengeParam, + const LocalRegisterRequest& aRegisterEntry); + + NS_DECL_NSIRUNNABLE +private: + ~U2FRegisterTask(); + + CryptoBuffer mAppParam; + CryptoBuffer mChallengeParam; + LocalRegisterRequest mRegisterEntry; +}; + +// Generate an assertion using the provided Authenticator for the given origin +// and provided application to attest to ownership of a valid scoped credential. +class U2FSignTask final : public U2FTask +{ +public: + U2FSignTask(const nsAString& aOrigin, + const nsAString& aAppId, + const nsAString& aVersion, + const Authenticator& aAuthenticator, + const CryptoBuffer& aAppParam, + const CryptoBuffer& aChallengeParam, + const CryptoBuffer& aClientData, + const CryptoBuffer& aKeyHandle); + + NS_DECL_NSIRUNNABLE +private: + ~U2FSignTask(); + + nsString mVersion; + CryptoBuffer mAppParam; + CryptoBuffer mChallengeParam; + CryptoBuffer mClientData; + CryptoBuffer mKeyHandle; +}; + +// Mediate inter-thread communication for multiple authenticators being queried +// in concert. Operates as a cyclic buffer with a stop-work method. +class U2FStatus +{ +public: + U2FStatus(); + + void WaitGroupAdd(); + void WaitGroupDone(); + void WaitGroupWait(); + + void Stop(const ErrorCode aErrorCode); + void Stop(const ErrorCode aErrorCode, const nsAString& aResponse); + bool IsStopped(); + ErrorCode GetErrorCode(); + nsString GetResponse(); + + NS_INLINE_DECL_THREADSAFE_REFCOUNTING(U2FStatus) + +private: + ~U2FStatus(); + + uint16_t mCount; + bool mIsStopped; + nsString mResponse; + MOZ_INIT_OUTSIDE_CTOR ErrorCode mErrorCode; + ReentrantMonitor mReentrantMonitor; +}; + +// U2FRunnables run to completion, performing a single U2F operation such as +// registering, or signing. +class U2FRunnable : public Runnable + , public nsNSSShutDownObject +{ +public: + U2FRunnable(const nsAString& aOrigin, const nsAString& aAppId); + + // No NSS resources to release. + virtual + void virtualDestroyNSSReference() override {}; + +protected: + virtual ~U2FRunnable(); + ErrorCode EvaluateAppID(); + + nsString mOrigin; + nsString mAppId; +}; + +// This U2FRunnable completes a single application-requested U2F Register +// operation. +class U2FRegisterRunnable : public U2FRunnable +{ +public: + U2FRegisterRunnable(const nsAString& aOrigin, + const nsAString& aAppId, + const Sequence<RegisterRequest>& aRegisterRequests, + const Sequence<RegisteredKey>& aRegisteredKeys, + const Sequence<Authenticator>& aAuthenticators, + U2FRegisterCallback* aCallback); + + void SendResponse(const RegisterResponse& aResponse); + void SetTimeout(const int32_t aTimeoutMillis); + + NS_DECL_NSIRUNNABLE + +private: + ~U2FRegisterRunnable(); + + nsTArray<LocalRegisterRequest> mRegisterRequests; + nsTArray<LocalRegisteredKey> mRegisteredKeys; + nsTArray<Authenticator> mAuthenticators; + nsMainThreadPtrHandle<U2FRegisterCallback> mCallback; + Nullable<int32_t> opt_mTimeoutSeconds; +}; + +// This U2FRunnable completes a single application-requested U2F Sign operation. +class U2FSignRunnable : public U2FRunnable +{ +public: + U2FSignRunnable(const nsAString& aOrigin, + const nsAString& aAppId, + const nsAString& aChallenge, + const Sequence<RegisteredKey>& aRegisteredKeys, + const Sequence<Authenticator>& aAuthenticators, + U2FSignCallback* aCallback); + + void SendResponse(const SignResponse& aResponse); + void SetTimeout(const int32_t aTimeoutMillis); + + NS_DECL_NSIRUNNABLE + +private: + ~U2FSignRunnable(); + + nsString mChallenge; + CryptoBuffer mClientData; + nsTArray<LocalRegisteredKey> mRegisteredKeys; + nsTArray<Authenticator> mAuthenticators; + nsMainThreadPtrHandle<U2FSignCallback> mCallback; + Nullable<int32_t> opt_mTimeoutSeconds; +}; + +// The U2F Class is used by the JS engine to initiate U2F operations. +class U2F final : public nsISupports + , public nsWrapperCache + , public nsNSSShutDownObject +{ +public: + NS_DECL_CYCLE_COLLECTING_ISUPPORTS + NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(U2F) + + U2F(); + + nsPIDOMWindowInner* + GetParentObject() const + { + return mParent; + } + + void + Init(nsPIDOMWindowInner* aParent, ErrorResult& aRv); + + virtual JSObject* + WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override; + + void + Register(const nsAString& aAppId, + const Sequence<RegisterRequest>& aRegisterRequests, + const Sequence<RegisteredKey>& aRegisteredKeys, + U2FRegisterCallback& aCallback, + const Optional<Nullable<int32_t>>& opt_aTimeoutSeconds, + ErrorResult& aRv); + + void + Sign(const nsAString& aAppId, + const nsAString& aChallenge, + const Sequence<RegisteredKey>& aRegisteredKeys, + U2FSignCallback& aCallback, + const Optional<Nullable<int32_t>>& opt_aTimeoutSeconds, + ErrorResult& aRv); + + // No NSS resources to release. + virtual + void virtualDestroyNSSReference() override {}; + +private: + nsCOMPtr<nsPIDOMWindowInner> mParent; + nsString mOrigin; + Sequence<Authenticator> mAuthenticators; + bool mInitialized; + + ~U2F(); +}; + +} // namespace dom +} // namespace mozilla + +#endif // mozilla_dom_U2F_h |