blob: 065fded73d3cab2a5e6391e6b18c732ff15f7bf7 [file] [log] [blame]
// Copyright 2021 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/appid_exclude_probe_task.h"
#include "device/fido/ctap2_device_operation.h"
#include "device/fido/make_credential_task.h"
namespace device {
AppIdExcludeProbeTask::AppIdExcludeProbeTask(FidoDevice* device,
CtapMakeCredentialRequest request,
MakeCredentialOptions options,
Callback callback)
: FidoTask(device),
request_(std::move(request)),
options_(std::move(options)),
callback_(std::move(callback)) {}
AppIdExcludeProbeTask::~AppIdExcludeProbeTask() = default;
void AppIdExcludeProbeTask::StartTask() {
DCHECK(request_.app_id_exclude);
DCHECK(!options_.make_u2f_api_credential);
DCHECK_EQ(device()->supported_protocol(), ProtocolVersion::kCtap2);
DCHECK(!device()->NoSilentRequests());
// Most authenticators can only process excludeList parameters up to a certain
// size. Batch the list into chunks according to what the device can handle
// and filter out IDs that are too large to originate from this device.
exclude_list_batches_ =
FilterAndBatchCredentialDescriptors(request_.exclude_list, *device());
DCHECK(!exclude_list_batches_.empty());
if (exclude_list_batches_.size() == 1 &&
exclude_list_batches_.front().empty()) {
// None of the credential IDs are candidates for this device.
std::move(callback_).Run(CtapDeviceResponseCode::kSuccess, absl::nullopt);
return;
}
NextSilentSignOperation();
}
void AppIdExcludeProbeTask::Cancel() {
canceled_ = true;
if (silent_sign_operation_) {
silent_sign_operation_->Cancel();
}
}
void AppIdExcludeProbeTask::NextSilentSignOperation() {
DCHECK(current_exclude_list_batch_ < exclude_list_batches_.size());
CtapGetAssertionRequest request(*request_.app_id_exclude,
/*client_data_json=*/"");
request.allow_list = exclude_list_batches_.at(current_exclude_list_batch_);
request.user_presence_required = false;
request.user_verification = UserVerificationRequirement::kDiscouraged;
silent_sign_operation_ = std::make_unique<Ctap2DeviceOperation<
CtapGetAssertionRequest, AuthenticatorGetAssertionResponse>>(
device(), std::move(request),
base::BindOnce(&AppIdExcludeProbeTask::HandleResponseToSilentSignRequest,
weak_factory_.GetWeakPtr()),
base::BindOnce(&ReadCTAPGetAssertionResponse),
/*string_fixup_predicate=*/nullptr);
silent_sign_operation_->Start();
}
void AppIdExcludeProbeTask::HandleResponseToSilentSignRequest(
CtapDeviceResponseCode response_code,
absl::optional<AuthenticatorGetAssertionResponse> response_data) {
silent_sign_operation_.reset();
if (canceled_) {
return;
}
if (response_code == CtapDeviceResponseCode::kSuccess) {
// The authenticator recognized a credential from previous exclude list
// batch.
std::move(callback_).Run(
CtapDeviceResponseCode::kCtap2ErrCredentialExcluded, absl::nullopt);
return;
}
if (!FidoDevice::IsStatusForUnrecognisedCredentialID(response_code)) {
// The authenticator returned an unexpected error.
std::move(callback_).Run(CtapDeviceResponseCode::kCtap2ErrOther,
absl::nullopt);
return;
}
// The authenticator didn't recognize any credential from the previous exclude
// list batch. Try the next batch, if there is one.
current_exclude_list_batch_++;
if (current_exclude_list_batch_ == exclude_list_batches_.size()) {
// All done.
std::move(callback_).Run(CtapDeviceResponseCode::kSuccess, absl::nullopt);
return;
}
NextSilentSignOperation();
}
} // namespace device