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 
11 #include "base/callback.h"
12 #include "base/component_export.h"
13 #include "base/macros.h"
14 #include "base/memory/weak_ptr.h"
15 #include "base/optional.h"
16 #include "base/sequence_checker.h"
17 #include "device/fido/authenticator_make_credential_response.h"
18 #include "device/fido/authenticator_selection_criteria.h"
19 #include "device/fido/client_data.h"
20 #include "device/fido/ctap_make_credential_request.h"
21 #include "device/fido/fido_constants.h"
22 #include "device/fido/fido_request_handler_base.h"
23 #include "device/fido/fido_transport_protocol.h"
24 
25 namespace device {
26 
27 class FidoAuthenticator;
28 class FidoDiscoveryFactory;
29 
30 namespace pin {
31 struct EmptyResponse;
32 struct RetriesResponse;
33 class TokenResponse;
34 }  // namespace pin
35 
36 enum class MakeCredentialStatus {
37   kSuccess,
38   kAuthenticatorResponseInvalid,
39   kUserConsentButCredentialExcluded,
40   kUserConsentDenied,
41   kAuthenticatorRemovedDuringPINEntry,
42   kSoftPINBlock,
43   kHardPINBlock,
44   kAuthenticatorMissingResidentKeys,
45   // TODO(agl): kAuthenticatorMissingUserVerification can
46   // also be returned when the authenticator supports UV, but
47   // there's no UI support for collecting a PIN. This could
48   // be clearer.
49   kAuthenticatorMissingUserVerification,
50   kStorageFull,
51   kWinInvalidStateError,
52   kWinNotAllowedError,
53 };
54 
COMPONENT_EXPORT(DEVICE_FIDO)55 class COMPONENT_EXPORT(DEVICE_FIDO) MakeCredentialRequestHandler
56     : public FidoRequestHandlerBase {
57  public:
58   using CompletionCallback = base::OnceCallback<void(
59       MakeCredentialStatus,
60       base::Optional<AuthenticatorMakeCredentialResponse>,
61       const FidoAuthenticator*)>;
62 
63   MakeCredentialRequestHandler(
64       FidoDiscoveryFactory* fido_discovery_factory,
65       const base::flat_set<FidoTransportProtocol>& supported_transports,
66       CtapMakeCredentialRequest request_parameter,
67       AuthenticatorSelectionCriteria authenticator_criteria,
68       bool allow_skipping_pin_touch,
69       CompletionCallback completion_callback);
70   ~MakeCredentialRequestHandler() override;
71 
72  private:
73   enum class State {
74     kWaitingForTouch,
75     kWaitingForSecondTouch,
76     kGettingRetries,
77     kWaitingForPIN,
78     kWaitingForNewPIN,
79     kSettingPIN,
80     kRequestWithPIN,
81     kFinished,
82   };
83 
84   // FidoRequestHandlerBase:
85   void DispatchRequest(FidoAuthenticator* authenticator) override;
86   void AuthenticatorRemoved(FidoDiscoveryBase* discovery,
87                             FidoAuthenticator* authenticator) override;
88 
89   void HandleResponse(
90       FidoAuthenticator* authenticator,
91       CtapDeviceResponseCode response_code,
92       base::Optional<AuthenticatorMakeCredentialResponse> response);
93   void CollectPINThenSendRequest(FidoAuthenticator* authenticator);
94   void StartPINFallbackForInternalUv(FidoAuthenticator* authenticator);
95   void SetPINThenSendRequest(FidoAuthenticator* authenticator);
96   void HandleInternalUvLocked(FidoAuthenticator* authenticator);
97   void HandleInapplicableAuthenticator(FidoAuthenticator* authenticator);
98   void OnHavePIN(std::string pin);
99   void OnRetriesResponse(CtapDeviceResponseCode status,
100                          base::Optional<pin::RetriesResponse> response);
101   void OnHaveSetPIN(std::string pin,
102                     CtapDeviceResponseCode status,
103                     base::Optional<pin::EmptyResponse> response);
104   void OnHavePINToken(CtapDeviceResponseCode status,
105                       base::Optional<pin::TokenResponse> response);
106   void OnUvRetriesResponse(CtapDeviceResponseCode status,
107                            base::Optional<pin::RetriesResponse> response);
108   void OnHaveUvToken(FidoAuthenticator* authenticator,
109                      CtapDeviceResponseCode status,
110                      base::Optional<pin::TokenResponse> response);
111   void DispatchRequestWithToken(pin::TokenResponse token);
112 
113   CompletionCallback completion_callback_;
114   State state_ = State::kWaitingForTouch;
115   CtapMakeCredentialRequest request_;
116   AuthenticatorSelectionCriteria authenticator_selection_criteria_;
117   base::Optional<AndroidClientDataExtensionInput> android_client_data_ext_;
118 
119   // If true, the request handler may skip the first touch to select a device
120   // that will require a PIN.
121   bool allow_skipping_pin_touch_;
122   // authenticator_ points to the authenticator that will be used for this
123   // operation. It's only set after the user touches an authenticator to select
124   // it, after which point that authenticator will be used exclusively through
125   // requesting PIN etc. The object is owned by the underlying discovery object
126   // and this pointer is cleared if it's removed during processing.
127   FidoAuthenticator* authenticator_ = nullptr;
128   SEQUENCE_CHECKER(my_sequence_checker_);
129   base::WeakPtrFactory<MakeCredentialRequestHandler> weak_factory_{this};
130 
131   DISALLOW_COPY_AND_ASSIGN(MakeCredentialRequestHandler);
132 };
133 
134 }  // namespace device
135 
136 #endif  // DEVICE_FIDO_MAKE_CREDENTIAL_REQUEST_HANDLER_H_
137