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 : #ifndef mozilla_dom_U2F_h
8 : #define mozilla_dom_U2F_h
9 :
10 : #include "js/TypeDecls.h"
11 : #include "mozilla/Attributes.h"
12 : #include "mozilla/dom/BindingDeclarations.h"
13 : #include "mozilla/dom/CryptoBuffer.h"
14 : #include "mozilla/dom/Nullable.h"
15 : #include "mozilla/dom/U2FBinding.h"
16 : #include "mozilla/ErrorResult.h"
17 : #include "mozilla/MozPromise.h"
18 : #include "mozilla/ReentrantMonitor.h"
19 : #include "mozilla/SharedThreadPool.h"
20 : #include "nsCycleCollectionParticipant.h"
21 : #include "nsIU2FToken.h"
22 : #include "nsNSSShutDown.h"
23 : #include "nsPIDOMWindow.h"
24 : #include "nsProxyRelease.h"
25 : #include "nsWrapperCache.h"
26 :
27 : #include "U2FAuthenticator.h"
28 :
29 : class nsISerialEventTarget;
30 :
31 : namespace mozilla {
32 : namespace dom {
33 :
34 : class U2FRegisterCallback;
35 : class U2FSignCallback;
36 :
37 : // Defined in U2FBinding.h by the U2F.webidl; their use requires a JSContext.
38 : struct RegisterRequest;
39 : struct RegisteredKey;
40 :
41 : // These structs are analogs to the WebIDL versions, but can be used on worker
42 : // threads which lack a JSContext.
43 0 : struct LocalRegisterRequest
44 : {
45 : nsString mChallenge;
46 : nsString mVersion;
47 : CryptoBuffer mClientData;
48 : };
49 :
50 0 : struct LocalRegisteredKey
51 : {
52 : nsString mKeyHandle;
53 : nsString mVersion;
54 : Nullable<nsString> mAppId;
55 : // TODO: Support transport preferences
56 : // Nullable<nsTArray<Transport>> mTransports;
57 : };
58 :
59 : typedef MozPromise<nsString, ErrorCode, false> U2FPromise;
60 : typedef MozPromise<Authenticator, ErrorCode, false> U2FPrepPromise;
61 :
62 : // U2FPrepTasks return lists of Authenticators that are OK to
63 : // proceed; they're useful for culling incompatible Authenticators.
64 : // Currently, only IsRegistered is supported.
65 : class U2FPrepTask : public Runnable
66 : {
67 : public:
68 : explicit U2FPrepTask(const Authenticator& aAuthenticator,
69 : nsISerialEventTarget* aEventTarget);
70 :
71 : RefPtr<U2FPrepPromise> Execute();
72 :
73 : protected:
74 : virtual ~U2FPrepTask();
75 :
76 : Authenticator mAuthenticator;
77 : MozPromiseHolder<U2FPrepPromise> mPromise;
78 : const nsCOMPtr<nsISerialEventTarget> mEventTarget;
79 : };
80 :
81 : // Determine whether the provided Authenticator already knows
82 : // of the provided Registered Key.
83 : class U2FIsRegisteredTask final : public U2FPrepTask
84 : {
85 : public:
86 : U2FIsRegisteredTask(const Authenticator& aAuthenticator,
87 : const LocalRegisteredKey& aRegisteredKey,
88 : const CryptoBuffer& aAppParam,
89 : nsISerialEventTarget* aEventTarget);
90 :
91 : NS_DECL_NSIRUNNABLE
92 : private:
93 : ~U2FIsRegisteredTask();
94 :
95 : LocalRegisteredKey mRegisteredKey;
96 : CryptoBuffer mAppParam;
97 : };
98 :
99 : class U2FTask : public Runnable
100 : {
101 : public:
102 : U2FTask(const nsAString& aOrigin,
103 : const nsAString& aAppId,
104 : const Authenticator& aAuthenticator,
105 : nsISerialEventTarget* aEventTarget);
106 :
107 : RefPtr<U2FPromise> Execute();
108 :
109 : nsString mOrigin;
110 : nsString mAppId;
111 : Authenticator mAuthenticator;
112 : const nsCOMPtr<nsISerialEventTarget> mEventTarget;
113 :
114 : protected:
115 : virtual ~U2FTask();
116 :
117 : MozPromiseHolder<U2FPromise> mPromise;
118 : };
119 :
120 : // Use the provided Authenticator to Register a new scoped credential
121 : // for the provided application.
122 : class U2FRegisterTask final : public U2FTask
123 : {
124 : public:
125 : U2FRegisterTask(const nsAString& aOrigin,
126 : const nsAString& aAppId,
127 : const Authenticator& aAuthenticator,
128 : const CryptoBuffer& aAppParam,
129 : const CryptoBuffer& aChallengeParam,
130 : const LocalRegisterRequest& aRegisterEntry,
131 : nsISerialEventTarget* aEventTarget);
132 :
133 : NS_DECL_NSIRUNNABLE
134 : private:
135 : ~U2FRegisterTask();
136 :
137 : CryptoBuffer mAppParam;
138 : CryptoBuffer mChallengeParam;
139 : LocalRegisterRequest mRegisterEntry;
140 : };
141 :
142 : // Generate an assertion using the provided Authenticator for the given origin
143 : // and provided application to attest to ownership of a valid scoped credential.
144 : class U2FSignTask final : public U2FTask
145 : {
146 : public:
147 : U2FSignTask(const nsAString& aOrigin,
148 : const nsAString& aAppId,
149 : const nsAString& aVersion,
150 : const Authenticator& aAuthenticator,
151 : const CryptoBuffer& aAppParam,
152 : const CryptoBuffer& aChallengeParam,
153 : const CryptoBuffer& aClientData,
154 : const CryptoBuffer& aKeyHandle,
155 : nsISerialEventTarget* aEventTarget);
156 :
157 : NS_DECL_NSIRUNNABLE
158 : private:
159 : ~U2FSignTask();
160 :
161 : nsString mVersion;
162 : CryptoBuffer mAppParam;
163 : CryptoBuffer mChallengeParam;
164 : CryptoBuffer mClientData;
165 : CryptoBuffer mKeyHandle;
166 : };
167 :
168 : // Mediate inter-thread communication for multiple authenticators being queried
169 : // in concert. Operates as a cyclic buffer with a stop-work method.
170 : class U2FStatus
171 : {
172 : public:
173 : U2FStatus();
174 : U2FStatus(const U2FStatus&) = delete;
175 :
176 : void WaitGroupAdd();
177 : void WaitGroupDone();
178 : void WaitGroupWait();
179 :
180 : void Stop(const ErrorCode aErrorCode);
181 : void Stop(const ErrorCode aErrorCode, const nsAString& aResponse);
182 : bool IsStopped();
183 : ErrorCode GetErrorCode();
184 : nsString GetResponse();
185 :
186 0 : NS_INLINE_DECL_THREADSAFE_REFCOUNTING(U2FStatus)
187 :
188 : private:
189 : ~U2FStatus();
190 :
191 : uint16_t mCount;
192 : bool mIsStopped;
193 : nsString mResponse;
194 : MOZ_INIT_OUTSIDE_CTOR ErrorCode mErrorCode;
195 : ReentrantMonitor mReentrantMonitor;
196 : };
197 :
198 : // U2FRunnables run to completion, performing a single U2F operation such as
199 : // registering, or signing.
200 : class U2FRunnable : public Runnable
201 : , public nsNSSShutDownObject
202 : {
203 : public:
204 : U2FRunnable(const nsAString& aOrigin, const nsAString& aAppId,
205 : nsISerialEventTarget* aEventTarget);
206 :
207 : // No NSS resources to release.
208 : virtual
209 0 : void virtualDestroyNSSReference() override {};
210 :
211 : protected:
212 : virtual ~U2FRunnable();
213 : ErrorCode EvaluateAppID();
214 :
215 : nsString mOrigin;
216 : nsString mAppId;
217 : const nsCOMPtr<nsISerialEventTarget> mEventTarget;
218 : };
219 :
220 : // This U2FRunnable completes a single application-requested U2F Register
221 : // operation.
222 : class U2FRegisterRunnable : public U2FRunnable
223 : {
224 : public:
225 : U2FRegisterRunnable(const nsAString& aOrigin,
226 : const nsAString& aAppId,
227 : const Sequence<RegisterRequest>& aRegisterRequests,
228 : const Sequence<RegisteredKey>& aRegisteredKeys,
229 : const Sequence<Authenticator>& aAuthenticators,
230 : U2FRegisterCallback* aCallback,
231 : nsISerialEventTarget* aEventTarget);
232 :
233 : void SendResponse(const RegisterResponse& aResponse);
234 : void SetTimeout(const int32_t aTimeoutMillis);
235 :
236 : NS_DECL_NSIRUNNABLE
237 :
238 : private:
239 : ~U2FRegisterRunnable();
240 :
241 : nsTArray<LocalRegisterRequest> mRegisterRequests;
242 : nsTArray<LocalRegisteredKey> mRegisteredKeys;
243 : nsTArray<Authenticator> mAuthenticators;
244 : nsMainThreadPtrHandle<U2FRegisterCallback> mCallback;
245 : Nullable<int32_t> opt_mTimeoutSeconds;
246 : };
247 :
248 : // This U2FRunnable completes a single application-requested U2F Sign operation.
249 : class U2FSignRunnable : public U2FRunnable
250 : {
251 : public:
252 : U2FSignRunnable(const nsAString& aOrigin,
253 : const nsAString& aAppId,
254 : const nsAString& aChallenge,
255 : const Sequence<RegisteredKey>& aRegisteredKeys,
256 : const Sequence<Authenticator>& aAuthenticators,
257 : U2FSignCallback* aCallback,
258 : nsISerialEventTarget* aEventTarget);
259 :
260 : void SendResponse(const SignResponse& aResponse);
261 : void SetTimeout(const int32_t aTimeoutMillis);
262 :
263 : NS_DECL_NSIRUNNABLE
264 :
265 : private:
266 : ~U2FSignRunnable();
267 :
268 : nsString mChallenge;
269 : CryptoBuffer mClientData;
270 : nsTArray<LocalRegisteredKey> mRegisteredKeys;
271 : nsTArray<Authenticator> mAuthenticators;
272 : nsMainThreadPtrHandle<U2FSignCallback> mCallback;
273 : Nullable<int32_t> opt_mTimeoutSeconds;
274 : };
275 :
276 : // The U2F Class is used by the JS engine to initiate U2F operations.
277 : class U2F final : public nsISupports
278 : , public nsWrapperCache
279 : , public nsNSSShutDownObject
280 : {
281 : public:
282 : NS_DECL_CYCLE_COLLECTING_ISUPPORTS
283 1 : NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(U2F)
284 :
285 : U2F();
286 :
287 : nsPIDOMWindowInner*
288 0 : GetParentObject() const
289 : {
290 0 : return mParent;
291 : }
292 :
293 : void
294 : Init(nsPIDOMWindowInner* aParent, ErrorResult& aRv);
295 :
296 : virtual JSObject*
297 : WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
298 :
299 : void
300 : Register(const nsAString& aAppId,
301 : const Sequence<RegisterRequest>& aRegisterRequests,
302 : const Sequence<RegisteredKey>& aRegisteredKeys,
303 : U2FRegisterCallback& aCallback,
304 : const Optional<Nullable<int32_t>>& opt_aTimeoutSeconds,
305 : ErrorResult& aRv);
306 :
307 : void
308 : Sign(const nsAString& aAppId,
309 : const nsAString& aChallenge,
310 : const Sequence<RegisteredKey>& aRegisteredKeys,
311 : U2FSignCallback& aCallback,
312 : const Optional<Nullable<int32_t>>& opt_aTimeoutSeconds,
313 : ErrorResult& aRv);
314 :
315 : // No NSS resources to release.
316 : virtual
317 0 : void virtualDestroyNSSReference() override {};
318 :
319 : private:
320 : nsCOMPtr<nsPIDOMWindowInner> mParent;
321 : nsString mOrigin;
322 : Sequence<Authenticator> mAuthenticators;
323 : bool mInitialized;
324 : nsCOMPtr<nsISerialEventTarget> mEventTarget;
325 :
326 : ~U2F();
327 : };
328 :
329 : } // namespace dom
330 : } // namespace mozilla
331 :
332 : #endif // mozilla_dom_U2F_h
|