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