Bug 1856663 - Add more chunks for Android mochitest-plain. r=jmaher,taskgraph-reviewe...
[gecko.git] / dom / webauthn / U2FTokenManager.cpp
blob1937b9ffe63ddba4cba92b42b346e5c4ff86edf6
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
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 #include "json/json.h"
7 #include "mozilla/dom/U2FTokenManager.h"
8 #include "mozilla/dom/U2FTokenTransport.h"
9 #include "mozilla/dom/PWebAuthnTransactionParent.h"
10 #include "mozilla/MozPromise.h"
11 #include "mozilla/ipc/BackgroundParent.h"
12 #include "mozilla/ClearOnShutdown.h"
13 #include "mozilla/Services.h"
14 #include "mozilla/Unused.h"
15 #include "nsEscape.h"
16 #include "nsIObserver.h"
17 #include "nsIObserverService.h"
18 #include "nsIThread.h"
19 #include "nsTextFormatter.h"
20 #include "mozilla/Telemetry.h"
21 #include "WebAuthnEnumStrings.h"
23 #include "mozilla/dom/AndroidWebAuthnTokenManager.h"
25 namespace mozilla::dom {
27 /***********************************************************************
28 * Statics
29 **********************************************************************/
31 namespace {
32 static mozilla::LazyLogModule gU2FTokenManagerLog("u2fkeymanager");
33 StaticAutoPtr<U2FTokenManager> gU2FTokenManager;
34 static nsIThread* gBackgroundThread;
35 } // namespace
37 /***********************************************************************
38 * U2FManager Implementation
39 **********************************************************************/
41 U2FTokenManager::U2FTokenManager()
42 : mTransactionParent(nullptr), mLastTransactionId(0) {
43 MOZ_ASSERT(XRE_IsParentProcess());
44 // Create on the main thread to make sure ClearOnShutdown() works.
45 MOZ_ASSERT(NS_IsMainThread());
48 // static
49 void U2FTokenManager::Initialize() {
50 if (!XRE_IsParentProcess()) {
51 return;
53 MOZ_ASSERT(NS_IsMainThread());
54 MOZ_ASSERT(!gU2FTokenManager);
55 gU2FTokenManager = new U2FTokenManager();
56 ClearOnShutdown(&gU2FTokenManager);
59 // static
60 U2FTokenManager* U2FTokenManager::Get() {
61 MOZ_ASSERT(XRE_IsParentProcess());
62 // We should only be accessing this on the background thread
63 MOZ_ASSERT(!NS_IsMainThread());
64 return gU2FTokenManager;
67 void U2FTokenManager::AbortTransaction(const uint64_t& aTransactionId,
68 const nsresult& aError) {
69 Unused << mTransactionParent->SendAbort(aTransactionId, aError);
70 ClearTransaction();
73 void U2FTokenManager::AbortOngoingTransaction() {
74 if (mLastTransactionId > 0 && mTransactionParent) {
75 // Send an abort to any other ongoing transaction
76 Unused << mTransactionParent->SendAbort(mLastTransactionId,
77 NS_ERROR_DOM_ABORT_ERR);
79 ClearTransaction();
82 void U2FTokenManager::MaybeClearTransaction(
83 PWebAuthnTransactionParent* aParent) {
84 // Only clear if we've been requested to do so by our current transaction
85 // parent.
86 if (mTransactionParent == aParent) {
87 ClearTransaction();
91 void U2FTokenManager::ClearTransaction() {
92 mTransactionParent = nullptr;
94 // Drop managers at the end of all transactions
95 if (mTokenManagerImpl) {
96 mTokenManagerImpl->Drop();
97 mTokenManagerImpl = nullptr;
100 // Forget promises, if necessary.
101 mRegisterPromise.DisconnectIfExists();
102 mSignPromise.DisconnectIfExists();
104 // Clear transaction id.
105 mLastTransactionId = 0;
108 RefPtr<U2FTokenTransport> U2FTokenManager::GetTokenManagerImpl() {
109 mozilla::ipc::AssertIsOnBackgroundThread();
111 if (mTokenManagerImpl) {
112 return mTokenManagerImpl;
115 if (!gBackgroundThread) {
116 gBackgroundThread = NS_GetCurrentThread();
117 MOZ_ASSERT(gBackgroundThread, "This should never be null!");
120 return AndroidWebAuthnTokenManager::GetInstance();
123 void U2FTokenManager::Register(
124 PWebAuthnTransactionParent* aTransactionParent,
125 const uint64_t& aTransactionId,
126 const WebAuthnMakeCredentialInfo& aTransactionInfo) {
127 MOZ_LOG(gU2FTokenManagerLog, LogLevel::Debug, ("U2FAuthRegister"));
129 AbortOngoingTransaction();
130 mTransactionParent = aTransactionParent;
131 mTokenManagerImpl = GetTokenManagerImpl();
133 if (!mTokenManagerImpl) {
134 AbortTransaction(aTransactionId, NS_ERROR_DOM_NOT_ALLOWED_ERR);
135 return;
138 mLastTransactionId = aTransactionId;
140 mozilla::ipc::AssertIsOnBackgroundThread();
141 MOZ_ASSERT(mLastTransactionId > 0);
143 uint64_t tid = mLastTransactionId;
145 mTokenManagerImpl
146 ->Register(aTransactionInfo, /* aForceNoneAttestation */ true)
147 ->Then(
148 GetCurrentSerialEventTarget(), __func__,
149 [tid](WebAuthnMakeCredentialResult&& aResult) {
150 Telemetry::ScalarAdd(Telemetry::ScalarID::SECURITY_WEBAUTHN_USED,
151 u"U2FRegisterFinish"_ns, 1);
152 U2FTokenManager* mgr = U2FTokenManager::Get();
153 mgr->MaybeConfirmRegister(tid, aResult);
155 [tid](nsresult rv) {
156 MOZ_ASSERT(NS_FAILED(rv));
157 U2FTokenManager* mgr = U2FTokenManager::Get();
158 Telemetry::ScalarAdd(Telemetry::ScalarID::SECURITY_WEBAUTHN_USED,
159 u"U2FRegisterAbort"_ns, 1);
160 mgr->MaybeAbortRegister(tid, rv);
162 ->Track(mRegisterPromise);
165 void U2FTokenManager::MaybeConfirmRegister(
166 const uint64_t& aTransactionId,
167 const WebAuthnMakeCredentialResult& aResult) {
168 MOZ_ASSERT(mLastTransactionId == aTransactionId);
169 mRegisterPromise.Complete();
171 Unused << mTransactionParent->SendConfirmRegister(aTransactionId, aResult);
172 ClearTransaction();
175 void U2FTokenManager::MaybeAbortRegister(const uint64_t& aTransactionId,
176 const nsresult& aError) {
177 MOZ_ASSERT(mLastTransactionId == aTransactionId);
178 mRegisterPromise.Complete();
179 AbortTransaction(aTransactionId, aError);
182 void U2FTokenManager::Sign(PWebAuthnTransactionParent* aTransactionParent,
183 const uint64_t& aTransactionId,
184 const WebAuthnGetAssertionInfo& aTransactionInfo) {
185 MOZ_LOG(gU2FTokenManagerLog, LogLevel::Debug, ("U2FAuthSign"));
187 AbortOngoingTransaction();
188 mTransactionParent = aTransactionParent;
189 mTokenManagerImpl = GetTokenManagerImpl();
191 if (!mTokenManagerImpl) {
192 AbortTransaction(aTransactionId, NS_ERROR_DOM_NOT_ALLOWED_ERR);
193 return;
196 mLastTransactionId = aTransactionId;
198 mozilla::ipc::AssertIsOnBackgroundThread();
199 MOZ_ASSERT(mLastTransactionId > 0);
200 uint64_t tid = mLastTransactionId;
202 mTokenManagerImpl->Sign(aTransactionInfo)
203 ->Then(
204 GetCurrentSerialEventTarget(), __func__,
205 [tid](nsTArray<WebAuthnGetAssertionResultWrapper>&& aResult) {
206 U2FTokenManager* mgr = U2FTokenManager::Get();
207 Telemetry::ScalarAdd(Telemetry::ScalarID::SECURITY_WEBAUTHN_USED,
208 u"U2FSignFinish"_ns, 1);
209 if (aResult.Length() == 1) {
210 WebAuthnGetAssertionResult result = aResult[0].assertion;
211 mgr->MaybeConfirmSign(tid, result);
214 [tid](nsresult rv) {
215 MOZ_ASSERT(NS_FAILED(rv));
216 U2FTokenManager* mgr = U2FTokenManager::Get();
217 Telemetry::ScalarAdd(Telemetry::ScalarID::SECURITY_WEBAUTHN_USED,
218 u"U2FSignAbort"_ns, 1);
219 mgr->MaybeAbortSign(tid, rv);
221 ->Track(mSignPromise);
224 void U2FTokenManager::MaybeConfirmSign(
225 const uint64_t& aTransactionId, const WebAuthnGetAssertionResult& aResult) {
226 MOZ_ASSERT(mLastTransactionId == aTransactionId);
227 mSignPromise.Complete();
229 Unused << mTransactionParent->SendConfirmSign(aTransactionId, aResult);
230 ClearTransaction();
233 void U2FTokenManager::MaybeAbortSign(const uint64_t& aTransactionId,
234 const nsresult& aError) {
235 MOZ_ASSERT(mLastTransactionId == aTransactionId);
236 mSignPromise.Complete();
237 AbortTransaction(aTransactionId, aError);
240 void U2FTokenManager::Cancel(PWebAuthnTransactionParent* aParent,
241 const Tainted<uint64_t>& aTransactionId) {
242 // The last transaction ID also suffers from the issue described in Bug
243 // 1696159. A content process could cancel another content processes
244 // transaction by guessing the last transaction ID.
245 if (mTransactionParent != aParent ||
246 !MOZ_IS_VALID(aTransactionId, mLastTransactionId == aTransactionId)) {
247 return;
250 mTokenManagerImpl->Cancel();
251 ClearTransaction();
254 } // namespace mozilla::dom