1 // Copyright 2019 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #ifndef CONTENT_BROWSER_WEBAUTH_AUTHENTICATOR_COMMON_H_
6 #define CONTENT_BROWSER_WEBAUTH_AUTHENTICATOR_COMMON_H_
7 
8 #include <stdint.h>
9 
10 #include <memory>
11 #include <string>
12 #include <utility>
13 #include <vector>
14 
15 #include "base/containers/flat_set.h"
16 #include "base/containers/span.h"
17 #include "base/macros.h"
18 #include "base/optional.h"
19 #include "base/timer/timer.h"
20 #include "content/common/content_export.h"
21 #include "content/public/browser/authenticator_request_client_delegate.h"
22 #include "content/public/browser/web_contents_observer.h"
23 #include "device/fido/authenticator_get_assertion_response.h"
24 #include "device/fido/authenticator_make_credential_response.h"
25 #include "device/fido/authenticator_selection_criteria.h"
26 #include "device/fido/client_data.h"
27 #include "device/fido/ctap_get_assertion_request.h"
28 #include "device/fido/ctap_make_credential_request.h"
29 #include "device/fido/fido_constants.h"
30 #include "device/fido/fido_transport_protocol.h"
31 #include "device/fido/make_credential_request_handler.h"
32 #include "services/data_decoder/public/cpp/data_decoder.h"
33 #include "third_party/blink/public/mojom/webauthn/authenticator.mojom.h"
34 #include "url/origin.h"
35 
36 namespace base {
37 class OneShotTimer;
38 }
39 
40 namespace device {
41 
42 class FidoRequestHandlerBase;
43 class FidoDiscoveryFactory;
44 
45 enum class FidoReturnCode : uint8_t;
46 
47 enum class GetAssertionStatus;
48 enum class MakeCredentialStatus;
49 
50 }  // namespace device
51 
52 namespace url {
53 class Origin;
54 }
55 
56 namespace content {
57 
58 class BrowserContext;
59 class RenderFrameHost;
60 class WebAuthRequestSecurityChecker;
61 
62 namespace client_data {
63 // These enumerate the possible values for the `type` member of
64 // CollectedClientData. See
65 // https://w3c.github.io/webauthn/#dom-collectedclientdata-type
66 CONTENT_EXPORT extern const char kCreateType[];
67 CONTENT_EXPORT extern const char kGetType[];
68 }  // namespace client_data
69 
70 enum class RequestExtension;
71 
72 // Common code for any WebAuthn Authenticator interfaces.
73 class CONTENT_EXPORT AuthenticatorCommon {
74  public:
75   explicit AuthenticatorCommon(RenderFrameHost* render_frame_host);
76   virtual ~AuthenticatorCommon();
77 
78   // This is not-quite an implementation of blink::mojom::Authenticator. The
79   // first two functions take the caller's origin explicitly. This allows the
80   // caller origin to be overridden if needed.
81   void MakeCredential(
82       url::Origin caller_origin,
83       blink::mojom::PublicKeyCredentialCreationOptionsPtr options,
84       blink::mojom::Authenticator::MakeCredentialCallback callback);
85   void GetAssertion(url::Origin caller_origin,
86                     blink::mojom::PublicKeyCredentialRequestOptionsPtr options,
87                     blink::mojom::Authenticator::GetAssertionCallback callback);
88   void IsUserVerifyingPlatformAuthenticatorAvailable(
89       blink::mojom::Authenticator::
90           IsUserVerifyingPlatformAuthenticatorAvailableCallback callback);
91   void Cancel();
92 
93   void Cleanup();
94 
95   void DisableUI();
96 
97  protected:
98   virtual std::unique_ptr<AuthenticatorRequestClientDelegate>
99   CreateRequestDelegate();
100 
101   std::unique_ptr<AuthenticatorRequestClientDelegate> request_delegate_;
102 
103  private:
104   friend class AuthenticatorImplTest;
105 
106   // Enumerates whether or not to check that the WebContents has focus.
107   enum class Focus {
108     kDoCheck,
109     kDontCheck,
110   };
111 
112   // Replaces the current |request_| with a |MakeCredentialRequestHandler|,
113   // effectively restarting the request.
114   void StartMakeCredentialRequest(bool allow_skipping_pin_touch);
115 
116   // Replaces the current |request_| with a |GetAssertionRequestHandler|,
117   // effectively restarting the request.
118   void StartGetAssertionRequest(bool allow_skipping_pin_touch);
119 
120   bool IsFocused() const;
121 
122   // Callback to handle the large blob being compressed before attempting to
123   // start a request.
124   void OnLargeBlobCompressed(
125       data_decoder::DataDecoder::ResultOrError<mojo_base::BigBuffer> result);
126 
127   // Callback to handle the large blob being uncompressed before completing a
128   // request.
129   void OnLargeBlobUncompressed(
130       device::AuthenticatorGetAssertionResponse response,
131       data_decoder::DataDecoder::ResultOrError<mojo_base::BigBuffer> result);
132 
133   // Callback to handle the async response from a U2fDevice.
134   void OnRegisterResponse(
135       device::MakeCredentialStatus status_code,
136       base::Optional<device::AuthenticatorMakeCredentialResponse> response_data,
137       const device::FidoAuthenticator* authenticator);
138 
139   // Callback to complete the registration process once a decision about
140   // whether or not to return attestation data has been made.
141   void OnRegisterResponseAttestationDecided(
142       device::AuthenticatorMakeCredentialResponse response_data,
143       bool is_transport_used_internal,
144       bool attestation_permitted);
145 
146   // Callback to handle the async response from a U2fDevice.
147   void OnSignResponse(
148       device::GetAssertionStatus status_code,
149       base::Optional<std::vector<device::AuthenticatorGetAssertionResponse>>
150           response_data,
151       const device::FidoAuthenticator* authenticator);
152 
153   // Runs when timer expires and cancels all issued requests to a U2fDevice.
154   void OnTimeout();
155   // Cancels the currently pending request (if any) with the supplied status.
156   void CancelWithStatus(blink::mojom::AuthenticatorStatus status);
157   // Runs when the user cancels WebAuthN request via UI dialog.
158   void OnCancelFromUI();
159 
160   // Called when a GetAssertion has completed, either because an allow_list was
161   // used and so an answer is returned directly, or because the user selected an
162   // account from the options.
163   void OnAccountSelected(device::AuthenticatorGetAssertionResponse response);
164 
165   // Signals to the request delegate that the request has failed for |reason|.
166   // The request delegate decides whether to present the user with a visual
167   // error before the request is finally resolved with |status|.
168   void SignalFailureToRequestDelegate(
169       const device::FidoAuthenticator* authenticator,
170       AuthenticatorRequestClientDelegate::InterestingFailureReason reason,
171       blink::mojom::AuthenticatorStatus status);
172 
173   void InvokeCallbackAndCleanup(
174       blink::mojom::Authenticator::MakeCredentialCallback callback,
175       blink::mojom::AuthenticatorStatus status,
176       blink::mojom::MakeCredentialAuthenticatorResponsePtr response = nullptr,
177       Focus focus_check = Focus::kDontCheck);
178   void InvokeCallbackAndCleanup(
179       blink::mojom::Authenticator::GetAssertionCallback callback,
180       blink::mojom::AuthenticatorStatus status,
181       blink::mojom::GetAssertionAuthenticatorResponsePtr response = nullptr);
182 
183   BrowserContext* browser_context() const;
184 
185   // Returns the FidoDiscoveryFactory for the current request. This may be a
186   // real instance, or one injected by the Virtual Authenticator environment, or
187   // a unit testing fake. InitDiscoveryFactory() must be called before this
188   // accessor. It gets reset at the end of each request by Cleanup().
189   device::FidoDiscoveryFactory* discovery_factory();
190   void InitDiscoveryFactory();
191 
192   RenderFrameHost* const render_frame_host_;
193   std::unique_ptr<device::FidoRequestHandlerBase> request_;
194   std::unique_ptr<device::FidoDiscoveryFactory> discovery_factory_;
195   device::FidoDiscoveryFactory* discovery_factory_testing_override_ = nullptr;
196   blink::mojom::Authenticator::MakeCredentialCallback
197       make_credential_response_callback_;
198   blink::mojom::Authenticator::GetAssertionCallback
199       get_assertion_response_callback_;
200   std::string client_data_json_;
201   // empty_allow_list_ is true iff a GetAssertion is currently pending and the
202   // request did not list any credential IDs in the allow list.
203   bool empty_allow_list_ = false;
204   bool disable_ui_ = false;
205   url::Origin caller_origin_;
206   std::string relying_party_id_;
207   scoped_refptr<WebAuthRequestSecurityChecker> security_checker_;
208   std::unique_ptr<base::OneShotTimer> timer_ =
209       std::make_unique<base::OneShotTimer>();
210   base::Optional<std::string> app_id_;
211   base::Optional<device::CtapMakeCredentialRequest>
212       ctap_make_credential_request_;
213   base::Optional<device::MakeCredentialRequestHandler::Options>
214       make_credential_options_;
215   base::Optional<device::CtapGetAssertionRequest> ctap_get_assertion_request_;
216   base::Optional<device::CtapGetAssertionOptions> ctap_get_assertion_options_;
217   // awaiting_attestation_response_ is true if the embedder has been queried
218   // about an attestsation decision and the response is still pending.
219   bool awaiting_attestation_response_ = false;
220   blink::mojom::AuthenticatorStatus error_awaiting_user_acknowledgement_ =
221       blink::mojom::AuthenticatorStatus::NOT_ALLOWED_ERROR;
222   data_decoder::DataDecoder data_decoder_;
223 
224   base::flat_set<RequestExtension> requested_extensions_;
225 
226   base::WeakPtrFactory<AuthenticatorCommon> weak_factory_{this};
227 
228   DISALLOW_COPY_AND_ASSIGN(AuthenticatorCommon);
229 };
230 
231 }  // namespace content
232 
233 #endif  // CONTENT_BROWSER_WEBAUTH_AUTHENTICATOR_COMMON_H_
234