1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189 |
- // Copyright 2018 The Chromium Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style license that can be
- // found in the LICENSE file.
- #include "device/fido/fido_device_authenticator.h"
- #include <algorithm>
- #include <numeric>
- #include <utility>
- #include "base/bind.h"
- #include "base/containers/contains.h"
- #include "base/feature_list.h"
- #include "base/logging.h"
- #include "base/threading/sequenced_task_runner_handle.h"
- #include "build/build_config.h"
- #include "build/chromeos_buildflags.h"
- #include "device/fido/appid_exclude_probe_task.h"
- #include "device/fido/authenticator_supported_options.h"
- #include "device/fido/credential_management.h"
- #include "device/fido/ctap_authenticator_selection_request.h"
- #include "device/fido/ctap_get_assertion_request.h"
- #include "device/fido/ctap_make_credential_request.h"
- #include "device/fido/features.h"
- #include "device/fido/fido_constants.h"
- #include "device/fido/fido_device.h"
- #include "device/fido/fido_parsing_utils.h"
- #include "device/fido/fido_types.h"
- #include "device/fido/get_assertion_task.h"
- #include "device/fido/large_blob.h"
- #include "device/fido/make_credential_task.h"
- #include "device/fido/pin.h"
- #include "device/fido/u2f_command_constructor.h"
- #include "device/fido/virtual_fido_device.h"
- namespace device {
- using ClientPinAvailability =
- AuthenticatorSupportedOptions::ClientPinAvailability;
- using UserVerificationAvailability =
- AuthenticatorSupportedOptions::UserVerificationAvailability;
- namespace {
- // Helper method for determining correct bio enrollment version.
- BioEnrollmentRequest::Version GetBioEnrollmentRequestVersion(
- const AuthenticatorSupportedOptions& options) {
- DCHECK(options.bio_enrollment_availability_preview !=
- AuthenticatorSupportedOptions::BioEnrollmentAvailability::
- kNotSupported ||
- options.bio_enrollment_availability !=
- AuthenticatorSupportedOptions::BioEnrollmentAvailability::
- kNotSupported);
- return options.bio_enrollment_availability !=
- AuthenticatorSupportedOptions::BioEnrollmentAvailability::
- kNotSupported
- ? BioEnrollmentRequest::kDefault
- : BioEnrollmentRequest::kPreview;
- }
- CredentialManagementRequest::Version GetCredentialManagementRequestVersion(
- const AuthenticatorSupportedOptions& options) {
- DCHECK(options.supports_credential_management_preview ||
- options.supports_credential_management);
- return options.supports_credential_management
- ? CredentialManagementRequest::kDefault
- : CredentialManagementRequest::kPreview;
- }
- } // namespace
- FidoDeviceAuthenticator::FidoDeviceAuthenticator(
- std::unique_ptr<FidoDevice> device)
- : device_(std::move(device)) {}
- FidoDeviceAuthenticator::~FidoDeviceAuthenticator() = default;
- void FidoDeviceAuthenticator::InitializeAuthenticator(
- base::OnceClosure callback) {
- base::SequencedTaskRunnerHandle::Get()->PostTask(
- FROM_HERE,
- base::BindOnce(
- &FidoDevice::DiscoverSupportedProtocolAndDeviceInfo,
- device()->GetWeakPtr(),
- base::BindOnce(&FidoDeviceAuthenticator::InitializeAuthenticatorDone,
- weak_factory_.GetWeakPtr(), std::move(callback))));
- }
- void FidoDeviceAuthenticator::InitializeAuthenticatorDone(
- base::OnceClosure callback) {
- DCHECK(!options_);
- switch (device_->supported_protocol()) {
- case ProtocolVersion::kU2f:
- options_ = AuthenticatorSupportedOptions();
- break;
- case ProtocolVersion::kCtap2:
- DCHECK(device_->device_info()) << "uninitialized device";
- options_ = device_->device_info()->options;
- if (device_->device_info()->pin_protocols) {
- DCHECK(!device_->device_info()->pin_protocols->empty());
- // Choose the highest supported version.
- chosen_pin_uv_auth_protocol_ =
- *(device_->device_info()->pin_protocols->end() - 1);
- }
- break;
- case ProtocolVersion::kUnknown:
- NOTREACHED() << "uninitialized device";
- options_ = AuthenticatorSupportedOptions();
- }
- std::move(callback).Run();
- }
- void FidoDeviceAuthenticator::ExcludeAppIdCredentialsBeforeMakeCredential(
- CtapMakeCredentialRequest request,
- MakeCredentialOptions options,
- base::OnceCallback<void(CtapDeviceResponseCode, absl::optional<bool>)>
- callback) {
- // If the device (or request) is U2F-only then |MakeCredential| will handle
- // the AppID-excluded credentials, if any. There's no interaction with PUATs
- // to worry about because U2F doesn't have them.
- //
- // (If the device is AlwaysUV then it should still support up=false requests
- // without a PUAT, so they aren't excluded here.)
- if (!MakeCredentialTask::WillUseCTAP2(device_.get(), request, options) ||
- device_->NoSilentRequests()) {
- std::move(callback).Run(CtapDeviceResponseCode::kSuccess, absl::nullopt);
- return;
- }
- // This is a CTAP2 device. In CTAP 2.1, a PUAT is invalidated if a request is
- // made with a different RP ID, even if the PUAT isn't used on that request.
- // Therefore appidExclude probing has to happen before the PUAT is obtained.
- // For CTAP 2.0 devices we follow the same pattern, even though a PIN token
- // doesn't have that issue.
- RunTask<AppIdExcludeProbeTask, bool, CtapMakeCredentialRequest,
- MakeCredentialOptions>(std::move(request), std::move(options),
- std::move(callback));
- }
- void FidoDeviceAuthenticator::MakeCredential(
- CtapMakeCredentialRequest request,
- MakeCredentialOptions request_options,
- MakeCredentialCallback callback) {
- // If the authenticator has UV configured then UV will be required in
- // order to create a credential (as specified by CTAP 2.0), even if
- // user-verification is "discouraged". However, if the request is U2F-only
- // then that doesn't apply and UV must be set to discouraged so that the
- // request can be translated to U2F.
- if (!request.pin_auth &&
- options_->user_verification_availability ==
- UserVerificationAvailability::kSupportedAndConfigured &&
- !options_->make_cred_uv_not_required &&
- !request_options.make_u2f_api_credential) {
- request.user_verification = UserVerificationRequirement::kRequired;
- } else {
- request.user_verification = UserVerificationRequirement::kDiscouraged;
- }
- RunTask<MakeCredentialTask, AuthenticatorMakeCredentialResponse,
- CtapMakeCredentialRequest, MakeCredentialOptions>(
- std::move(request), std::move(request_options), std::move(callback));
- }
- void FidoDeviceAuthenticator::GetAssertion(CtapGetAssertionRequest request,
- CtapGetAssertionOptions options,
- GetAssertionCallback callback) {
- if (!options.prf_inputs.empty()) {
- GetEphemeralKey(base::BindOnce(
- &FidoDeviceAuthenticator::OnHaveEphemeralKeyForGetAssertion,
- weak_factory_.GetWeakPtr(), std::move(request), std::move(options),
- std::move(callback)));
- return;
- }
- DoGetAssertion(std::move(request), std::move(options), std::move(callback));
- }
- void FidoDeviceAuthenticator::OnHaveEphemeralKeyForGetAssertion(
- CtapGetAssertionRequest request,
- CtapGetAssertionOptions options,
- GetAssertionCallback callback,
- CtapDeviceResponseCode status,
- absl::optional<pin::KeyAgreementResponse> key) {
- if (status != CtapDeviceResponseCode::kSuccess) {
- std::move(callback).Run(status, absl::nullopt);
- return;
- }
- options.pin_key_agreement = std::move(*key);
- DoGetAssertion(std::move(request), std::move(options), std::move(callback));
- }
- void FidoDeviceAuthenticator::DoGetAssertion(CtapGetAssertionRequest request,
- CtapGetAssertionOptions options,
- GetAssertionCallback callback) {
- if (!request.pin_auth &&
- options_->user_verification_availability ==
- UserVerificationAvailability::kSupportedAndConfigured &&
- request.user_verification != UserVerificationRequirement::kDiscouraged) {
- request.user_verification = UserVerificationRequirement::kRequired;
- } else {
- request.user_verification = UserVerificationRequirement::kDiscouraged;
- }
- RunTask<GetAssertionTask, AuthenticatorGetAssertionResponse,
- CtapGetAssertionRequest, CtapGetAssertionOptions>(
- std::move(request), std::move(options), std::move(callback));
- }
- void FidoDeviceAuthenticator::GetNextAssertion(GetAssertionCallback callback) {
- RunOperation<CtapGetNextAssertionRequest, AuthenticatorGetAssertionResponse>(
- CtapGetNextAssertionRequest(), std::move(callback),
- base::BindOnce(&ReadCTAPGetAssertionResponse, device_->DeviceTransport()),
- GetAssertionTask::StringFixupPredicate);
- }
- void FidoDeviceAuthenticator::GetTouch(base::OnceClosure callback) {
- if (device()->device_info() &&
- device()->device_info()->SupportsAtLeast(Ctap2Version::kCtap2_1)) {
- RunOperation<CtapAuthenticatorSelectionRequest, pin::EmptyResponse>(
- CtapAuthenticatorSelectionRequest(),
- base::BindOnce(
- [](std::string authenticator_id, base::OnceClosure callback,
- CtapDeviceResponseCode status,
- absl::optional<pin::EmptyResponse> _) {
- if (status == CtapDeviceResponseCode::kSuccess) {
- std::move(callback).Run();
- return;
- }
- FIDO_LOG(DEBUG) << "Ignoring status " << static_cast<int>(status)
- << " from " << authenticator_id;
- },
- GetId(), std::move(callback)),
- base::BindOnce(&pin::EmptyResponse::Parse));
- return;
- }
- MakeCredential(
- MakeCredentialTask::GetTouchRequest(device()), MakeCredentialOptions(),
- base::BindOnce(
- [](std::string authenticator_id, base::OnceCallback<void()> callback,
- CtapDeviceResponseCode status,
- absl::optional<AuthenticatorMakeCredentialResponse>) {
- // If the device didn't understand/process the request it may
- // fail immediately. Rather than count that as a touch, ignore
- // those cases completely.
- if (status == CtapDeviceResponseCode::kSuccess ||
- status == CtapDeviceResponseCode::kCtap2ErrPinNotSet ||
- status == CtapDeviceResponseCode::kCtap2ErrPinInvalid ||
- status == CtapDeviceResponseCode::kCtap2ErrPinAuthInvalid) {
- std::move(callback).Run();
- return;
- }
- FIDO_LOG(DEBUG) << "Ignoring status " << static_cast<int>(status)
- << " from " << authenticator_id;
- },
- GetId(), std::move(callback)));
- }
- void FidoDeviceAuthenticator::GetPinRetries(GetRetriesCallback callback) {
- DCHECK(Options());
- DCHECK(Options()->client_pin_availability !=
- ClientPinAvailability::kNotSupported);
- DCHECK(chosen_pin_uv_auth_protocol_);
- RunOperation<pin::PinRetriesRequest, pin::RetriesResponse>(
- pin::PinRetriesRequest{*chosen_pin_uv_auth_protocol_},
- std::move(callback),
- base::BindOnce(&pin::RetriesResponse::ParsePinRetries));
- }
- void FidoDeviceAuthenticator::GetEphemeralKey(
- GetEphemeralKeyCallback callback) {
- DCHECK(Options());
- DCHECK(Options()->client_pin_availability !=
- ClientPinAvailability::kNotSupported ||
- Options()->supports_pin_uv_auth_token ||
- SupportsHMACSecretExtension());
- DCHECK(chosen_pin_uv_auth_protocol_);
- RunOperation<pin::KeyAgreementRequest, pin::KeyAgreementResponse>(
- pin::KeyAgreementRequest{*chosen_pin_uv_auth_protocol_},
- std::move(callback), base::BindOnce(&pin::KeyAgreementResponse::Parse));
- }
- void FidoDeviceAuthenticator::GetPINToken(
- std::string pin,
- std::vector<pin::Permissions> permissions,
- absl::optional<std::string> rp_id,
- GetTokenCallback callback) {
- DCHECK(Options());
- DCHECK(Options()->client_pin_availability !=
- ClientPinAvailability::kNotSupported);
- DCHECK_NE(permissions.size(), 0u);
- DCHECK(!((base::Contains(permissions, pin::Permissions::kMakeCredential)) ||
- base::Contains(permissions, pin::Permissions::kGetAssertion)) ||
- rp_id);
- GetEphemeralKey(base::BindOnce(
- &FidoDeviceAuthenticator::OnHaveEphemeralKeyForGetPINToken,
- weak_factory_.GetWeakPtr(), std::move(pin), std::move(permissions),
- std::move(rp_id), std::move(callback)));
- }
- void FidoDeviceAuthenticator::OnHaveEphemeralKeyForGetPINToken(
- std::string pin,
- std::vector<pin::Permissions> permissions,
- absl::optional<std::string> rp_id,
- GetTokenCallback callback,
- CtapDeviceResponseCode status,
- absl::optional<pin::KeyAgreementResponse> key) {
- if (status != CtapDeviceResponseCode::kSuccess) {
- std::move(callback).Run(status, absl::nullopt);
- return;
- }
- if (Options()->supports_pin_uv_auth_token) {
- pin::PinTokenWithPermissionsRequest request(*chosen_pin_uv_auth_protocol_,
- pin, *key, permissions, rp_id);
- std::vector<uint8_t> shared_key = request.shared_key();
- RunOperation<pin::PinTokenWithPermissionsRequest, pin::TokenResponse>(
- std::move(request), std::move(callback),
- base::BindOnce(&pin::TokenResponse::Parse,
- *chosen_pin_uv_auth_protocol_, std::move(shared_key)));
- return;
- }
- pin::PinTokenRequest request(*chosen_pin_uv_auth_protocol_, pin, *key);
- std::vector<uint8_t> shared_key = request.shared_key();
- RunOperation<pin::PinTokenRequest, pin::TokenResponse>(
- std::move(request), std::move(callback),
- base::BindOnce(&pin::TokenResponse::Parse, *chosen_pin_uv_auth_protocol_,
- std::move(shared_key)));
- }
- void FidoDeviceAuthenticator::SetPIN(const std::string& pin,
- SetPINCallback callback) {
- DCHECK(Options());
- DCHECK(Options()->client_pin_availability !=
- ClientPinAvailability::kNotSupported);
- GetEphemeralKey(base::BindOnce(
- &FidoDeviceAuthenticator::OnHaveEphemeralKeyForSetPIN,
- weak_factory_.GetWeakPtr(), std::move(pin), std::move(callback)));
- }
- void FidoDeviceAuthenticator::OnHaveEphemeralKeyForSetPIN(
- std::string pin,
- SetPINCallback callback,
- CtapDeviceResponseCode status,
- absl::optional<pin::KeyAgreementResponse> key) {
- if (status != CtapDeviceResponseCode::kSuccess) {
- std::move(callback).Run(status, absl::nullopt);
- return;
- }
- RunOperation<pin::SetRequest, pin::EmptyResponse>(
- pin::SetRequest(*chosen_pin_uv_auth_protocol_, pin, *key),
- std::move(callback), base::BindOnce(&pin::EmptyResponse::Parse));
- }
- void FidoDeviceAuthenticator::ChangePIN(const std::string& old_pin,
- const std::string& new_pin,
- SetPINCallback callback) {
- DCHECK(Options());
- DCHECK(Options()->client_pin_availability !=
- ClientPinAvailability::kNotSupported);
- GetEphemeralKey(
- base::BindOnce(&FidoDeviceAuthenticator::OnHaveEphemeralKeyForChangePIN,
- weak_factory_.GetWeakPtr(), std::move(old_pin),
- std::move(new_pin), std::move(callback)));
- }
- void FidoDeviceAuthenticator::OnHaveEphemeralKeyForChangePIN(
- std::string old_pin,
- std::string new_pin,
- SetPINCallback callback,
- CtapDeviceResponseCode status,
- absl::optional<pin::KeyAgreementResponse> key) {
- if (status != CtapDeviceResponseCode::kSuccess) {
- std::move(callback).Run(status, absl::nullopt);
- return;
- }
- RunOperation<pin::ChangeRequest, pin::EmptyResponse>(
- pin::ChangeRequest(*chosen_pin_uv_auth_protocol_, old_pin, new_pin, *key),
- std::move(callback), base::BindOnce(&pin::EmptyResponse::Parse));
- }
- FidoAuthenticator::PINUVDisposition
- FidoDeviceAuthenticator::PINUVDispositionForMakeCredential(
- const CtapMakeCredentialRequest& request,
- const FidoRequestHandlerBase::Observer* observer) {
- DCHECK(device_->SupportedProtocolIsInitialized());
- DCHECK(options_);
- const bool can_collect_pin = observer && observer->SupportsPIN();
- const bool pin_supported = Options()->client_pin_availability !=
- ClientPinAvailability::kNotSupported;
- const bool pin_configured = Options()->client_pin_availability ==
- ClientPinAvailability::kSupportedAndPinSet;
- const bool uv_configured =
- Options()->user_verification_availability ==
- UserVerificationAvailability::kSupportedAndConfigured;
- // CTAP 2.0 requires a PIN for credential creation once a PIN has been set.
- // Thus, if fallback to U2F isn't possible, a PIN will be needed if set.
- const bool u2f_fallback_possible =
- device()->device_info() &&
- device()->device_info()->versions.contains(ProtocolVersion::kU2f) &&
- IsConvertibleToU2fRegisterCommand(request) &&
- !ShouldPreferCTAP2EvenIfItNeedsAPIN(request);
- // CTAP 2.1 authenticators on the other hand can indicate that they allow
- // credential creation with PIN or UV.
- const bool can_make_ctap2_credential_without_uv =
- request.user_verification == UserVerificationRequirement::kDiscouraged &&
- options_->make_cred_uv_not_required;
- const UserVerificationRequirement uv_requirement =
- (pin_configured && !u2f_fallback_possible &&
- !can_make_ctap2_credential_without_uv)
- ? UserVerificationRequirement::kRequired
- : request.user_verification;
- if (uv_requirement == UserVerificationRequirement::kDiscouraged ||
- (uv_requirement == UserVerificationRequirement::kPreferred &&
- ((!pin_configured || !can_collect_pin) && !uv_configured))) {
- return PINUVDisposition::kNoUV;
- }
- // Authenticators with built-in UV that don't support UV token should try
- // sending the request as-is with uv=true first.
- if (uv_configured && !CanGetUvToken()) {
- return (can_collect_pin && pin_supported)
- ? PINUVDisposition::kNoTokenInternalUVPINFallback
- : PINUVDisposition::kNoTokenInternalUV;
- }
- const bool can_get_token =
- (can_collect_pin && pin_supported) || CanGetUvToken();
- if (can_get_token) {
- return PINUVDisposition::kGetToken;
- }
- return PINUVDisposition::kUnsatisfiable;
- }
- FidoAuthenticator::PINUVDisposition
- FidoDeviceAuthenticator::PINUVDispositionForGetAssertion(
- const CtapGetAssertionRequest& request,
- const FidoRequestHandlerBase::Observer* observer) {
- // TODO(crbug.com/1149405): GetAssertion requests don't allow in-line UV
- // enrollment. Perhaps we should change this and align with MakeCredential
- // behavior.
- const bool can_collect_pin = observer && observer->SupportsPIN();
- const bool pin_configured = Options()->client_pin_availability ==
- ClientPinAvailability::kSupportedAndPinSet;
- const bool uv_configured =
- Options()->user_verification_availability ==
- UserVerificationAvailability::kSupportedAndConfigured;
- const UserVerificationRequirement uv_requirement =
- request.allow_list.empty() ? UserVerificationRequirement::kRequired
- : request.user_verification;
- if (uv_requirement == UserVerificationRequirement::kDiscouraged ||
- (uv_requirement == UserVerificationRequirement::kPreferred &&
- ((!pin_configured || !can_collect_pin) && !uv_configured))) {
- return PINUVDisposition::kNoUV;
- }
- // Authenticators with built-in UV that don't support UV token should try
- // sending the request as-is with uv=true first.
- if (uv_configured && !CanGetUvToken()) {
- return (can_collect_pin && pin_configured)
- ? PINUVDisposition::kNoTokenInternalUVPINFallback
- : PINUVDisposition::kNoTokenInternalUV;
- }
- if ((can_collect_pin && pin_configured) || CanGetUvToken()) {
- return PINUVDisposition::kGetToken;
- }
- return PINUVDisposition::kUnsatisfiable;
- }
- void FidoDeviceAuthenticator::GetCredentialsMetadata(
- const pin::TokenResponse& pin_token,
- GetCredentialsMetadataCallback callback) {
- DCHECK(Options()->supports_credential_management ||
- Options()->supports_credential_management_preview);
- DCHECK(chosen_pin_uv_auth_protocol_ == pin_token.protocol());
- RunOperation<CredentialManagementRequest, CredentialsMetadataResponse>(
- CredentialManagementRequest::ForGetCredsMetadata(
- GetCredentialManagementRequestVersion(*Options()), pin_token),
- std::move(callback), base::BindOnce(&CredentialsMetadataResponse::Parse));
- }
- struct FidoDeviceAuthenticator::EnumerateCredentialsState {
- explicit EnumerateCredentialsState(pin::TokenResponse pin_token_)
- : pin_token(pin_token_) {}
- EnumerateCredentialsState(EnumerateCredentialsState&&) = default;
- EnumerateCredentialsState& operator=(EnumerateCredentialsState&&) = default;
- pin::TokenResponse pin_token;
- size_t rp_count = 0;
- size_t current_rp = 0;
- size_t current_rp_credential_count = 0;
- FidoDeviceAuthenticator::EnumerateCredentialsCallback callback;
- std::vector<AggregatedEnumerateCredentialsResponse> responses;
- std::vector<std::array<uint8_t, kRpIdHashLength>> rp_id_hashes;
- };
- void FidoDeviceAuthenticator::EnumerateCredentials(
- const pin::TokenResponse& pin_token,
- EnumerateCredentialsCallback callback) {
- DCHECK(Options()->supports_credential_management ||
- Options()->supports_credential_management_preview);
- DCHECK(chosen_pin_uv_auth_protocol_ == pin_token.protocol());
- EnumerateCredentialsState state(pin_token);
- state.callback = std::move(callback);
- RunOperation<CredentialManagementRequest, EnumerateRPsResponse>(
- CredentialManagementRequest::ForEnumerateRPsBegin(
- GetCredentialManagementRequestVersion(*Options()), pin_token),
- base::BindOnce(&FidoDeviceAuthenticator::OnEnumerateRPsDone,
- weak_factory_.GetWeakPtr(), std::move(state)),
- base::BindOnce(&EnumerateRPsResponse::Parse, /*expect_rp_count=*/true),
- &EnumerateRPsResponse::StringFixupPredicate);
- }
- // TaskClearProxy interposes |callback| and resets |task_| before it runs.
- template <typename... Args>
- void FidoDeviceAuthenticator::TaskClearProxy(
- base::OnceCallback<void(Args...)> callback,
- Args... args) {
- DCHECK(task_);
- DCHECK(!operation_);
- task_.reset();
- std::move(callback).Run(std::forward<Args>(args)...);
- }
- // OperationClearProxy interposes |callback| and resets |operation_| before it
- // runs.
- template <typename... Args>
- void FidoDeviceAuthenticator::OperationClearProxy(
- base::OnceCallback<void(Args...)> callback,
- Args... args) {
- DCHECK(operation_);
- DCHECK(!task_);
- operation_.reset();
- std::move(callback).Run(std::forward<Args>(args)...);
- }
- // RunTask starts a |FidoTask| and ensures that |task_| is reset when the given
- // callback is called.
- template <typename Task, typename Response, typename... RequestArgs>
- void FidoDeviceAuthenticator::RunTask(
- RequestArgs&&... request_args,
- base::OnceCallback<void(CtapDeviceResponseCode, absl::optional<Response>)>
- callback) {
- DCHECK(!task_);
- DCHECK(!operation_);
- DCHECK(device_->SupportedProtocolIsInitialized())
- << "InitializeAuthenticator() must be called first.";
- task_ = std::make_unique<Task>(
- device_.get(), std::forward<RequestArgs>(request_args)...,
- base::BindOnce(
- &FidoDeviceAuthenticator::TaskClearProxy<CtapDeviceResponseCode,
- absl::optional<Response>>,
- weak_factory_.GetWeakPtr(), std::move(callback)));
- }
- // RunOperation starts a |Ctap2DeviceOperation| and ensures that |operation_| is
- // reset when the given completion callback is called.
- template <typename Request, typename Response>
- void FidoDeviceAuthenticator::RunOperation(
- Request request,
- base::OnceCallback<void(CtapDeviceResponseCode, absl::optional<Response>)>
- callback,
- base::OnceCallback<
- absl::optional<Response>(const absl::optional<cbor::Value>&)> parser,
- bool (*string_fixup_predicate)(const std::vector<const cbor::Value*>&)) {
- DCHECK(!task_);
- DCHECK(!operation_);
- DCHECK(device_->SupportedProtocolIsInitialized())
- << "InitializeAuthenticator() must be called first.";
- operation_ = std::make_unique<Ctap2DeviceOperation<Request, Response>>(
- device_.get(), std::move(request),
- base::BindOnce(&FidoDeviceAuthenticator::OperationClearProxy<
- CtapDeviceResponseCode, absl::optional<Response>>,
- weak_factory_.GetWeakPtr(), std::move(callback)),
- std::move(parser), string_fixup_predicate);
- operation_->Start();
- }
- void FidoDeviceAuthenticator::OnEnumerateRPsDone(
- EnumerateCredentialsState state,
- CtapDeviceResponseCode status,
- absl::optional<EnumerateRPsResponse> response) {
- DCHECK_EQ(state.rp_id_hashes.size(), state.responses.size());
- DCHECK_LE(state.rp_id_hashes.size(), state.rp_count);
- if (status != CtapDeviceResponseCode::kSuccess) {
- std::move(state.callback).Run(status, absl::nullopt);
- return;
- }
- if (state.rp_count == 0) {
- if (response->rp_count == 0) {
- std::move(state.callback).Run(status, std::move(state.responses));
- return;
- }
- state.rp_count = response->rp_count;
- }
- DCHECK(response->rp);
- DCHECK(response->rp_id_hash);
- state.rp_id_hashes.push_back(*response->rp_id_hash);
- state.responses.emplace_back(*response->rp);
- if (state.rp_id_hashes.size() < state.rp_count) {
- // Get the next RP.
- RunOperation<CredentialManagementRequest, EnumerateRPsResponse>(
- CredentialManagementRequest::ForEnumerateRPsGetNext(
- GetCredentialManagementRequestVersion(*Options())),
- base::BindOnce(&FidoDeviceAuthenticator::OnEnumerateRPsDone,
- weak_factory_.GetWeakPtr(), std::move(state)),
- base::BindOnce(&EnumerateRPsResponse::Parse, /*expect_rp_count=*/false),
- &EnumerateRPsResponse::StringFixupPredicate);
- return;
- }
- auto request = CredentialManagementRequest::ForEnumerateCredentialsBegin(
- GetCredentialManagementRequestVersion(*Options()), state.pin_token,
- state.rp_id_hashes.front());
- RunOperation<CredentialManagementRequest, EnumerateCredentialsResponse>(
- std::move(request),
- base::BindOnce(&FidoDeviceAuthenticator::OnEnumerateCredentialsDone,
- weak_factory_.GetWeakPtr(), std::move(state)),
- base::BindOnce(&EnumerateCredentialsResponse::Parse,
- /*expect_credential_count=*/true),
- &EnumerateCredentialsResponse::StringFixupPredicate);
- }
- void FidoDeviceAuthenticator::OnEnumerateCredentialsDone(
- EnumerateCredentialsState state,
- CtapDeviceResponseCode status,
- absl::optional<EnumerateCredentialsResponse> response) {
- DCHECK_EQ(state.rp_id_hashes.size(), state.responses.size());
- DCHECK_EQ(state.rp_id_hashes.size(), state.rp_count);
- DCHECK_LT(state.current_rp, state.rp_count);
- if (status != CtapDeviceResponseCode::kSuccess) {
- std::move(state.callback).Run(status, absl::nullopt);
- return;
- }
- if (state.current_rp_credential_count == 0) {
- // First credential for this RP.
- DCHECK_GT(response->credential_count, 0u);
- state.current_rp_credential_count = response->credential_count;
- }
- AggregatedEnumerateCredentialsResponse& current_aggregated_response =
- state.responses.at(state.current_rp);
- current_aggregated_response.credentials.push_back(std::move(*response));
- if (current_aggregated_response.credentials.size() <
- state.current_rp_credential_count) {
- // Fetch the next credential for this RP.
- RunOperation<CredentialManagementRequest, EnumerateCredentialsResponse>(
- CredentialManagementRequest::ForEnumerateCredentialsGetNext(
- GetCredentialManagementRequestVersion(*Options())),
- base::BindOnce(&FidoDeviceAuthenticator::OnEnumerateCredentialsDone,
- weak_factory_.GetWeakPtr(), std::move(state)),
- base::BindOnce(&EnumerateCredentialsResponse::Parse,
- /*expect_credential_count=*/false),
- &EnumerateCredentialsResponse::StringFixupPredicate);
- return;
- }
- if (++state.current_rp < state.rp_count) {
- // Enumerate credentials for the next RP.
- state.current_rp_credential_count = 0;
- auto request = CredentialManagementRequest::ForEnumerateCredentialsBegin(
- GetCredentialManagementRequestVersion(*Options()), state.pin_token,
- state.rp_id_hashes.at(state.current_rp));
- RunOperation<CredentialManagementRequest, EnumerateCredentialsResponse>(
- std::move(request),
- base::BindOnce(&FidoDeviceAuthenticator::OnEnumerateCredentialsDone,
- weak_factory_.GetWeakPtr(), std::move(state)),
- base::BindOnce(&EnumerateCredentialsResponse::Parse,
- /*expect_credential_count=*/true),
- &EnumerateCredentialsResponse::StringFixupPredicate);
- return;
- }
- std::move(state.callback)
- .Run(CtapDeviceResponseCode::kSuccess, std::move(state.responses));
- return;
- }
- void FidoDeviceAuthenticator::DeleteCredential(
- const pin::TokenResponse& pin_token,
- const PublicKeyCredentialDescriptor& credential_id,
- DeleteCredentialCallback callback) {
- DCHECK(Options()->supports_credential_management ||
- Options()->supports_credential_management_preview);
- DCHECK(chosen_pin_uv_auth_protocol_ == pin_token.protocol());
- RunOperation<CredentialManagementRequest, DeleteCredentialResponse>(
- CredentialManagementRequest::ForDeleteCredential(
- GetCredentialManagementRequestVersion(*Options()), pin_token,
- credential_id),
- std::move(callback), base::BindOnce(&DeleteCredentialResponse::Parse),
- /*string_fixup_predicate=*/nullptr);
- }
- bool FidoDeviceAuthenticator::SupportsUpdateUserInformation() const {
- return device_->device_info() &&
- device_->device_info()->SupportsAtLeast(Ctap2Version::kCtap2_1);
- }
- void FidoDeviceAuthenticator::UpdateUserInformation(
- const pin::TokenResponse& pin_token,
- const PublicKeyCredentialDescriptor& credential_id,
- const PublicKeyCredentialUserEntity& updated_user,
- UpdateUserInformationCallback callback) {
- DCHECK(Options()->supports_credential_management ||
- Options()->supports_credential_management_preview);
- DCHECK(chosen_pin_uv_auth_protocol_ == pin_token.protocol());
- RunOperation<CredentialManagementRequest, UpdateUserInformationResponse>(
- CredentialManagementRequest::ForUpdateUserInformation(
- GetCredentialManagementRequestVersion(*Options()), pin_token,
- credential_id, updated_user),
- std::move(callback),
- base::BindOnce(&UpdateUserInformationResponse::Parse),
- /*string_fixup_predicate=*/nullptr);
- }
- void FidoDeviceAuthenticator::GetModality(BioEnrollmentCallback callback) {
- RunOperation<BioEnrollmentRequest, BioEnrollmentResponse>(
- BioEnrollmentRequest::ForGetModality(
- GetBioEnrollmentRequestVersion(*Options())),
- std::move(callback), base::BindOnce(&BioEnrollmentResponse::Parse));
- }
- void FidoDeviceAuthenticator::GetSensorInfo(BioEnrollmentCallback callback) {
- RunOperation<BioEnrollmentRequest, BioEnrollmentResponse>(
- BioEnrollmentRequest::ForGetSensorInfo(
- GetBioEnrollmentRequestVersion(*Options())),
- std::move(callback), base::BindOnce(&BioEnrollmentResponse::Parse));
- }
- void FidoDeviceAuthenticator::BioEnrollFingerprint(
- const pin::TokenResponse& pin_token,
- absl::optional<std::vector<uint8_t>> template_id,
- BioEnrollmentCallback callback) {
- DCHECK(chosen_pin_uv_auth_protocol_ == pin_token.protocol());
- RunOperation<BioEnrollmentRequest, BioEnrollmentResponse>(
- template_id ? BioEnrollmentRequest::ForEnrollNextSample(
- GetBioEnrollmentRequestVersion(*Options()),
- std::move(pin_token), std::move(*template_id))
- : BioEnrollmentRequest::ForEnrollBegin(
- GetBioEnrollmentRequestVersion(*Options()),
- std::move(pin_token)),
- std::move(callback), base::BindOnce(&BioEnrollmentResponse::Parse));
- }
- void FidoDeviceAuthenticator::BioEnrollRename(
- const pin::TokenResponse& pin_token,
- std::vector<uint8_t> id,
- std::string name,
- BioEnrollmentCallback callback) {
- DCHECK(chosen_pin_uv_auth_protocol_ == pin_token.protocol());
- RunOperation<BioEnrollmentRequest, BioEnrollmentResponse>(
- BioEnrollmentRequest::ForRename(
- GetBioEnrollmentRequestVersion(*Options()), pin_token, std::move(id),
- std::move(name)),
- std::move(callback), base::BindOnce(&BioEnrollmentResponse::Parse));
- }
- void FidoDeviceAuthenticator::BioEnrollDelete(
- const pin::TokenResponse& pin_token,
- std::vector<uint8_t> template_id,
- BioEnrollmentCallback callback) {
- DCHECK(chosen_pin_uv_auth_protocol_ == pin_token.protocol());
- RunOperation<BioEnrollmentRequest, BioEnrollmentResponse>(
- BioEnrollmentRequest::ForDelete(
- GetBioEnrollmentRequestVersion(*Options()), pin_token,
- std::move(template_id)),
- std::move(callback), base::BindOnce(&BioEnrollmentResponse::Parse));
- }
- void FidoDeviceAuthenticator::BioEnrollCancel(BioEnrollmentCallback callback) {
- RunOperation<BioEnrollmentRequest, BioEnrollmentResponse>(
- BioEnrollmentRequest::ForCancel(
- GetBioEnrollmentRequestVersion(*Options())),
- std::move(callback), base::BindOnce(&BioEnrollmentResponse::Parse));
- }
- void FidoDeviceAuthenticator::BioEnrollEnumerate(
- const pin::TokenResponse& pin_token,
- BioEnrollmentCallback callback) {
- DCHECK(chosen_pin_uv_auth_protocol_ == pin_token.protocol());
- RunOperation<BioEnrollmentRequest, BioEnrollmentResponse>(
- BioEnrollmentRequest::ForEnumerate(
- GetBioEnrollmentRequestVersion(*Options()), std::move(pin_token)),
- std::move(callback), base::BindOnce(&BioEnrollmentResponse::Parse));
- }
- void FidoDeviceAuthenticator::WriteLargeBlob(
- LargeBlob large_blob,
- const LargeBlobKey& large_blob_key,
- const absl::optional<pin::TokenResponse> pin_uv_auth_token,
- base::OnceCallback<void(CtapDeviceResponseCode)> callback) {
- auto pin_uv_auth_token_copy = pin_uv_auth_token;
- FetchLargeBlobArray(
- pin_uv_auth_token_copy, LargeBlobArrayReader(),
- base::BindOnce(&FidoDeviceAuthenticator::OnHaveLargeBlobArrayForWrite,
- weak_factory_.GetWeakPtr(), large_blob, large_blob_key,
- std::move(pin_uv_auth_token), std::move(callback)));
- }
- void FidoDeviceAuthenticator::ReadLargeBlob(
- const std::vector<LargeBlobKey>& large_blob_keys,
- const absl::optional<pin::TokenResponse> pin_uv_auth_token,
- LargeBlobReadCallback callback) {
- DCHECK(!large_blob_keys.empty());
- FetchLargeBlobArray(
- std::move(pin_uv_auth_token), LargeBlobArrayReader(),
- base::BindOnce(&FidoDeviceAuthenticator::OnHaveLargeBlobArrayForRead,
- weak_factory_.GetWeakPtr(), large_blob_keys,
- std::move(callback)));
- }
- void FidoDeviceAuthenticator::FetchLargeBlobArray(
- const absl::optional<pin::TokenResponse> pin_uv_auth_token,
- LargeBlobArrayReader large_blob_array_reader,
- base::OnceCallback<void(CtapDeviceResponseCode,
- absl::optional<LargeBlobArrayReader>)> callback) {
- size_t bytes_to_read = max_large_blob_fragment_length();
- LargeBlobsRequest request =
- LargeBlobsRequest::ForRead(bytes_to_read, large_blob_array_reader.size());
- RunOperation<LargeBlobsRequest, LargeBlobsResponse>(
- std::move(request),
- base::BindOnce(&FidoDeviceAuthenticator::OnReadLargeBlobFragment,
- weak_factory_.GetWeakPtr(), bytes_to_read,
- std::move(large_blob_array_reader),
- std::move(pin_uv_auth_token), std::move(callback)),
- base::BindOnce(&LargeBlobsResponse::ParseForRead, bytes_to_read));
- }
- void FidoDeviceAuthenticator::OnReadLargeBlobFragment(
- const size_t bytes_requested,
- LargeBlobArrayReader large_blob_array_reader,
- const absl::optional<pin::TokenResponse> pin_uv_auth_token,
- base::OnceCallback<void(CtapDeviceResponseCode,
- absl::optional<LargeBlobArrayReader>)> callback,
- CtapDeviceResponseCode status,
- absl::optional<LargeBlobsResponse> response) {
- if (status != CtapDeviceResponseCode::kSuccess) {
- std::move(callback).Run(status, absl::nullopt);
- return;
- }
- DCHECK(response && response->config());
- large_blob_array_reader.Append(*response->config());
- if (response->config()->size() == bytes_requested) {
- // More data may be available, read the next fragment.
- FetchLargeBlobArray(std::move(pin_uv_auth_token),
- std::move(large_blob_array_reader),
- std::move(callback));
- return;
- }
- std::move(callback).Run(CtapDeviceResponseCode::kSuccess,
- std::move(large_blob_array_reader));
- }
- void FidoDeviceAuthenticator::OnHaveLargeBlobArrayForWrite(
- LargeBlob large_blob,
- const LargeBlobKey& large_blob_key,
- const absl::optional<pin::TokenResponse> pin_uv_auth_token,
- base::OnceCallback<void(CtapDeviceResponseCode)> callback,
- CtapDeviceResponseCode status,
- absl::optional<LargeBlobArrayReader> large_blob_array_reader) {
- if (status != CtapDeviceResponseCode::kSuccess) {
- std::move(callback).Run(status);
- return;
- }
- absl::optional<std::vector<LargeBlobData>> large_blob_array =
- large_blob_array_reader->Materialize();
- if (!large_blob_array) {
- // The large blob array is corrupted. Replace it completely with a new one.
- // TODO(nsatragno): but maybe we want to do something else like trying
- // again? It might have been corrupted while transported. Decide when we
- // have hardware to test.
- large_blob_array.emplace();
- return;
- }
- auto existing_large_blob =
- std::find_if(large_blob_array->begin(), large_blob_array->end(),
- [&large_blob_key](const LargeBlobData& blob) {
- return blob.Decrypt(large_blob_key);
- });
- LargeBlobData new_large_blob_data(large_blob_key, std::move(large_blob));
- if (existing_large_blob != large_blob_array->end()) {
- *existing_large_blob = std::move(new_large_blob_data);
- } else {
- large_blob_array->emplace_back(std::move(new_large_blob_data));
- }
- LargeBlobArrayWriter writer(*large_blob_array);
- if (writer.size() >
- *device_->device_info()->max_serialized_large_blob_array) {
- std::move(callback).Run(CtapDeviceResponseCode::kCtap2ErrRequestTooLarge);
- return;
- }
- WriteLargeBlobArray(std::move(pin_uv_auth_token), std::move(writer),
- std::move(callback));
- }
- void FidoDeviceAuthenticator::WriteLargeBlobArray(
- const absl::optional<pin::TokenResponse> pin_uv_auth_token,
- LargeBlobArrayWriter large_blob_array_writer,
- base::OnceCallback<void(CtapDeviceResponseCode)> callback) {
- LargeBlobArrayFragment fragment =
- large_blob_array_writer.Pop(max_large_blob_fragment_length());
- LargeBlobsRequest request = LargeBlobsRequest::ForWrite(
- std::move(fragment), large_blob_array_writer.size());
- if (pin_uv_auth_token) {
- DCHECK(chosen_pin_uv_auth_protocol_ == pin_uv_auth_token->protocol());
- request.SetPinParam(*pin_uv_auth_token);
- }
- RunOperation<LargeBlobsRequest, LargeBlobsResponse>(
- std::move(request),
- base::BindOnce(&FidoDeviceAuthenticator::OnWriteLargeBlobFragment,
- weak_factory_.GetWeakPtr(),
- std::move(large_blob_array_writer),
- std::move(pin_uv_auth_token), std::move(callback)),
- base::BindOnce(&LargeBlobsResponse::ParseForWrite));
- }
- void FidoDeviceAuthenticator::OnWriteLargeBlobFragment(
- LargeBlobArrayWriter large_blob_array_writer,
- const absl::optional<pin::TokenResponse> pin_uv_auth_token,
- base::OnceCallback<void(CtapDeviceResponseCode)> callback,
- CtapDeviceResponseCode status,
- absl::optional<LargeBlobsResponse> response) {
- if (status != CtapDeviceResponseCode::kSuccess) {
- std::move(callback).Run(status);
- return;
- }
- if (large_blob_array_writer.has_remaining_fragments()) {
- WriteLargeBlobArray(std::move(pin_uv_auth_token),
- std::move(large_blob_array_writer),
- std::move(callback));
- return;
- }
- std::move(callback).Run(CtapDeviceResponseCode::kSuccess);
- }
- void FidoDeviceAuthenticator::OnHaveLargeBlobArrayForRead(
- const std::vector<LargeBlobKey>& large_blob_keys,
- LargeBlobReadCallback callback,
- CtapDeviceResponseCode status,
- absl::optional<LargeBlobArrayReader> large_blob_array_reader) {
- if (status != CtapDeviceResponseCode::kSuccess) {
- std::move(callback).Run(status, absl::nullopt);
- return;
- }
- absl::optional<std::vector<LargeBlobData>> large_blob_array =
- large_blob_array_reader->Materialize();
- if (!large_blob_array) {
- std::move(callback).Run(CtapDeviceResponseCode::kCtap2ErrIntegrityFailure,
- absl::nullopt);
- return;
- }
- std::vector<std::pair<LargeBlobKey, LargeBlob>> result;
- for (const LargeBlobData& blob : *large_blob_array) {
- for (const LargeBlobKey& key : large_blob_keys) {
- absl::optional<LargeBlob> plaintext = blob.Decrypt(key);
- if (plaintext) {
- result.emplace_back(std::make_pair(key, std::move(*plaintext)));
- break;
- }
- }
- }
- std::move(callback).Run(CtapDeviceResponseCode::kSuccess, std::move(result));
- }
- absl::optional<base::span<const int32_t>>
- FidoDeviceAuthenticator::GetAlgorithms() {
- if (device_->supported_protocol() == ProtocolVersion::kU2f) {
- static constexpr int32_t kU2fAlgorithms[1] = {
- static_cast<int32_t>(CoseAlgorithmIdentifier::kEs256)};
- return kU2fAlgorithms;
- }
- const absl::optional<AuthenticatorGetInfoResponse>& get_info_response =
- device_->device_info();
- if (get_info_response) {
- return get_info_response->algorithms;
- }
- return absl::nullopt;
- }
- bool FidoDeviceAuthenticator::DiscoverableCredentialStorageFull() const {
- return device_->device_info()->remaining_discoverable_credentials == 0u;
- }
- void FidoDeviceAuthenticator::Reset(ResetCallback callback) {
- DCHECK(device_->SupportedProtocolIsInitialized())
- << "InitializeAuthenticator() must be called first.";
- RunOperation<pin::ResetRequest, pin::ResetResponse>(
- pin::ResetRequest(), std::move(callback),
- base::BindOnce(&pin::ResetResponse::Parse));
- }
- void FidoDeviceAuthenticator::Cancel() {
- if (operation_) {
- operation_->Cancel();
- }
- if (task_) {
- task_->Cancel();
- }
- }
- std::string FidoDeviceAuthenticator::GetId() const {
- return device_->GetId();
- }
- std::string FidoDeviceAuthenticator::GetDisplayName() const {
- return device_->GetDisplayName();
- }
- ProtocolVersion FidoDeviceAuthenticator::SupportedProtocol() const {
- DCHECK(device_->SupportedProtocolIsInitialized());
- return device_->supported_protocol();
- }
- bool FidoDeviceAuthenticator::SupportsHMACSecretExtension() const {
- const absl::optional<AuthenticatorGetInfoResponse>& get_info_response =
- device_->device_info();
- return get_info_response && get_info_response->extensions &&
- base::Contains(*get_info_response->extensions, kExtensionHmacSecret);
- }
- bool FidoDeviceAuthenticator::SupportsEnterpriseAttestation() const {
- DCHECK(device_->SupportedProtocolIsInitialized());
- if (device_->supported_protocol() == ProtocolVersion::kU2f) {
- // U2F devices always "support" enterprise attestation because it turns into
- // a bit in the makeCredential command that is ignored if not supported.
- return true;
- }
- return options_ && options_->enterprise_attestation;
- }
- bool FidoDeviceAuthenticator::SupportsCredBlobOfSize(size_t num_bytes) const {
- const absl::optional<AuthenticatorGetInfoResponse>& get_info_response =
- device_->device_info();
- return get_info_response && get_info_response->max_cred_blob_length &&
- num_bytes <= get_info_response->max_cred_blob_length.value();
- }
- const absl::optional<AuthenticatorSupportedOptions>&
- FidoDeviceAuthenticator::Options() const {
- return options_;
- }
- absl::optional<FidoTransportProtocol>
- FidoDeviceAuthenticator::AuthenticatorTransport() const {
- return device_->DeviceTransport();
- }
- bool FidoDeviceAuthenticator::IsInPairingMode() const {
- return device_->IsInPairingMode();
- }
- bool FidoDeviceAuthenticator::IsPaired() const {
- return device_->IsPaired();
- }
- bool FidoDeviceAuthenticator::RequiresBlePairingPin() const {
- return device_->RequiresBlePairingPin();
- }
- void FidoDeviceAuthenticator::SetTaskForTesting(
- std::unique_ptr<FidoTask> task) {
- task_ = std::move(task);
- }
- void FidoDeviceAuthenticator::GetUvRetries(GetRetriesCallback callback) {
- DCHECK(Options());
- DCHECK(Options()->user_verification_availability !=
- UserVerificationAvailability::kNotSupported);
- DCHECK(chosen_pin_uv_auth_protocol_);
- RunOperation<pin::UvRetriesRequest, pin::RetriesResponse>(
- pin::UvRetriesRequest{*chosen_pin_uv_auth_protocol_}, std::move(callback),
- base::BindOnce(&pin::RetriesResponse::ParseUvRetries));
- }
- bool FidoDeviceAuthenticator::CanGetUvToken() {
- return options_->user_verification_availability ==
- AuthenticatorSupportedOptions::UserVerificationAvailability::
- kSupportedAndConfigured &&
- options_->supports_pin_uv_auth_token;
- }
- void FidoDeviceAuthenticator::GetUvToken(
- std::vector<pin::Permissions> permissions,
- absl::optional<std::string> rp_id,
- GetTokenCallback callback) {
- GetEphemeralKey(
- base::BindOnce(&FidoDeviceAuthenticator::OnHaveEphemeralKeyForUvToken,
- weak_factory_.GetWeakPtr(), std::move(rp_id),
- std::move(permissions), std::move(callback)));
- }
- uint32_t FidoDeviceAuthenticator::CurrentMinPINLength() {
- return ForcePINChange() ? kMinPinLength : NewMinPINLength();
- }
- uint32_t FidoDeviceAuthenticator::NewMinPINLength() {
- return device()->device_info()->min_pin_length.value_or(kMinPinLength);
- }
- bool FidoDeviceAuthenticator::ForcePINChange() {
- return device()->device_info()->force_pin_change.value_or(false);
- }
- void FidoDeviceAuthenticator::OnHaveEphemeralKeyForUvToken(
- absl::optional<std::string> rp_id,
- std::vector<pin::Permissions> permissions,
- GetTokenCallback callback,
- CtapDeviceResponseCode status,
- absl::optional<pin::KeyAgreementResponse> key) {
- if (status != CtapDeviceResponseCode::kSuccess) {
- std::move(callback).Run(status, absl::nullopt);
- return;
- }
- DCHECK(key);
- pin::UvTokenRequest request(*chosen_pin_uv_auth_protocol_, *key,
- std::move(rp_id), permissions);
- std::vector<uint8_t> shared_key = request.shared_key();
- RunOperation<pin::UvTokenRequest, pin::TokenResponse>(
- std::move(request), std::move(callback),
- base::BindOnce(&pin::TokenResponse::Parse, *chosen_pin_uv_auth_protocol_,
- std::move(shared_key)));
- }
- size_t FidoDeviceAuthenticator::max_large_blob_fragment_length() {
- return device_->device_info()->max_msg_size
- ? *device_->device_info()->max_msg_size -
- kLargeBlobReadEncodingOverhead
- : kLargeBlobDefaultMaxFragmentLength;
- }
- base::WeakPtr<FidoAuthenticator> FidoDeviceAuthenticator::GetWeakPtr() {
- return weak_factory_.GetWeakPtr();
- }
- } // namespace device
|