fido_device_authenticator.cc 47 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189
  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. #include "device/fido/fido_device_authenticator.h"
  5. #include <algorithm>
  6. #include <numeric>
  7. #include <utility>
  8. #include "base/bind.h"
  9. #include "base/containers/contains.h"
  10. #include "base/feature_list.h"
  11. #include "base/logging.h"
  12. #include "base/threading/sequenced_task_runner_handle.h"
  13. #include "build/build_config.h"
  14. #include "build/chromeos_buildflags.h"
  15. #include "device/fido/appid_exclude_probe_task.h"
  16. #include "device/fido/authenticator_supported_options.h"
  17. #include "device/fido/credential_management.h"
  18. #include "device/fido/ctap_authenticator_selection_request.h"
  19. #include "device/fido/ctap_get_assertion_request.h"
  20. #include "device/fido/ctap_make_credential_request.h"
  21. #include "device/fido/features.h"
  22. #include "device/fido/fido_constants.h"
  23. #include "device/fido/fido_device.h"
  24. #include "device/fido/fido_parsing_utils.h"
  25. #include "device/fido/fido_types.h"
  26. #include "device/fido/get_assertion_task.h"
  27. #include "device/fido/large_blob.h"
  28. #include "device/fido/make_credential_task.h"
  29. #include "device/fido/pin.h"
  30. #include "device/fido/u2f_command_constructor.h"
  31. #include "device/fido/virtual_fido_device.h"
  32. namespace device {
  33. using ClientPinAvailability =
  34. AuthenticatorSupportedOptions::ClientPinAvailability;
  35. using UserVerificationAvailability =
  36. AuthenticatorSupportedOptions::UserVerificationAvailability;
  37. namespace {
  38. // Helper method for determining correct bio enrollment version.
  39. BioEnrollmentRequest::Version GetBioEnrollmentRequestVersion(
  40. const AuthenticatorSupportedOptions& options) {
  41. DCHECK(options.bio_enrollment_availability_preview !=
  42. AuthenticatorSupportedOptions::BioEnrollmentAvailability::
  43. kNotSupported ||
  44. options.bio_enrollment_availability !=
  45. AuthenticatorSupportedOptions::BioEnrollmentAvailability::
  46. kNotSupported);
  47. return options.bio_enrollment_availability !=
  48. AuthenticatorSupportedOptions::BioEnrollmentAvailability::
  49. kNotSupported
  50. ? BioEnrollmentRequest::kDefault
  51. : BioEnrollmentRequest::kPreview;
  52. }
  53. CredentialManagementRequest::Version GetCredentialManagementRequestVersion(
  54. const AuthenticatorSupportedOptions& options) {
  55. DCHECK(options.supports_credential_management_preview ||
  56. options.supports_credential_management);
  57. return options.supports_credential_management
  58. ? CredentialManagementRequest::kDefault
  59. : CredentialManagementRequest::kPreview;
  60. }
  61. } // namespace
  62. FidoDeviceAuthenticator::FidoDeviceAuthenticator(
  63. std::unique_ptr<FidoDevice> device)
  64. : device_(std::move(device)) {}
  65. FidoDeviceAuthenticator::~FidoDeviceAuthenticator() = default;
  66. void FidoDeviceAuthenticator::InitializeAuthenticator(
  67. base::OnceClosure callback) {
  68. base::SequencedTaskRunnerHandle::Get()->PostTask(
  69. FROM_HERE,
  70. base::BindOnce(
  71. &FidoDevice::DiscoverSupportedProtocolAndDeviceInfo,
  72. device()->GetWeakPtr(),
  73. base::BindOnce(&FidoDeviceAuthenticator::InitializeAuthenticatorDone,
  74. weak_factory_.GetWeakPtr(), std::move(callback))));
  75. }
  76. void FidoDeviceAuthenticator::InitializeAuthenticatorDone(
  77. base::OnceClosure callback) {
  78. DCHECK(!options_);
  79. switch (device_->supported_protocol()) {
  80. case ProtocolVersion::kU2f:
  81. options_ = AuthenticatorSupportedOptions();
  82. break;
  83. case ProtocolVersion::kCtap2:
  84. DCHECK(device_->device_info()) << "uninitialized device";
  85. options_ = device_->device_info()->options;
  86. if (device_->device_info()->pin_protocols) {
  87. DCHECK(!device_->device_info()->pin_protocols->empty());
  88. // Choose the highest supported version.
  89. chosen_pin_uv_auth_protocol_ =
  90. *(device_->device_info()->pin_protocols->end() - 1);
  91. }
  92. break;
  93. case ProtocolVersion::kUnknown:
  94. NOTREACHED() << "uninitialized device";
  95. options_ = AuthenticatorSupportedOptions();
  96. }
  97. std::move(callback).Run();
  98. }
  99. void FidoDeviceAuthenticator::ExcludeAppIdCredentialsBeforeMakeCredential(
  100. CtapMakeCredentialRequest request,
  101. MakeCredentialOptions options,
  102. base::OnceCallback<void(CtapDeviceResponseCode, absl::optional<bool>)>
  103. callback) {
  104. // If the device (or request) is U2F-only then |MakeCredential| will handle
  105. // the AppID-excluded credentials, if any. There's no interaction with PUATs
  106. // to worry about because U2F doesn't have them.
  107. //
  108. // (If the device is AlwaysUV then it should still support up=false requests
  109. // without a PUAT, so they aren't excluded here.)
  110. if (!MakeCredentialTask::WillUseCTAP2(device_.get(), request, options) ||
  111. device_->NoSilentRequests()) {
  112. std::move(callback).Run(CtapDeviceResponseCode::kSuccess, absl::nullopt);
  113. return;
  114. }
  115. // This is a CTAP2 device. In CTAP 2.1, a PUAT is invalidated if a request is
  116. // made with a different RP ID, even if the PUAT isn't used on that request.
  117. // Therefore appidExclude probing has to happen before the PUAT is obtained.
  118. // For CTAP 2.0 devices we follow the same pattern, even though a PIN token
  119. // doesn't have that issue.
  120. RunTask<AppIdExcludeProbeTask, bool, CtapMakeCredentialRequest,
  121. MakeCredentialOptions>(std::move(request), std::move(options),
  122. std::move(callback));
  123. }
  124. void FidoDeviceAuthenticator::MakeCredential(
  125. CtapMakeCredentialRequest request,
  126. MakeCredentialOptions request_options,
  127. MakeCredentialCallback callback) {
  128. // If the authenticator has UV configured then UV will be required in
  129. // order to create a credential (as specified by CTAP 2.0), even if
  130. // user-verification is "discouraged". However, if the request is U2F-only
  131. // then that doesn't apply and UV must be set to discouraged so that the
  132. // request can be translated to U2F.
  133. if (!request.pin_auth &&
  134. options_->user_verification_availability ==
  135. UserVerificationAvailability::kSupportedAndConfigured &&
  136. !options_->make_cred_uv_not_required &&
  137. !request_options.make_u2f_api_credential) {
  138. request.user_verification = UserVerificationRequirement::kRequired;
  139. } else {
  140. request.user_verification = UserVerificationRequirement::kDiscouraged;
  141. }
  142. RunTask<MakeCredentialTask, AuthenticatorMakeCredentialResponse,
  143. CtapMakeCredentialRequest, MakeCredentialOptions>(
  144. std::move(request), std::move(request_options), std::move(callback));
  145. }
  146. void FidoDeviceAuthenticator::GetAssertion(CtapGetAssertionRequest request,
  147. CtapGetAssertionOptions options,
  148. GetAssertionCallback callback) {
  149. if (!options.prf_inputs.empty()) {
  150. GetEphemeralKey(base::BindOnce(
  151. &FidoDeviceAuthenticator::OnHaveEphemeralKeyForGetAssertion,
  152. weak_factory_.GetWeakPtr(), std::move(request), std::move(options),
  153. std::move(callback)));
  154. return;
  155. }
  156. DoGetAssertion(std::move(request), std::move(options), std::move(callback));
  157. }
  158. void FidoDeviceAuthenticator::OnHaveEphemeralKeyForGetAssertion(
  159. CtapGetAssertionRequest request,
  160. CtapGetAssertionOptions options,
  161. GetAssertionCallback callback,
  162. CtapDeviceResponseCode status,
  163. absl::optional<pin::KeyAgreementResponse> key) {
  164. if (status != CtapDeviceResponseCode::kSuccess) {
  165. std::move(callback).Run(status, absl::nullopt);
  166. return;
  167. }
  168. options.pin_key_agreement = std::move(*key);
  169. DoGetAssertion(std::move(request), std::move(options), std::move(callback));
  170. }
  171. void FidoDeviceAuthenticator::DoGetAssertion(CtapGetAssertionRequest request,
  172. CtapGetAssertionOptions options,
  173. GetAssertionCallback callback) {
  174. if (!request.pin_auth &&
  175. options_->user_verification_availability ==
  176. UserVerificationAvailability::kSupportedAndConfigured &&
  177. request.user_verification != UserVerificationRequirement::kDiscouraged) {
  178. request.user_verification = UserVerificationRequirement::kRequired;
  179. } else {
  180. request.user_verification = UserVerificationRequirement::kDiscouraged;
  181. }
  182. RunTask<GetAssertionTask, AuthenticatorGetAssertionResponse,
  183. CtapGetAssertionRequest, CtapGetAssertionOptions>(
  184. std::move(request), std::move(options), std::move(callback));
  185. }
  186. void FidoDeviceAuthenticator::GetNextAssertion(GetAssertionCallback callback) {
  187. RunOperation<CtapGetNextAssertionRequest, AuthenticatorGetAssertionResponse>(
  188. CtapGetNextAssertionRequest(), std::move(callback),
  189. base::BindOnce(&ReadCTAPGetAssertionResponse, device_->DeviceTransport()),
  190. GetAssertionTask::StringFixupPredicate);
  191. }
  192. void FidoDeviceAuthenticator::GetTouch(base::OnceClosure callback) {
  193. if (device()->device_info() &&
  194. device()->device_info()->SupportsAtLeast(Ctap2Version::kCtap2_1)) {
  195. RunOperation<CtapAuthenticatorSelectionRequest, pin::EmptyResponse>(
  196. CtapAuthenticatorSelectionRequest(),
  197. base::BindOnce(
  198. [](std::string authenticator_id, base::OnceClosure callback,
  199. CtapDeviceResponseCode status,
  200. absl::optional<pin::EmptyResponse> _) {
  201. if (status == CtapDeviceResponseCode::kSuccess) {
  202. std::move(callback).Run();
  203. return;
  204. }
  205. FIDO_LOG(DEBUG) << "Ignoring status " << static_cast<int>(status)
  206. << " from " << authenticator_id;
  207. },
  208. GetId(), std::move(callback)),
  209. base::BindOnce(&pin::EmptyResponse::Parse));
  210. return;
  211. }
  212. MakeCredential(
  213. MakeCredentialTask::GetTouchRequest(device()), MakeCredentialOptions(),
  214. base::BindOnce(
  215. [](std::string authenticator_id, base::OnceCallback<void()> callback,
  216. CtapDeviceResponseCode status,
  217. absl::optional<AuthenticatorMakeCredentialResponse>) {
  218. // If the device didn't understand/process the request it may
  219. // fail immediately. Rather than count that as a touch, ignore
  220. // those cases completely.
  221. if (status == CtapDeviceResponseCode::kSuccess ||
  222. status == CtapDeviceResponseCode::kCtap2ErrPinNotSet ||
  223. status == CtapDeviceResponseCode::kCtap2ErrPinInvalid ||
  224. status == CtapDeviceResponseCode::kCtap2ErrPinAuthInvalid) {
  225. std::move(callback).Run();
  226. return;
  227. }
  228. FIDO_LOG(DEBUG) << "Ignoring status " << static_cast<int>(status)
  229. << " from " << authenticator_id;
  230. },
  231. GetId(), std::move(callback)));
  232. }
  233. void FidoDeviceAuthenticator::GetPinRetries(GetRetriesCallback callback) {
  234. DCHECK(Options());
  235. DCHECK(Options()->client_pin_availability !=
  236. ClientPinAvailability::kNotSupported);
  237. DCHECK(chosen_pin_uv_auth_protocol_);
  238. RunOperation<pin::PinRetriesRequest, pin::RetriesResponse>(
  239. pin::PinRetriesRequest{*chosen_pin_uv_auth_protocol_},
  240. std::move(callback),
  241. base::BindOnce(&pin::RetriesResponse::ParsePinRetries));
  242. }
  243. void FidoDeviceAuthenticator::GetEphemeralKey(
  244. GetEphemeralKeyCallback callback) {
  245. DCHECK(Options());
  246. DCHECK(Options()->client_pin_availability !=
  247. ClientPinAvailability::kNotSupported ||
  248. Options()->supports_pin_uv_auth_token ||
  249. SupportsHMACSecretExtension());
  250. DCHECK(chosen_pin_uv_auth_protocol_);
  251. RunOperation<pin::KeyAgreementRequest, pin::KeyAgreementResponse>(
  252. pin::KeyAgreementRequest{*chosen_pin_uv_auth_protocol_},
  253. std::move(callback), base::BindOnce(&pin::KeyAgreementResponse::Parse));
  254. }
  255. void FidoDeviceAuthenticator::GetPINToken(
  256. std::string pin,
  257. std::vector<pin::Permissions> permissions,
  258. absl::optional<std::string> rp_id,
  259. GetTokenCallback callback) {
  260. DCHECK(Options());
  261. DCHECK(Options()->client_pin_availability !=
  262. ClientPinAvailability::kNotSupported);
  263. DCHECK_NE(permissions.size(), 0u);
  264. DCHECK(!((base::Contains(permissions, pin::Permissions::kMakeCredential)) ||
  265. base::Contains(permissions, pin::Permissions::kGetAssertion)) ||
  266. rp_id);
  267. GetEphemeralKey(base::BindOnce(
  268. &FidoDeviceAuthenticator::OnHaveEphemeralKeyForGetPINToken,
  269. weak_factory_.GetWeakPtr(), std::move(pin), std::move(permissions),
  270. std::move(rp_id), std::move(callback)));
  271. }
  272. void FidoDeviceAuthenticator::OnHaveEphemeralKeyForGetPINToken(
  273. std::string pin,
  274. std::vector<pin::Permissions> permissions,
  275. absl::optional<std::string> rp_id,
  276. GetTokenCallback callback,
  277. CtapDeviceResponseCode status,
  278. absl::optional<pin::KeyAgreementResponse> key) {
  279. if (status != CtapDeviceResponseCode::kSuccess) {
  280. std::move(callback).Run(status, absl::nullopt);
  281. return;
  282. }
  283. if (Options()->supports_pin_uv_auth_token) {
  284. pin::PinTokenWithPermissionsRequest request(*chosen_pin_uv_auth_protocol_,
  285. pin, *key, permissions, rp_id);
  286. std::vector<uint8_t> shared_key = request.shared_key();
  287. RunOperation<pin::PinTokenWithPermissionsRequest, pin::TokenResponse>(
  288. std::move(request), std::move(callback),
  289. base::BindOnce(&pin::TokenResponse::Parse,
  290. *chosen_pin_uv_auth_protocol_, std::move(shared_key)));
  291. return;
  292. }
  293. pin::PinTokenRequest request(*chosen_pin_uv_auth_protocol_, pin, *key);
  294. std::vector<uint8_t> shared_key = request.shared_key();
  295. RunOperation<pin::PinTokenRequest, pin::TokenResponse>(
  296. std::move(request), std::move(callback),
  297. base::BindOnce(&pin::TokenResponse::Parse, *chosen_pin_uv_auth_protocol_,
  298. std::move(shared_key)));
  299. }
  300. void FidoDeviceAuthenticator::SetPIN(const std::string& pin,
  301. SetPINCallback callback) {
  302. DCHECK(Options());
  303. DCHECK(Options()->client_pin_availability !=
  304. ClientPinAvailability::kNotSupported);
  305. GetEphemeralKey(base::BindOnce(
  306. &FidoDeviceAuthenticator::OnHaveEphemeralKeyForSetPIN,
  307. weak_factory_.GetWeakPtr(), std::move(pin), std::move(callback)));
  308. }
  309. void FidoDeviceAuthenticator::OnHaveEphemeralKeyForSetPIN(
  310. std::string pin,
  311. SetPINCallback callback,
  312. CtapDeviceResponseCode status,
  313. absl::optional<pin::KeyAgreementResponse> key) {
  314. if (status != CtapDeviceResponseCode::kSuccess) {
  315. std::move(callback).Run(status, absl::nullopt);
  316. return;
  317. }
  318. RunOperation<pin::SetRequest, pin::EmptyResponse>(
  319. pin::SetRequest(*chosen_pin_uv_auth_protocol_, pin, *key),
  320. std::move(callback), base::BindOnce(&pin::EmptyResponse::Parse));
  321. }
  322. void FidoDeviceAuthenticator::ChangePIN(const std::string& old_pin,
  323. const std::string& new_pin,
  324. SetPINCallback callback) {
  325. DCHECK(Options());
  326. DCHECK(Options()->client_pin_availability !=
  327. ClientPinAvailability::kNotSupported);
  328. GetEphemeralKey(
  329. base::BindOnce(&FidoDeviceAuthenticator::OnHaveEphemeralKeyForChangePIN,
  330. weak_factory_.GetWeakPtr(), std::move(old_pin),
  331. std::move(new_pin), std::move(callback)));
  332. }
  333. void FidoDeviceAuthenticator::OnHaveEphemeralKeyForChangePIN(
  334. std::string old_pin,
  335. std::string new_pin,
  336. SetPINCallback callback,
  337. CtapDeviceResponseCode status,
  338. absl::optional<pin::KeyAgreementResponse> key) {
  339. if (status != CtapDeviceResponseCode::kSuccess) {
  340. std::move(callback).Run(status, absl::nullopt);
  341. return;
  342. }
  343. RunOperation<pin::ChangeRequest, pin::EmptyResponse>(
  344. pin::ChangeRequest(*chosen_pin_uv_auth_protocol_, old_pin, new_pin, *key),
  345. std::move(callback), base::BindOnce(&pin::EmptyResponse::Parse));
  346. }
  347. FidoAuthenticator::PINUVDisposition
  348. FidoDeviceAuthenticator::PINUVDispositionForMakeCredential(
  349. const CtapMakeCredentialRequest& request,
  350. const FidoRequestHandlerBase::Observer* observer) {
  351. DCHECK(device_->SupportedProtocolIsInitialized());
  352. DCHECK(options_);
  353. const bool can_collect_pin = observer && observer->SupportsPIN();
  354. const bool pin_supported = Options()->client_pin_availability !=
  355. ClientPinAvailability::kNotSupported;
  356. const bool pin_configured = Options()->client_pin_availability ==
  357. ClientPinAvailability::kSupportedAndPinSet;
  358. const bool uv_configured =
  359. Options()->user_verification_availability ==
  360. UserVerificationAvailability::kSupportedAndConfigured;
  361. // CTAP 2.0 requires a PIN for credential creation once a PIN has been set.
  362. // Thus, if fallback to U2F isn't possible, a PIN will be needed if set.
  363. const bool u2f_fallback_possible =
  364. device()->device_info() &&
  365. device()->device_info()->versions.contains(ProtocolVersion::kU2f) &&
  366. IsConvertibleToU2fRegisterCommand(request) &&
  367. !ShouldPreferCTAP2EvenIfItNeedsAPIN(request);
  368. // CTAP 2.1 authenticators on the other hand can indicate that they allow
  369. // credential creation with PIN or UV.
  370. const bool can_make_ctap2_credential_without_uv =
  371. request.user_verification == UserVerificationRequirement::kDiscouraged &&
  372. options_->make_cred_uv_not_required;
  373. const UserVerificationRequirement uv_requirement =
  374. (pin_configured && !u2f_fallback_possible &&
  375. !can_make_ctap2_credential_without_uv)
  376. ? UserVerificationRequirement::kRequired
  377. : request.user_verification;
  378. if (uv_requirement == UserVerificationRequirement::kDiscouraged ||
  379. (uv_requirement == UserVerificationRequirement::kPreferred &&
  380. ((!pin_configured || !can_collect_pin) && !uv_configured))) {
  381. return PINUVDisposition::kNoUV;
  382. }
  383. // Authenticators with built-in UV that don't support UV token should try
  384. // sending the request as-is with uv=true first.
  385. if (uv_configured && !CanGetUvToken()) {
  386. return (can_collect_pin && pin_supported)
  387. ? PINUVDisposition::kNoTokenInternalUVPINFallback
  388. : PINUVDisposition::kNoTokenInternalUV;
  389. }
  390. const bool can_get_token =
  391. (can_collect_pin && pin_supported) || CanGetUvToken();
  392. if (can_get_token) {
  393. return PINUVDisposition::kGetToken;
  394. }
  395. return PINUVDisposition::kUnsatisfiable;
  396. }
  397. FidoAuthenticator::PINUVDisposition
  398. FidoDeviceAuthenticator::PINUVDispositionForGetAssertion(
  399. const CtapGetAssertionRequest& request,
  400. const FidoRequestHandlerBase::Observer* observer) {
  401. // TODO(crbug.com/1149405): GetAssertion requests don't allow in-line UV
  402. // enrollment. Perhaps we should change this and align with MakeCredential
  403. // behavior.
  404. const bool can_collect_pin = observer && observer->SupportsPIN();
  405. const bool pin_configured = Options()->client_pin_availability ==
  406. ClientPinAvailability::kSupportedAndPinSet;
  407. const bool uv_configured =
  408. Options()->user_verification_availability ==
  409. UserVerificationAvailability::kSupportedAndConfigured;
  410. const UserVerificationRequirement uv_requirement =
  411. request.allow_list.empty() ? UserVerificationRequirement::kRequired
  412. : request.user_verification;
  413. if (uv_requirement == UserVerificationRequirement::kDiscouraged ||
  414. (uv_requirement == UserVerificationRequirement::kPreferred &&
  415. ((!pin_configured || !can_collect_pin) && !uv_configured))) {
  416. return PINUVDisposition::kNoUV;
  417. }
  418. // Authenticators with built-in UV that don't support UV token should try
  419. // sending the request as-is with uv=true first.
  420. if (uv_configured && !CanGetUvToken()) {
  421. return (can_collect_pin && pin_configured)
  422. ? PINUVDisposition::kNoTokenInternalUVPINFallback
  423. : PINUVDisposition::kNoTokenInternalUV;
  424. }
  425. if ((can_collect_pin && pin_configured) || CanGetUvToken()) {
  426. return PINUVDisposition::kGetToken;
  427. }
  428. return PINUVDisposition::kUnsatisfiable;
  429. }
  430. void FidoDeviceAuthenticator::GetCredentialsMetadata(
  431. const pin::TokenResponse& pin_token,
  432. GetCredentialsMetadataCallback callback) {
  433. DCHECK(Options()->supports_credential_management ||
  434. Options()->supports_credential_management_preview);
  435. DCHECK(chosen_pin_uv_auth_protocol_ == pin_token.protocol());
  436. RunOperation<CredentialManagementRequest, CredentialsMetadataResponse>(
  437. CredentialManagementRequest::ForGetCredsMetadata(
  438. GetCredentialManagementRequestVersion(*Options()), pin_token),
  439. std::move(callback), base::BindOnce(&CredentialsMetadataResponse::Parse));
  440. }
  441. struct FidoDeviceAuthenticator::EnumerateCredentialsState {
  442. explicit EnumerateCredentialsState(pin::TokenResponse pin_token_)
  443. : pin_token(pin_token_) {}
  444. EnumerateCredentialsState(EnumerateCredentialsState&&) = default;
  445. EnumerateCredentialsState& operator=(EnumerateCredentialsState&&) = default;
  446. pin::TokenResponse pin_token;
  447. size_t rp_count = 0;
  448. size_t current_rp = 0;
  449. size_t current_rp_credential_count = 0;
  450. FidoDeviceAuthenticator::EnumerateCredentialsCallback callback;
  451. std::vector<AggregatedEnumerateCredentialsResponse> responses;
  452. std::vector<std::array<uint8_t, kRpIdHashLength>> rp_id_hashes;
  453. };
  454. void FidoDeviceAuthenticator::EnumerateCredentials(
  455. const pin::TokenResponse& pin_token,
  456. EnumerateCredentialsCallback callback) {
  457. DCHECK(Options()->supports_credential_management ||
  458. Options()->supports_credential_management_preview);
  459. DCHECK(chosen_pin_uv_auth_protocol_ == pin_token.protocol());
  460. EnumerateCredentialsState state(pin_token);
  461. state.callback = std::move(callback);
  462. RunOperation<CredentialManagementRequest, EnumerateRPsResponse>(
  463. CredentialManagementRequest::ForEnumerateRPsBegin(
  464. GetCredentialManagementRequestVersion(*Options()), pin_token),
  465. base::BindOnce(&FidoDeviceAuthenticator::OnEnumerateRPsDone,
  466. weak_factory_.GetWeakPtr(), std::move(state)),
  467. base::BindOnce(&EnumerateRPsResponse::Parse, /*expect_rp_count=*/true),
  468. &EnumerateRPsResponse::StringFixupPredicate);
  469. }
  470. // TaskClearProxy interposes |callback| and resets |task_| before it runs.
  471. template <typename... Args>
  472. void FidoDeviceAuthenticator::TaskClearProxy(
  473. base::OnceCallback<void(Args...)> callback,
  474. Args... args) {
  475. DCHECK(task_);
  476. DCHECK(!operation_);
  477. task_.reset();
  478. std::move(callback).Run(std::forward<Args>(args)...);
  479. }
  480. // OperationClearProxy interposes |callback| and resets |operation_| before it
  481. // runs.
  482. template <typename... Args>
  483. void FidoDeviceAuthenticator::OperationClearProxy(
  484. base::OnceCallback<void(Args...)> callback,
  485. Args... args) {
  486. DCHECK(operation_);
  487. DCHECK(!task_);
  488. operation_.reset();
  489. std::move(callback).Run(std::forward<Args>(args)...);
  490. }
  491. // RunTask starts a |FidoTask| and ensures that |task_| is reset when the given
  492. // callback is called.
  493. template <typename Task, typename Response, typename... RequestArgs>
  494. void FidoDeviceAuthenticator::RunTask(
  495. RequestArgs&&... request_args,
  496. base::OnceCallback<void(CtapDeviceResponseCode, absl::optional<Response>)>
  497. callback) {
  498. DCHECK(!task_);
  499. DCHECK(!operation_);
  500. DCHECK(device_->SupportedProtocolIsInitialized())
  501. << "InitializeAuthenticator() must be called first.";
  502. task_ = std::make_unique<Task>(
  503. device_.get(), std::forward<RequestArgs>(request_args)...,
  504. base::BindOnce(
  505. &FidoDeviceAuthenticator::TaskClearProxy<CtapDeviceResponseCode,
  506. absl::optional<Response>>,
  507. weak_factory_.GetWeakPtr(), std::move(callback)));
  508. }
  509. // RunOperation starts a |Ctap2DeviceOperation| and ensures that |operation_| is
  510. // reset when the given completion callback is called.
  511. template <typename Request, typename Response>
  512. void FidoDeviceAuthenticator::RunOperation(
  513. Request request,
  514. base::OnceCallback<void(CtapDeviceResponseCode, absl::optional<Response>)>
  515. callback,
  516. base::OnceCallback<
  517. absl::optional<Response>(const absl::optional<cbor::Value>&)> parser,
  518. bool (*string_fixup_predicate)(const std::vector<const cbor::Value*>&)) {
  519. DCHECK(!task_);
  520. DCHECK(!operation_);
  521. DCHECK(device_->SupportedProtocolIsInitialized())
  522. << "InitializeAuthenticator() must be called first.";
  523. operation_ = std::make_unique<Ctap2DeviceOperation<Request, Response>>(
  524. device_.get(), std::move(request),
  525. base::BindOnce(&FidoDeviceAuthenticator::OperationClearProxy<
  526. CtapDeviceResponseCode, absl::optional<Response>>,
  527. weak_factory_.GetWeakPtr(), std::move(callback)),
  528. std::move(parser), string_fixup_predicate);
  529. operation_->Start();
  530. }
  531. void FidoDeviceAuthenticator::OnEnumerateRPsDone(
  532. EnumerateCredentialsState state,
  533. CtapDeviceResponseCode status,
  534. absl::optional<EnumerateRPsResponse> response) {
  535. DCHECK_EQ(state.rp_id_hashes.size(), state.responses.size());
  536. DCHECK_LE(state.rp_id_hashes.size(), state.rp_count);
  537. if (status != CtapDeviceResponseCode::kSuccess) {
  538. std::move(state.callback).Run(status, absl::nullopt);
  539. return;
  540. }
  541. if (state.rp_count == 0) {
  542. if (response->rp_count == 0) {
  543. std::move(state.callback).Run(status, std::move(state.responses));
  544. return;
  545. }
  546. state.rp_count = response->rp_count;
  547. }
  548. DCHECK(response->rp);
  549. DCHECK(response->rp_id_hash);
  550. state.rp_id_hashes.push_back(*response->rp_id_hash);
  551. state.responses.emplace_back(*response->rp);
  552. if (state.rp_id_hashes.size() < state.rp_count) {
  553. // Get the next RP.
  554. RunOperation<CredentialManagementRequest, EnumerateRPsResponse>(
  555. CredentialManagementRequest::ForEnumerateRPsGetNext(
  556. GetCredentialManagementRequestVersion(*Options())),
  557. base::BindOnce(&FidoDeviceAuthenticator::OnEnumerateRPsDone,
  558. weak_factory_.GetWeakPtr(), std::move(state)),
  559. base::BindOnce(&EnumerateRPsResponse::Parse, /*expect_rp_count=*/false),
  560. &EnumerateRPsResponse::StringFixupPredicate);
  561. return;
  562. }
  563. auto request = CredentialManagementRequest::ForEnumerateCredentialsBegin(
  564. GetCredentialManagementRequestVersion(*Options()), state.pin_token,
  565. state.rp_id_hashes.front());
  566. RunOperation<CredentialManagementRequest, EnumerateCredentialsResponse>(
  567. std::move(request),
  568. base::BindOnce(&FidoDeviceAuthenticator::OnEnumerateCredentialsDone,
  569. weak_factory_.GetWeakPtr(), std::move(state)),
  570. base::BindOnce(&EnumerateCredentialsResponse::Parse,
  571. /*expect_credential_count=*/true),
  572. &EnumerateCredentialsResponse::StringFixupPredicate);
  573. }
  574. void FidoDeviceAuthenticator::OnEnumerateCredentialsDone(
  575. EnumerateCredentialsState state,
  576. CtapDeviceResponseCode status,
  577. absl::optional<EnumerateCredentialsResponse> response) {
  578. DCHECK_EQ(state.rp_id_hashes.size(), state.responses.size());
  579. DCHECK_EQ(state.rp_id_hashes.size(), state.rp_count);
  580. DCHECK_LT(state.current_rp, state.rp_count);
  581. if (status != CtapDeviceResponseCode::kSuccess) {
  582. std::move(state.callback).Run(status, absl::nullopt);
  583. return;
  584. }
  585. if (state.current_rp_credential_count == 0) {
  586. // First credential for this RP.
  587. DCHECK_GT(response->credential_count, 0u);
  588. state.current_rp_credential_count = response->credential_count;
  589. }
  590. AggregatedEnumerateCredentialsResponse& current_aggregated_response =
  591. state.responses.at(state.current_rp);
  592. current_aggregated_response.credentials.push_back(std::move(*response));
  593. if (current_aggregated_response.credentials.size() <
  594. state.current_rp_credential_count) {
  595. // Fetch the next credential for this RP.
  596. RunOperation<CredentialManagementRequest, EnumerateCredentialsResponse>(
  597. CredentialManagementRequest::ForEnumerateCredentialsGetNext(
  598. GetCredentialManagementRequestVersion(*Options())),
  599. base::BindOnce(&FidoDeviceAuthenticator::OnEnumerateCredentialsDone,
  600. weak_factory_.GetWeakPtr(), std::move(state)),
  601. base::BindOnce(&EnumerateCredentialsResponse::Parse,
  602. /*expect_credential_count=*/false),
  603. &EnumerateCredentialsResponse::StringFixupPredicate);
  604. return;
  605. }
  606. if (++state.current_rp < state.rp_count) {
  607. // Enumerate credentials for the next RP.
  608. state.current_rp_credential_count = 0;
  609. auto request = CredentialManagementRequest::ForEnumerateCredentialsBegin(
  610. GetCredentialManagementRequestVersion(*Options()), state.pin_token,
  611. state.rp_id_hashes.at(state.current_rp));
  612. RunOperation<CredentialManagementRequest, EnumerateCredentialsResponse>(
  613. std::move(request),
  614. base::BindOnce(&FidoDeviceAuthenticator::OnEnumerateCredentialsDone,
  615. weak_factory_.GetWeakPtr(), std::move(state)),
  616. base::BindOnce(&EnumerateCredentialsResponse::Parse,
  617. /*expect_credential_count=*/true),
  618. &EnumerateCredentialsResponse::StringFixupPredicate);
  619. return;
  620. }
  621. std::move(state.callback)
  622. .Run(CtapDeviceResponseCode::kSuccess, std::move(state.responses));
  623. return;
  624. }
  625. void FidoDeviceAuthenticator::DeleteCredential(
  626. const pin::TokenResponse& pin_token,
  627. const PublicKeyCredentialDescriptor& credential_id,
  628. DeleteCredentialCallback callback) {
  629. DCHECK(Options()->supports_credential_management ||
  630. Options()->supports_credential_management_preview);
  631. DCHECK(chosen_pin_uv_auth_protocol_ == pin_token.protocol());
  632. RunOperation<CredentialManagementRequest, DeleteCredentialResponse>(
  633. CredentialManagementRequest::ForDeleteCredential(
  634. GetCredentialManagementRequestVersion(*Options()), pin_token,
  635. credential_id),
  636. std::move(callback), base::BindOnce(&DeleteCredentialResponse::Parse),
  637. /*string_fixup_predicate=*/nullptr);
  638. }
  639. bool FidoDeviceAuthenticator::SupportsUpdateUserInformation() const {
  640. return device_->device_info() &&
  641. device_->device_info()->SupportsAtLeast(Ctap2Version::kCtap2_1);
  642. }
  643. void FidoDeviceAuthenticator::UpdateUserInformation(
  644. const pin::TokenResponse& pin_token,
  645. const PublicKeyCredentialDescriptor& credential_id,
  646. const PublicKeyCredentialUserEntity& updated_user,
  647. UpdateUserInformationCallback callback) {
  648. DCHECK(Options()->supports_credential_management ||
  649. Options()->supports_credential_management_preview);
  650. DCHECK(chosen_pin_uv_auth_protocol_ == pin_token.protocol());
  651. RunOperation<CredentialManagementRequest, UpdateUserInformationResponse>(
  652. CredentialManagementRequest::ForUpdateUserInformation(
  653. GetCredentialManagementRequestVersion(*Options()), pin_token,
  654. credential_id, updated_user),
  655. std::move(callback),
  656. base::BindOnce(&UpdateUserInformationResponse::Parse),
  657. /*string_fixup_predicate=*/nullptr);
  658. }
  659. void FidoDeviceAuthenticator::GetModality(BioEnrollmentCallback callback) {
  660. RunOperation<BioEnrollmentRequest, BioEnrollmentResponse>(
  661. BioEnrollmentRequest::ForGetModality(
  662. GetBioEnrollmentRequestVersion(*Options())),
  663. std::move(callback), base::BindOnce(&BioEnrollmentResponse::Parse));
  664. }
  665. void FidoDeviceAuthenticator::GetSensorInfo(BioEnrollmentCallback callback) {
  666. RunOperation<BioEnrollmentRequest, BioEnrollmentResponse>(
  667. BioEnrollmentRequest::ForGetSensorInfo(
  668. GetBioEnrollmentRequestVersion(*Options())),
  669. std::move(callback), base::BindOnce(&BioEnrollmentResponse::Parse));
  670. }
  671. void FidoDeviceAuthenticator::BioEnrollFingerprint(
  672. const pin::TokenResponse& pin_token,
  673. absl::optional<std::vector<uint8_t>> template_id,
  674. BioEnrollmentCallback callback) {
  675. DCHECK(chosen_pin_uv_auth_protocol_ == pin_token.protocol());
  676. RunOperation<BioEnrollmentRequest, BioEnrollmentResponse>(
  677. template_id ? BioEnrollmentRequest::ForEnrollNextSample(
  678. GetBioEnrollmentRequestVersion(*Options()),
  679. std::move(pin_token), std::move(*template_id))
  680. : BioEnrollmentRequest::ForEnrollBegin(
  681. GetBioEnrollmentRequestVersion(*Options()),
  682. std::move(pin_token)),
  683. std::move(callback), base::BindOnce(&BioEnrollmentResponse::Parse));
  684. }
  685. void FidoDeviceAuthenticator::BioEnrollRename(
  686. const pin::TokenResponse& pin_token,
  687. std::vector<uint8_t> id,
  688. std::string name,
  689. BioEnrollmentCallback callback) {
  690. DCHECK(chosen_pin_uv_auth_protocol_ == pin_token.protocol());
  691. RunOperation<BioEnrollmentRequest, BioEnrollmentResponse>(
  692. BioEnrollmentRequest::ForRename(
  693. GetBioEnrollmentRequestVersion(*Options()), pin_token, std::move(id),
  694. std::move(name)),
  695. std::move(callback), base::BindOnce(&BioEnrollmentResponse::Parse));
  696. }
  697. void FidoDeviceAuthenticator::BioEnrollDelete(
  698. const pin::TokenResponse& pin_token,
  699. std::vector<uint8_t> template_id,
  700. BioEnrollmentCallback callback) {
  701. DCHECK(chosen_pin_uv_auth_protocol_ == pin_token.protocol());
  702. RunOperation<BioEnrollmentRequest, BioEnrollmentResponse>(
  703. BioEnrollmentRequest::ForDelete(
  704. GetBioEnrollmentRequestVersion(*Options()), pin_token,
  705. std::move(template_id)),
  706. std::move(callback), base::BindOnce(&BioEnrollmentResponse::Parse));
  707. }
  708. void FidoDeviceAuthenticator::BioEnrollCancel(BioEnrollmentCallback callback) {
  709. RunOperation<BioEnrollmentRequest, BioEnrollmentResponse>(
  710. BioEnrollmentRequest::ForCancel(
  711. GetBioEnrollmentRequestVersion(*Options())),
  712. std::move(callback), base::BindOnce(&BioEnrollmentResponse::Parse));
  713. }
  714. void FidoDeviceAuthenticator::BioEnrollEnumerate(
  715. const pin::TokenResponse& pin_token,
  716. BioEnrollmentCallback callback) {
  717. DCHECK(chosen_pin_uv_auth_protocol_ == pin_token.protocol());
  718. RunOperation<BioEnrollmentRequest, BioEnrollmentResponse>(
  719. BioEnrollmentRequest::ForEnumerate(
  720. GetBioEnrollmentRequestVersion(*Options()), std::move(pin_token)),
  721. std::move(callback), base::BindOnce(&BioEnrollmentResponse::Parse));
  722. }
  723. void FidoDeviceAuthenticator::WriteLargeBlob(
  724. LargeBlob large_blob,
  725. const LargeBlobKey& large_blob_key,
  726. const absl::optional<pin::TokenResponse> pin_uv_auth_token,
  727. base::OnceCallback<void(CtapDeviceResponseCode)> callback) {
  728. auto pin_uv_auth_token_copy = pin_uv_auth_token;
  729. FetchLargeBlobArray(
  730. pin_uv_auth_token_copy, LargeBlobArrayReader(),
  731. base::BindOnce(&FidoDeviceAuthenticator::OnHaveLargeBlobArrayForWrite,
  732. weak_factory_.GetWeakPtr(), large_blob, large_blob_key,
  733. std::move(pin_uv_auth_token), std::move(callback)));
  734. }
  735. void FidoDeviceAuthenticator::ReadLargeBlob(
  736. const std::vector<LargeBlobKey>& large_blob_keys,
  737. const absl::optional<pin::TokenResponse> pin_uv_auth_token,
  738. LargeBlobReadCallback callback) {
  739. DCHECK(!large_blob_keys.empty());
  740. FetchLargeBlobArray(
  741. std::move(pin_uv_auth_token), LargeBlobArrayReader(),
  742. base::BindOnce(&FidoDeviceAuthenticator::OnHaveLargeBlobArrayForRead,
  743. weak_factory_.GetWeakPtr(), large_blob_keys,
  744. std::move(callback)));
  745. }
  746. void FidoDeviceAuthenticator::FetchLargeBlobArray(
  747. const absl::optional<pin::TokenResponse> pin_uv_auth_token,
  748. LargeBlobArrayReader large_blob_array_reader,
  749. base::OnceCallback<void(CtapDeviceResponseCode,
  750. absl::optional<LargeBlobArrayReader>)> callback) {
  751. size_t bytes_to_read = max_large_blob_fragment_length();
  752. LargeBlobsRequest request =
  753. LargeBlobsRequest::ForRead(bytes_to_read, large_blob_array_reader.size());
  754. RunOperation<LargeBlobsRequest, LargeBlobsResponse>(
  755. std::move(request),
  756. base::BindOnce(&FidoDeviceAuthenticator::OnReadLargeBlobFragment,
  757. weak_factory_.GetWeakPtr(), bytes_to_read,
  758. std::move(large_blob_array_reader),
  759. std::move(pin_uv_auth_token), std::move(callback)),
  760. base::BindOnce(&LargeBlobsResponse::ParseForRead, bytes_to_read));
  761. }
  762. void FidoDeviceAuthenticator::OnReadLargeBlobFragment(
  763. const size_t bytes_requested,
  764. LargeBlobArrayReader large_blob_array_reader,
  765. const absl::optional<pin::TokenResponse> pin_uv_auth_token,
  766. base::OnceCallback<void(CtapDeviceResponseCode,
  767. absl::optional<LargeBlobArrayReader>)> callback,
  768. CtapDeviceResponseCode status,
  769. absl::optional<LargeBlobsResponse> response) {
  770. if (status != CtapDeviceResponseCode::kSuccess) {
  771. std::move(callback).Run(status, absl::nullopt);
  772. return;
  773. }
  774. DCHECK(response && response->config());
  775. large_blob_array_reader.Append(*response->config());
  776. if (response->config()->size() == bytes_requested) {
  777. // More data may be available, read the next fragment.
  778. FetchLargeBlobArray(std::move(pin_uv_auth_token),
  779. std::move(large_blob_array_reader),
  780. std::move(callback));
  781. return;
  782. }
  783. std::move(callback).Run(CtapDeviceResponseCode::kSuccess,
  784. std::move(large_blob_array_reader));
  785. }
  786. void FidoDeviceAuthenticator::OnHaveLargeBlobArrayForWrite(
  787. LargeBlob large_blob,
  788. const LargeBlobKey& large_blob_key,
  789. const absl::optional<pin::TokenResponse> pin_uv_auth_token,
  790. base::OnceCallback<void(CtapDeviceResponseCode)> callback,
  791. CtapDeviceResponseCode status,
  792. absl::optional<LargeBlobArrayReader> large_blob_array_reader) {
  793. if (status != CtapDeviceResponseCode::kSuccess) {
  794. std::move(callback).Run(status);
  795. return;
  796. }
  797. absl::optional<std::vector<LargeBlobData>> large_blob_array =
  798. large_blob_array_reader->Materialize();
  799. if (!large_blob_array) {
  800. // The large blob array is corrupted. Replace it completely with a new one.
  801. // TODO(nsatragno): but maybe we want to do something else like trying
  802. // again? It might have been corrupted while transported. Decide when we
  803. // have hardware to test.
  804. large_blob_array.emplace();
  805. return;
  806. }
  807. auto existing_large_blob =
  808. std::find_if(large_blob_array->begin(), large_blob_array->end(),
  809. [&large_blob_key](const LargeBlobData& blob) {
  810. return blob.Decrypt(large_blob_key);
  811. });
  812. LargeBlobData new_large_blob_data(large_blob_key, std::move(large_blob));
  813. if (existing_large_blob != large_blob_array->end()) {
  814. *existing_large_blob = std::move(new_large_blob_data);
  815. } else {
  816. large_blob_array->emplace_back(std::move(new_large_blob_data));
  817. }
  818. LargeBlobArrayWriter writer(*large_blob_array);
  819. if (writer.size() >
  820. *device_->device_info()->max_serialized_large_blob_array) {
  821. std::move(callback).Run(CtapDeviceResponseCode::kCtap2ErrRequestTooLarge);
  822. return;
  823. }
  824. WriteLargeBlobArray(std::move(pin_uv_auth_token), std::move(writer),
  825. std::move(callback));
  826. }
  827. void FidoDeviceAuthenticator::WriteLargeBlobArray(
  828. const absl::optional<pin::TokenResponse> pin_uv_auth_token,
  829. LargeBlobArrayWriter large_blob_array_writer,
  830. base::OnceCallback<void(CtapDeviceResponseCode)> callback) {
  831. LargeBlobArrayFragment fragment =
  832. large_blob_array_writer.Pop(max_large_blob_fragment_length());
  833. LargeBlobsRequest request = LargeBlobsRequest::ForWrite(
  834. std::move(fragment), large_blob_array_writer.size());
  835. if (pin_uv_auth_token) {
  836. DCHECK(chosen_pin_uv_auth_protocol_ == pin_uv_auth_token->protocol());
  837. request.SetPinParam(*pin_uv_auth_token);
  838. }
  839. RunOperation<LargeBlobsRequest, LargeBlobsResponse>(
  840. std::move(request),
  841. base::BindOnce(&FidoDeviceAuthenticator::OnWriteLargeBlobFragment,
  842. weak_factory_.GetWeakPtr(),
  843. std::move(large_blob_array_writer),
  844. std::move(pin_uv_auth_token), std::move(callback)),
  845. base::BindOnce(&LargeBlobsResponse::ParseForWrite));
  846. }
  847. void FidoDeviceAuthenticator::OnWriteLargeBlobFragment(
  848. LargeBlobArrayWriter large_blob_array_writer,
  849. const absl::optional<pin::TokenResponse> pin_uv_auth_token,
  850. base::OnceCallback<void(CtapDeviceResponseCode)> callback,
  851. CtapDeviceResponseCode status,
  852. absl::optional<LargeBlobsResponse> response) {
  853. if (status != CtapDeviceResponseCode::kSuccess) {
  854. std::move(callback).Run(status);
  855. return;
  856. }
  857. if (large_blob_array_writer.has_remaining_fragments()) {
  858. WriteLargeBlobArray(std::move(pin_uv_auth_token),
  859. std::move(large_blob_array_writer),
  860. std::move(callback));
  861. return;
  862. }
  863. std::move(callback).Run(CtapDeviceResponseCode::kSuccess);
  864. }
  865. void FidoDeviceAuthenticator::OnHaveLargeBlobArrayForRead(
  866. const std::vector<LargeBlobKey>& large_blob_keys,
  867. LargeBlobReadCallback callback,
  868. CtapDeviceResponseCode status,
  869. absl::optional<LargeBlobArrayReader> large_blob_array_reader) {
  870. if (status != CtapDeviceResponseCode::kSuccess) {
  871. std::move(callback).Run(status, absl::nullopt);
  872. return;
  873. }
  874. absl::optional<std::vector<LargeBlobData>> large_blob_array =
  875. large_blob_array_reader->Materialize();
  876. if (!large_blob_array) {
  877. std::move(callback).Run(CtapDeviceResponseCode::kCtap2ErrIntegrityFailure,
  878. absl::nullopt);
  879. return;
  880. }
  881. std::vector<std::pair<LargeBlobKey, LargeBlob>> result;
  882. for (const LargeBlobData& blob : *large_blob_array) {
  883. for (const LargeBlobKey& key : large_blob_keys) {
  884. absl::optional<LargeBlob> plaintext = blob.Decrypt(key);
  885. if (plaintext) {
  886. result.emplace_back(std::make_pair(key, std::move(*plaintext)));
  887. break;
  888. }
  889. }
  890. }
  891. std::move(callback).Run(CtapDeviceResponseCode::kSuccess, std::move(result));
  892. }
  893. absl::optional<base::span<const int32_t>>
  894. FidoDeviceAuthenticator::GetAlgorithms() {
  895. if (device_->supported_protocol() == ProtocolVersion::kU2f) {
  896. static constexpr int32_t kU2fAlgorithms[1] = {
  897. static_cast<int32_t>(CoseAlgorithmIdentifier::kEs256)};
  898. return kU2fAlgorithms;
  899. }
  900. const absl::optional<AuthenticatorGetInfoResponse>& get_info_response =
  901. device_->device_info();
  902. if (get_info_response) {
  903. return get_info_response->algorithms;
  904. }
  905. return absl::nullopt;
  906. }
  907. bool FidoDeviceAuthenticator::DiscoverableCredentialStorageFull() const {
  908. return device_->device_info()->remaining_discoverable_credentials == 0u;
  909. }
  910. void FidoDeviceAuthenticator::Reset(ResetCallback callback) {
  911. DCHECK(device_->SupportedProtocolIsInitialized())
  912. << "InitializeAuthenticator() must be called first.";
  913. RunOperation<pin::ResetRequest, pin::ResetResponse>(
  914. pin::ResetRequest(), std::move(callback),
  915. base::BindOnce(&pin::ResetResponse::Parse));
  916. }
  917. void FidoDeviceAuthenticator::Cancel() {
  918. if (operation_) {
  919. operation_->Cancel();
  920. }
  921. if (task_) {
  922. task_->Cancel();
  923. }
  924. }
  925. std::string FidoDeviceAuthenticator::GetId() const {
  926. return device_->GetId();
  927. }
  928. std::string FidoDeviceAuthenticator::GetDisplayName() const {
  929. return device_->GetDisplayName();
  930. }
  931. ProtocolVersion FidoDeviceAuthenticator::SupportedProtocol() const {
  932. DCHECK(device_->SupportedProtocolIsInitialized());
  933. return device_->supported_protocol();
  934. }
  935. bool FidoDeviceAuthenticator::SupportsHMACSecretExtension() const {
  936. const absl::optional<AuthenticatorGetInfoResponse>& get_info_response =
  937. device_->device_info();
  938. return get_info_response && get_info_response->extensions &&
  939. base::Contains(*get_info_response->extensions, kExtensionHmacSecret);
  940. }
  941. bool FidoDeviceAuthenticator::SupportsEnterpriseAttestation() const {
  942. DCHECK(device_->SupportedProtocolIsInitialized());
  943. if (device_->supported_protocol() == ProtocolVersion::kU2f) {
  944. // U2F devices always "support" enterprise attestation because it turns into
  945. // a bit in the makeCredential command that is ignored if not supported.
  946. return true;
  947. }
  948. return options_ && options_->enterprise_attestation;
  949. }
  950. bool FidoDeviceAuthenticator::SupportsCredBlobOfSize(size_t num_bytes) const {
  951. const absl::optional<AuthenticatorGetInfoResponse>& get_info_response =
  952. device_->device_info();
  953. return get_info_response && get_info_response->max_cred_blob_length &&
  954. num_bytes <= get_info_response->max_cred_blob_length.value();
  955. }
  956. const absl::optional<AuthenticatorSupportedOptions>&
  957. FidoDeviceAuthenticator::Options() const {
  958. return options_;
  959. }
  960. absl::optional<FidoTransportProtocol>
  961. FidoDeviceAuthenticator::AuthenticatorTransport() const {
  962. return device_->DeviceTransport();
  963. }
  964. bool FidoDeviceAuthenticator::IsInPairingMode() const {
  965. return device_->IsInPairingMode();
  966. }
  967. bool FidoDeviceAuthenticator::IsPaired() const {
  968. return device_->IsPaired();
  969. }
  970. bool FidoDeviceAuthenticator::RequiresBlePairingPin() const {
  971. return device_->RequiresBlePairingPin();
  972. }
  973. void FidoDeviceAuthenticator::SetTaskForTesting(
  974. std::unique_ptr<FidoTask> task) {
  975. task_ = std::move(task);
  976. }
  977. void FidoDeviceAuthenticator::GetUvRetries(GetRetriesCallback callback) {
  978. DCHECK(Options());
  979. DCHECK(Options()->user_verification_availability !=
  980. UserVerificationAvailability::kNotSupported);
  981. DCHECK(chosen_pin_uv_auth_protocol_);
  982. RunOperation<pin::UvRetriesRequest, pin::RetriesResponse>(
  983. pin::UvRetriesRequest{*chosen_pin_uv_auth_protocol_}, std::move(callback),
  984. base::BindOnce(&pin::RetriesResponse::ParseUvRetries));
  985. }
  986. bool FidoDeviceAuthenticator::CanGetUvToken() {
  987. return options_->user_verification_availability ==
  988. AuthenticatorSupportedOptions::UserVerificationAvailability::
  989. kSupportedAndConfigured &&
  990. options_->supports_pin_uv_auth_token;
  991. }
  992. void FidoDeviceAuthenticator::GetUvToken(
  993. std::vector<pin::Permissions> permissions,
  994. absl::optional<std::string> rp_id,
  995. GetTokenCallback callback) {
  996. GetEphemeralKey(
  997. base::BindOnce(&FidoDeviceAuthenticator::OnHaveEphemeralKeyForUvToken,
  998. weak_factory_.GetWeakPtr(), std::move(rp_id),
  999. std::move(permissions), std::move(callback)));
  1000. }
  1001. uint32_t FidoDeviceAuthenticator::CurrentMinPINLength() {
  1002. return ForcePINChange() ? kMinPinLength : NewMinPINLength();
  1003. }
  1004. uint32_t FidoDeviceAuthenticator::NewMinPINLength() {
  1005. return device()->device_info()->min_pin_length.value_or(kMinPinLength);
  1006. }
  1007. bool FidoDeviceAuthenticator::ForcePINChange() {
  1008. return device()->device_info()->force_pin_change.value_or(false);
  1009. }
  1010. void FidoDeviceAuthenticator::OnHaveEphemeralKeyForUvToken(
  1011. absl::optional<std::string> rp_id,
  1012. std::vector<pin::Permissions> permissions,
  1013. GetTokenCallback callback,
  1014. CtapDeviceResponseCode status,
  1015. absl::optional<pin::KeyAgreementResponse> key) {
  1016. if (status != CtapDeviceResponseCode::kSuccess) {
  1017. std::move(callback).Run(status, absl::nullopt);
  1018. return;
  1019. }
  1020. DCHECK(key);
  1021. pin::UvTokenRequest request(*chosen_pin_uv_auth_protocol_, *key,
  1022. std::move(rp_id), permissions);
  1023. std::vector<uint8_t> shared_key = request.shared_key();
  1024. RunOperation<pin::UvTokenRequest, pin::TokenResponse>(
  1025. std::move(request), std::move(callback),
  1026. base::BindOnce(&pin::TokenResponse::Parse, *chosen_pin_uv_auth_protocol_,
  1027. std::move(shared_key)));
  1028. }
  1029. size_t FidoDeviceAuthenticator::max_large_blob_fragment_length() {
  1030. return device_->device_info()->max_msg_size
  1031. ? *device_->device_info()->max_msg_size -
  1032. kLargeBlobReadEncodingOverhead
  1033. : kLargeBlobDefaultMaxFragmentLength;
  1034. }
  1035. base::WeakPtr<FidoAuthenticator> FidoDeviceAuthenticator::GetWeakPtr() {
  1036. return weak_factory_.GetWeakPtr();
  1037. }
  1038. } // namespace device