1 // Copyright 2018 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 DEVICE_FIDO_MAKE_CREDENTIAL_REQUEST_HANDLER_H_
6 #define DEVICE_FIDO_MAKE_CREDENTIAL_REQUEST_HANDLER_H_
7 
8 #include <memory>
9 #include <string>
10 #include <utility>
11 #include <vector>
12 
13 #include "base/callback.h"
14 #include "base/component_export.h"
15 #include "base/macros.h"
16 #include "base/memory/weak_ptr.h"
17 #include "base/optional.h"
18 #include "base/sequence_checker.h"
19 #include "device/fido/auth_token_requester.h"
20 #include "device/fido/authenticator_make_credential_response.h"
21 #include "device/fido/authenticator_selection_criteria.h"
22 #include "device/fido/bio/enroller.h"
23 #include "device/fido/client_data.h"
24 #include "device/fido/ctap_make_credential_request.h"
25 #include "device/fido/fido_constants.h"
26 #include "device/fido/fido_request_handler_base.h"
27 #include "device/fido/fido_transport_protocol.h"
28 #include "device/fido/fido_types.h"
29 #include "device/fido/pin.h"
30 
31 namespace base {
32 class ElapsedTimer;
33 }
34 
35 namespace device {
36 
37 class FidoAuthenticator;
38 class FidoDiscoveryFactory;
39 
40 namespace pin {
41 class TokenResponse;
42 }  // namespace pin
43 
44 enum class MakeCredentialStatus {
45   kSuccess,
46   kAuthenticatorResponseInvalid,
47   kUserConsentButCredentialExcluded,
48   kUserConsentDenied,
49   kAuthenticatorRemovedDuringPINEntry,
50   kSoftPINBlock,
51   kHardPINBlock,
52   kAuthenticatorMissingResidentKeys,
53   // TODO(agl): kAuthenticatorMissingUserVerification can
54   // also be returned when the authenticator supports UV, but
55   // there's no UI support for collecting a PIN. This could
56   // be clearer.
57   kAuthenticatorMissingUserVerification,
58   kAuthenticatorMissingLargeBlob,
59   kNoCommonAlgorithms,
60   kStorageFull,
61   kWinInvalidStateError,
62   kWinNotAllowedError,
63 };
64 
COMPONENT_EXPORT(DEVICE_FIDO)65 class COMPONENT_EXPORT(DEVICE_FIDO) MakeCredentialRequestHandler
66     : public FidoRequestHandlerBase,
67       public AuthTokenRequester::Delegate,
68       public BioEnroller::Delegate {
69  public:
70   using CompletionCallback = base::OnceCallback<void(
71       MakeCredentialStatus,
72       base::Optional<AuthenticatorMakeCredentialResponse>,
73       const FidoAuthenticator*)>;
74 
75   // Options contains higher-level request parameters that aren't part of the
76   // makeCredential request itself, or that need to be combined with knowledge
77   // of the specific authenticator, thus don't live in
78   // |CtapMakeCredentialRequest|.
79   struct COMPONENT_EXPORT(DEVICE_FIDO) Options {
80     Options();
81     explicit Options(
82         const AuthenticatorSelectionCriteria& authenticator_selection_criteria);
83     ~Options();
84     Options(const Options&);
85     Options(Options&&);
86     Options& operator=(const Options&);
87     Options& operator=(Options&&);
88 
89     // authenticator_attachment is a constraint on the type of authenticator
90     // that a credential should be created on.
91     AuthenticatorAttachment authenticator_attachment =
92         AuthenticatorAttachment::kAny;
93 
94     // resident_key indicates whether the request should result in the creation
95     // of a client-side discoverable credential (aka resident key).
96     ResidentKeyRequirement resident_key = ResidentKeyRequirement::kDiscouraged;
97 
98     // user_verification indicates whether the authenticator should (or must)
99     // perform user verficiation before creating the credential.
100     UserVerificationRequirement user_verification =
101         UserVerificationRequirement::kPreferred;
102 
103     // cred_protect_request extends |CredProtect| to include information that
104     // applies at request-routing time. The second element is true if the
105     // indicated protection level must be provided by the target authenticator
106     // for the MakeCredential request to be sent.
107     base::Optional<std::pair<CredProtectRequest, bool>> cred_protect_request;
108 
109     // allow_skipping_pin_touch causes the handler to forego the first
110     // "touch-only" step to collect a PIN if exactly one authenticator is
111     // discovered.
112     bool allow_skipping_pin_touch = false;
113 
114     // android_client_data_ext is a compatibility hack to support the Clank
115     // caBLEv2 authenticator.
116     base::Optional<AndroidClientDataExtensionInput> android_client_data_ext;
117 
118     // large_blob_support indicates whether the request should select for
119     // authenticators supporting the largeBlobs extension (kRequired), merely
120     // indicate support on the response (kPreferred), or ignore it
121     // (kNotRequested).
122     // Values other than kNotRequested will attempt to initialize the large blob
123     // on the authenticator.
124     LargeBlobSupport large_blob_support = LargeBlobSupport::kNotRequested;
125   };
126 
127   MakeCredentialRequestHandler(
128       FidoDiscoveryFactory* fido_discovery_factory,
129       const base::flat_set<FidoTransportProtocol>& supported_transports,
130       CtapMakeCredentialRequest request_parameter,
131       const Options& options,
132       CompletionCallback completion_callback);
133   ~MakeCredentialRequestHandler() override;
134 
135  private:
136   enum class State {
137     kWaitingForTouch,
138     kWaitingForToken,
139     kBioEnrollment,
140     kBioEnrollmentDone,
141     kWaitingForResponseWithToken,
142     kFinished,
143   };
144 
145   // FidoRequestHandlerBase:
146   void DispatchRequest(FidoAuthenticator* authenticator) override;
147   void AuthenticatorRemoved(FidoDiscoveryBase* discovery,
148                             FidoAuthenticator* authenticator) override;
149 
150   // AuthTokenRequester::Delegate:
151   void AuthenticatorSelectedForPINUVAuthToken(
152       FidoAuthenticator* authenticator) override;
153   void CollectNewPIN(ProvidePINCallback provide_pin_cb) override;
154   void CollectExistingPIN(int attempts,
155                           ProvidePINCallback provide_pin_cb) override;
156   void PromptForInternalUVRetry(int attempts) override;
157   void InternalUVLockedForAuthToken() override;
158   void HavePINUVAuthTokenResultForAuthenticator(
159       FidoAuthenticator* authenticator,
160       AuthTokenRequester::Result result,
161       base::Optional<pin::TokenResponse> response) override;
162 
163   // BioEnroller::Delegate:
164   void OnSampleCollected(BioEnrollmentSampleStatus status,
165                          int samples_remaining) override;
166   void OnEnrollmentDone(
167       base::Optional<std::vector<uint8_t>> template_id) override;
168   void OnEnrollmentError(CtapDeviceResponseCode status) override;
169 
170   void ObtainPINUVAuthToken(FidoAuthenticator* authenticator,
171                             bool skip_pin_touch);
172 
173   void HandleResponse(
174       FidoAuthenticator* authenticator,
175       std::unique_ptr<CtapMakeCredentialRequest> request,
176       base::ElapsedTimer request_timer,
177       CtapDeviceResponseCode response_code,
178       base::Optional<AuthenticatorMakeCredentialResponse> response);
179   void HandleInternalUvLocked(FidoAuthenticator* authenticator);
180   void HandleInapplicableAuthenticator(
181       FidoAuthenticator* authenticator,
182       std::unique_ptr<CtapMakeCredentialRequest> request);
183   void OnEnrollmentComplete(std::unique_ptr<CtapMakeCredentialRequest> request);
184   void OnEnrollmentDismissed();
185   void DispatchRequestWithToken(
186       FidoAuthenticator* authenticator,
187       std::unique_ptr<CtapMakeCredentialRequest> request,
188       pin::TokenResponse token);
189 
190   void SpecializeRequestForAuthenticator(
191       CtapMakeCredentialRequest* request,
192       const FidoAuthenticator* authenticator);
193 
194   CompletionCallback completion_callback_;
195   State state_ = State::kWaitingForTouch;
196   CtapMakeCredentialRequest request_;
197   base::Optional<base::RepeatingClosure> bio_enrollment_complete_barrier_;
198   const Options options_;
199 
200   std::map<FidoAuthenticator*, std::unique_ptr<AuthTokenRequester>>
201       auth_token_requester_map_;
202 
203   // selected_authenticator_for_pin_uv_auth_token_ points to the authenticator
204   // that was tapped by the user while requesting a pinUvAuthToken from
205   // connected authenticators. The object is owned by the underlying discovery
206   // object and this pointer is cleared if it's removed during processing.
207   FidoAuthenticator* selected_authenticator_for_pin_uv_auth_token_ = nullptr;
208   base::Optional<pin::TokenResponse> token_;
209   std::unique_ptr<BioEnroller> bio_enroller_;
210   SEQUENCE_CHECKER(my_sequence_checker_);
211   base::WeakPtrFactory<MakeCredentialRequestHandler> weak_factory_{this};
212 
213   DISALLOW_COPY_AND_ASSIGN(MakeCredentialRequestHandler);
214 };
215 
216 }  // namespace device
217 
218 #endif  // DEVICE_FIDO_MAKE_CREDENTIAL_REQUEST_HANDLER_H_
219