enrollment_handler.cc 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317
  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. #include "device/fido/bio/enrollment_handler.h"
  5. #include "base/bind.h"
  6. #include "base/callback_helpers.h"
  7. #include "components/device_event_log/device_event_log.h"
  8. #include "device/fido/bio/enrollment.h"
  9. #include "device/fido/fido_authenticator.h"
  10. #include "device/fido/fido_constants.h"
  11. #include "device/fido/pin.h"
  12. namespace device {
  13. BioEnrollmentHandler::SensorInfo::SensorInfo() = default;
  14. BioEnrollmentHandler::SensorInfo::SensorInfo(SensorInfo&&) = default;
  15. BioEnrollmentHandler::SensorInfo& BioEnrollmentHandler::SensorInfo::operator=(
  16. SensorInfo&&) = default;
  17. BioEnrollmentHandler::BioEnrollmentHandler(
  18. const base::flat_set<FidoTransportProtocol>& supported_transports,
  19. ReadyCallback ready_callback,
  20. ErrorCallback error_callback,
  21. GetPINCallback get_pin_callback,
  22. FidoDiscoveryFactory* factory)
  23. : FidoRequestHandlerBase(factory, supported_transports),
  24. ready_callback_(std::move(ready_callback)),
  25. error_callback_(std::move(error_callback)),
  26. get_pin_callback_(std::move(get_pin_callback)) {
  27. Start();
  28. }
  29. BioEnrollmentHandler::~BioEnrollmentHandler() {
  30. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  31. }
  32. void BioEnrollmentHandler::EnrollTemplate(
  33. SampleCallback sample_callback,
  34. EnrollmentCallback enrollment_callback) {
  35. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  36. DCHECK_EQ(state_, State::kReady);
  37. state_ = State::kEnrolling;
  38. sample_callback_ = std::move(sample_callback);
  39. enrollment_callback_ = std::move(enrollment_callback);
  40. bio_enroller_ =
  41. std::make_unique<BioEnroller>(this, authenticator_, *pin_token_response_);
  42. }
  43. void BioEnrollmentHandler::CancelEnrollment() {
  44. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  45. DCHECK_EQ(state_, State::kEnrolling);
  46. state_ = State::kCancellingEnrollment;
  47. bio_enroller_->Cancel();
  48. }
  49. void BioEnrollmentHandler::EnumerateTemplates(EnumerationCallback callback) {
  50. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  51. DCHECK(pin_token_response_);
  52. DCHECK_EQ(state_, State::kReady);
  53. state_ = State::kEnumerating;
  54. authenticator_->BioEnrollEnumerate(
  55. *pin_token_response_,
  56. base::BindOnce(&BioEnrollmentHandler::OnEnumerateTemplates,
  57. weak_factory_.GetWeakPtr(), std::move(callback)));
  58. }
  59. void BioEnrollmentHandler::RenameTemplate(std::vector<uint8_t> template_id,
  60. std::string name,
  61. StatusCallback callback) {
  62. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  63. DCHECK_EQ(state_, State::kReady);
  64. state_ = State::kRenaming;
  65. authenticator_->BioEnrollRename(
  66. *pin_token_response_, std::move(template_id), std::move(name),
  67. base::BindOnce(&BioEnrollmentHandler::OnRenameTemplate,
  68. weak_factory_.GetWeakPtr(), std::move(callback)));
  69. }
  70. void BioEnrollmentHandler::DeleteTemplate(std::vector<uint8_t> template_id,
  71. StatusCallback callback) {
  72. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  73. DCHECK_EQ(state_, State::kReady);
  74. state_ = State::kDeleting;
  75. authenticator_->BioEnrollDelete(
  76. *pin_token_response_, std::move(template_id),
  77. base::BindOnce(&BioEnrollmentHandler::OnDeleteTemplate,
  78. weak_factory_.GetWeakPtr(), std::move(callback)));
  79. }
  80. void BioEnrollmentHandler::DispatchRequest(FidoAuthenticator* authenticator) {
  81. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  82. if (state_ != State::kWaitingForTouch) {
  83. return;
  84. }
  85. authenticator->GetTouch(base::BindOnce(&BioEnrollmentHandler::OnTouch,
  86. weak_factory_.GetWeakPtr(),
  87. authenticator));
  88. }
  89. void BioEnrollmentHandler::AuthenticatorRemoved(
  90. FidoDiscoveryBase* discovery,
  91. FidoAuthenticator* authenticator) {
  92. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  93. FidoRequestHandlerBase::AuthenticatorRemoved(discovery, authenticator);
  94. if (authenticator_ != authenticator || state_ == State::kFinished) {
  95. return;
  96. }
  97. authenticator_ = nullptr;
  98. RunErrorCallback(Error::kAuthenticatorRemoved);
  99. }
  100. void BioEnrollmentHandler::OnSampleCollected(BioEnrollmentSampleStatus status,
  101. int samples_remaining) {
  102. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  103. DCHECK_EQ(state_, State::kEnrolling);
  104. sample_callback_.Run(status, samples_remaining);
  105. }
  106. void BioEnrollmentHandler::OnEnrollmentDone(
  107. absl::optional<std::vector<uint8_t>> template_id) {
  108. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  109. bio_enroller_.reset();
  110. if (!template_id) {
  111. DCHECK_EQ(state_, State::kCancellingEnrollment);
  112. state_ = State::kReady;
  113. std::move(enrollment_callback_)
  114. .Run(CtapDeviceResponseCode::kCtap2ErrKeepAliveCancel, {});
  115. return;
  116. }
  117. DCHECK(state_ == State::kEnrolling || state_ == State::kCancellingEnrollment);
  118. state_ = State::kReady;
  119. std::move(enrollment_callback_)
  120. .Run(CtapDeviceResponseCode::kSuccess, std::move(*template_id));
  121. }
  122. void BioEnrollmentHandler::OnEnrollmentError(CtapDeviceResponseCode status) {
  123. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  124. DCHECK(state_ == State::kEnrolling || state_ == State::kCancellingEnrollment);
  125. bio_enroller_.reset();
  126. state_ = State::kReady;
  127. std::move(enrollment_callback_).Run(status, {});
  128. }
  129. void BioEnrollmentHandler::OnTouch(FidoAuthenticator* authenticator) {
  130. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  131. if (state_ != State::kWaitingForTouch) {
  132. return;
  133. }
  134. CancelActiveAuthenticators(authenticator->GetId());
  135. if (!authenticator->Options() ||
  136. (authenticator->Options()->bio_enrollment_availability ==
  137. AuthenticatorSupportedOptions::BioEnrollmentAvailability::
  138. kNotSupported &&
  139. authenticator->Options()->bio_enrollment_availability_preview ==
  140. AuthenticatorSupportedOptions::BioEnrollmentAvailability::
  141. kNotSupported)) {
  142. RunErrorCallback(Error::kAuthenticatorMissingBioEnrollment);
  143. return;
  144. }
  145. if (authenticator->Options()->client_pin_availability !=
  146. AuthenticatorSupportedOptions::ClientPinAvailability::
  147. kSupportedAndPinSet) {
  148. RunErrorCallback(Error::kNoPINSet);
  149. return;
  150. }
  151. if (authenticator->ForcePINChange()) {
  152. RunErrorCallback(Error::kForcePINChange);
  153. return;
  154. }
  155. authenticator_ = authenticator;
  156. state_ = State::kGettingRetries;
  157. authenticator_->GetPinRetries(base::BindOnce(
  158. &BioEnrollmentHandler::OnRetriesResponse, weak_factory_.GetWeakPtr()));
  159. }
  160. void BioEnrollmentHandler::OnRetriesResponse(
  161. CtapDeviceResponseCode status,
  162. absl::optional<pin::RetriesResponse> response) {
  163. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  164. DCHECK_EQ(state_, State::kGettingRetries);
  165. if (!response || status != CtapDeviceResponseCode::kSuccess) {
  166. RunErrorCallback(Error::kAuthenticatorResponseInvalid);
  167. return;
  168. }
  169. if (response->retries == 0) {
  170. RunErrorCallback(Error::kHardPINBlock);
  171. return;
  172. }
  173. state_ = State::kWaitingForPIN;
  174. get_pin_callback_.Run(authenticator_->CurrentMinPINLength(),
  175. response->retries,
  176. base::BindOnce(&BioEnrollmentHandler::OnHavePIN,
  177. weak_factory_.GetWeakPtr()));
  178. }
  179. void BioEnrollmentHandler::OnHavePIN(std::string pin) {
  180. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  181. DCHECK_EQ(state_, State::kWaitingForPIN);
  182. state_ = State::kGettingPINToken;
  183. authenticator_->GetPINToken(
  184. std::move(pin), {pin::Permissions::kBioEnrollment},
  185. /*rp_id=*/absl::nullopt,
  186. base::BindOnce(&BioEnrollmentHandler::OnHavePINToken,
  187. weak_factory_.GetWeakPtr()));
  188. }
  189. void BioEnrollmentHandler::OnHavePINToken(
  190. CtapDeviceResponseCode status,
  191. absl::optional<pin::TokenResponse> response) {
  192. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  193. DCHECK_EQ(state_, State::kGettingPINToken);
  194. if (status != CtapDeviceResponseCode::kSuccess) {
  195. switch (status) {
  196. case CtapDeviceResponseCode::kCtap2ErrPinInvalid:
  197. state_ = State::kGettingRetries;
  198. authenticator_->GetPinRetries(
  199. base::BindOnce(&BioEnrollmentHandler::OnRetriesResponse,
  200. weak_factory_.GetWeakPtr()));
  201. return;
  202. case CtapDeviceResponseCode::kCtap2ErrPinAuthBlocked:
  203. RunErrorCallback(Error::kSoftPINBlock);
  204. return;
  205. case CtapDeviceResponseCode::kCtap2ErrPinBlocked:
  206. RunErrorCallback(Error::kHardPINBlock);
  207. return;
  208. default:
  209. RunErrorCallback(Error::kAuthenticatorResponseInvalid);
  210. return;
  211. }
  212. }
  213. pin_token_response_ = std::move(response);
  214. state_ = State::kGettingSensorInfo;
  215. authenticator_->GetSensorInfo(base::BindOnce(
  216. &BioEnrollmentHandler::OnGetSensorInfo, weak_factory_.GetWeakPtr()));
  217. }
  218. void BioEnrollmentHandler::OnGetSensorInfo(
  219. CtapDeviceResponseCode status,
  220. absl::optional<BioEnrollmentResponse> response) {
  221. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  222. DCHECK_EQ(state_, State::kGettingSensorInfo);
  223. if (status != CtapDeviceResponseCode::kSuccess) {
  224. RunErrorCallback(Error::kAuthenticatorResponseInvalid);
  225. return;
  226. }
  227. state_ = State::kReady;
  228. SensorInfo sensor_info;
  229. sensor_info.max_samples_for_enroll = response->max_samples_for_enroll;
  230. sensor_info.max_template_friendly_name =
  231. response->max_template_friendly_name.value_or(
  232. kDefaultMaxTemplateFriendlyName);
  233. std::move(ready_callback_).Run(std::move(sensor_info));
  234. }
  235. void BioEnrollmentHandler::OnEnumerateTemplates(
  236. EnumerationCallback callback,
  237. CtapDeviceResponseCode status,
  238. absl::optional<BioEnrollmentResponse> response) {
  239. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  240. DCHECK_EQ(state_, State::kEnumerating);
  241. state_ = State::kReady;
  242. if (status != CtapDeviceResponseCode::kSuccess) {
  243. std::move(callback).Run(status, absl::nullopt);
  244. return;
  245. }
  246. if (!response || !response->template_infos) {
  247. RunErrorCallback(Error::kAuthenticatorResponseInvalid);
  248. return;
  249. }
  250. std::move(callback).Run(status, std::move(*response->template_infos));
  251. }
  252. void BioEnrollmentHandler::OnRenameTemplate(
  253. StatusCallback callback,
  254. CtapDeviceResponseCode status,
  255. absl::optional<BioEnrollmentResponse> response) {
  256. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  257. DCHECK_EQ(state_, State::kRenaming);
  258. state_ = State::kReady;
  259. std::move(callback).Run(status);
  260. }
  261. void BioEnrollmentHandler::OnDeleteTemplate(
  262. StatusCallback callback,
  263. CtapDeviceResponseCode status,
  264. absl::optional<BioEnrollmentResponse> response) {
  265. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  266. DCHECK_EQ(state_, State::kDeleting);
  267. state_ = State::kReady;
  268. std::move(callback).Run(status);
  269. }
  270. void BioEnrollmentHandler::RunErrorCallback(Error error) {
  271. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  272. DCHECK_NE(state_, State::kFinished);
  273. state_ = State::kFinished;
  274. std::move(error_callback_).Run(error);
  275. }
  276. } // namespace device