blob: 1cabb01bfa26b60cd7c733ef17385ff9872000bc [file]
// Copyright 2019 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "content/browser/devtools/protocol/webauthn_handler.h"
#include <map>
#include <string>
#include <string_view>
#include <utility>
#include <vector>
#include "base/functional/callback.h"
#include "base/memory/ref_counted.h"
#include "base/memory/scoped_refptr.h"
#include "base/numerics/safe_conversions.h"
#include "base/strings/string_number_conversions.h"
#include "content/browser/devtools/protocol/web_authn.h"
#include "content/browser/renderer_host/render_frame_host_impl.h"
#include "content/browser/webauth/authenticator_environment.h"
#include "content/browser/webauth/virtual_authenticator.h"
#include "content/browser/webauth/virtual_authenticator_manager_impl.h"
#include "device/fido/public/fido_constants.h"
#include "device/fido/public/fido_transport_protocol.h"
#include "device/fido/virtual_fido_device.h"
#include "device/fido/virtual_u2f_device.h"
// This should be after all other #includes.
#if defined(_WINDOWS_) // Detect whether windows.h was included.
#include "base/win/windows_h_disallowed.h"
#endif // defined(_WINDOWS_)
namespace content::protocol {
namespace {
static constexpr char kActiveCmtgKeyIndexOutOfBounds[] =
"activeCmtgKeyIndex out of bounds";
static constexpr char kAlreadyHasInternalAuthenticator[] =
"Chrome only supports one internal authenticator per environment";
static constexpr char kAuthenticatorNotFound[] =
"Could not find a Virtual Authenticator matching the ID";
static constexpr char kCableNotSupportedOnU2f[] =
"U2F only supports the \"usb\", \"ble\" and \"nfc\" transports";
static constexpr char kCmtgNotSupported[] =
"CMTG is not supported by this authenticator";
static constexpr char kCouldNotCreateCredential[] =
"An error occurred trying to create the credential";
static constexpr char kCouldNotStoreLargeBlob[] =
"An error occurred trying to store the large blob";
static constexpr char kCredentialNotFound[] =
"Could not find a credential matching the ID";
static constexpr char kDevToolsNotAttached[] =
"The DevTools session is not attached to a frame";
static constexpr char kErrorCreatingAuthenticator[] =
"An error occurred when trying to create the authenticator";
static constexpr char kHandleRequiredForResidentCredential[] =
"The User Handle is required for Resident Credentials";
static constexpr char kInvalidCmtgKey[] = "Invalid CMTG key";
static constexpr char kInvalidCtapVersion[] = "Invalid CTAP version.";
static constexpr char kInvalidProtocol[] = "The protocol is not valid";
static constexpr char kInvalidSignatureCounter[] =
"Signature counter must be greater than or equal to -1";
static constexpr char kInvalidTransport[] = "The transport is not valid";
static constexpr char kInvalidUserHandle[] =
"The User Handle must have a maximum size of ";
static constexpr char kRequiresCtap2[] =
"Specified options require a CTAP 2 authenticator";
static constexpr char kRequiresCtap2_1[] =
"Specified options require a CTAP 2.1 authenticator";
static constexpr char kRequiresResidentKey[] =
"Specified options require an authenticator with resident key support";
static constexpr char kResidentCredentialNotSupported[] =
"The Authenticator does not support Resident Credentials.";
static constexpr char kRpIdRequired[] =
"The Relying Party ID is a required parameter";
static constexpr char kVirtualEnvironmentNotEnabled[] =
"The Virtual Authenticator Environment has not been enabled for this "
"session";
class GetCredentialCallbackAggregator
: public base::RefCounted<GetCredentialCallbackAggregator> {
public:
REQUIRE_ADOPTION_FOR_REFCOUNTED_TYPE();
explicit GetCredentialCallbackAggregator(
std::unique_ptr<WebAuthn::Backend::GetCredentialsCallback> callback)
: callback_(std::move(callback)) {}
GetCredentialCallbackAggregator(const GetCredentialCallbackAggregator&) =
delete;
GetCredentialCallbackAggregator operator=(
const GetCredentialCallbackAggregator&) = delete;
void OnLargeBlob(std::unique_ptr<WebAuthn::Credential> credential,
std::optional<std::vector<uint8_t>> blob) {
if (blob) {
credential->SetLargeBlob(Binary::fromVector(std::move(*blob)));
}
credentials_->emplace_back(std::move(credential));
}
private:
friend class base::RefCounted<GetCredentialCallbackAggregator>;
~GetCredentialCallbackAggregator() {
callback_->sendSuccess(std::move(credentials_));
}
std::unique_ptr<WebAuthn::Backend::GetCredentialsCallback> callback_;
std::unique_ptr<Array<WebAuthn::Credential>> credentials_ =
std::make_unique<Array<WebAuthn::Credential>>();
};
device::ProtocolVersion ConvertToProtocolVersion(std::string_view protocol) {
if (protocol == WebAuthn::AuthenticatorProtocolEnum::Ctap2)
return device::ProtocolVersion::kCtap2;
if (protocol == WebAuthn::AuthenticatorProtocolEnum::U2f)
return device::ProtocolVersion::kU2f;
return device::ProtocolVersion::kUnknown;
}
std::optional<device::Ctap2Version> ConvertToCtap2Version(
std::string_view version) {
if (version == WebAuthn::Ctap2VersionEnum::Ctap2_0)
return device::Ctap2Version::kCtap2_0;
if (version == WebAuthn::Ctap2VersionEnum::Ctap2_1)
return device::Ctap2Version::kCtap2_1;
if (version == WebAuthn::Ctap2VersionEnum::Ctap2_2) {
return device::Ctap2Version::kCtap2_2;
}
return std::nullopt;
}
std::vector<uint8_t> CopyBinaryToVector(const Binary& binary) {
return std::vector<uint8_t>(binary.begin(), binary.end());
}
std::unique_ptr<WebAuthn::Credential> BuildCredentialFromRegistration(
const VirtualAuthenticator& authenticator,
base::span<const uint8_t> credential_id,
const device::VirtualFidoDevice::RegistrationData& registration) {
int sign_count = -1;
if (registration.counter.has_value()) {
sign_count = base::saturated_cast<int>(*registration.counter);
}
auto credential = WebAuthn::Credential::Create()
.SetCredentialId(Binary::fromSpan(credential_id))
.SetPrivateKey(Binary::fromVector(
registration.private_key->GetPKCS8PrivateKey()))
.SetSignCount(sign_count)
.SetIsResidentCredential(registration.is_resident)
.SetBackupEligibility(registration.backup_eligible)
.SetBackupState(registration.backup_state)
.Build();
if (registration.rp) {
credential->SetRpId(registration.rp->id);
}
if (registration.user) {
credential->SetUserHandle(Binary::fromVector(registration.user->id));
if (registration.user->name) {
credential->SetUserName(*registration.user->name);
}
if (registration.user->display_name) {
credential->SetUserDisplayName(*registration.user->display_name);
}
}
if (authenticator.has_cmtg_key()) {
auto cmtg_keys = std::make_unique<Array<Binary>>();
for (const auto& key : registration.cmtg_keys) {
cmtg_keys->emplace_back(Binary::fromVector(key->GetPKCS8PrivateKey()));
}
credential->SetCmtgKeys(std::move(cmtg_keys));
credential->SetActiveCmtgKeyIndex(
base::saturated_cast<int>(registration.selected_cmtg_key_index));
credential->SetGenerateCmtgKeyOnNextOperation(
registration.generate_cmtg_key_on_next_operation);
}
return credential;
}
} // namespace
WebAuthnHandler::WebAuthnHandler()
: DevToolsDomainHandler(WebAuthn::Metainfo::domainName) {}
WebAuthnHandler::~WebAuthnHandler() = default;
void WebAuthnHandler::SetRenderer(int process_host_id,
RenderFrameHostImpl* frame_host) {
if (!frame_host) {
Disable();
}
frame_host_ = frame_host;
}
void WebAuthnHandler::Wire(UberDispatcher* dispatcher) {
frontend_ = std::make_unique<WebAuthn::Frontend>(dispatcher->channel());
WebAuthn::Dispatcher::wire(dispatcher, this);
}
Response WebAuthnHandler::Enable(std::optional<bool> enable_ui) {
if (!frame_host_)
return Response::ServerError(kDevToolsNotAttached);
AuthenticatorEnvironment::GetInstance()->EnableVirtualAuthenticatorFor(
frame_host_->frame_tree_node(),
enable_ui.value_or(/*default_value=*/false));
return Response::Success();
}
Response WebAuthnHandler::Disable() {
if (frame_host_) {
AuthenticatorEnvironment::GetInstance()->DisableVirtualAuthenticatorFor(
frame_host_->frame_tree_node());
}
return Response::Success();
}
Response WebAuthnHandler::AddVirtualAuthenticator(
std::unique_ptr<WebAuthn::VirtualAuthenticatorOptions> options,
String* out_authenticator_id) {
VirtualAuthenticatorManagerImpl* authenticator_manager =
AuthenticatorEnvironment::GetInstance()
->MaybeGetVirtualAuthenticatorManager(frame_host_->frame_tree_node());
if (!authenticator_manager)
return Response::ServerError(kVirtualEnvironmentNotEnabled);
auto transport =
device::ConvertToFidoTransportProtocol(options->GetTransport());
if (!transport)
return Response::InvalidParams(kInvalidTransport);
auto protocol = ConvertToProtocolVersion(options->GetProtocol());
if (protocol == device::ProtocolVersion::kUnknown)
return Response::InvalidParams(kInvalidProtocol);
if (protocol == device::ProtocolVersion::kU2f &&
!device::VirtualU2fDevice::IsTransportSupported(*transport)) {
return Response::InvalidParams(kCableNotSupportedOnU2f);
}
auto ctap2_version = ConvertToCtap2Version(
options->GetCtap2Version(WebAuthn::Ctap2VersionEnum::Ctap2_0));
if (!ctap2_version)
return Response::InvalidParams(kInvalidCtapVersion);
bool has_large_blob = options->GetHasLargeBlob(/*defaultValue=*/false);
bool has_cred_blob = options->GetHasCredBlob(/*defaultValue=*/false);
bool has_min_pin_length = options->GetHasMinPinLength(/*defaultValue=*/false);
bool has_prf = options->GetHasPrf(/*defaultValue=*/false);
bool has_hmac_secret = options->GetHasHmacSecret(/*defaultValue=*/false);
bool has_hmac_secret_mc = options->GetHasHmacSecretMc(/*defaultValue=*/false);
bool has_resident_key = options->GetHasResidentKey(/*defaultValue=*/false);
bool has_cmtg_key = options->GetHasCmtgKey(/*defaultValue=*/false);
if (!has_resident_key && (has_large_blob || has_cmtg_key)) {
return Response::InvalidParams(kRequiresResidentKey);
}
if (protocol != device::ProtocolVersion::kCtap2 && has_cmtg_key) {
return Response::InvalidParams(kRequiresCtap2);
}
if ((protocol != device::ProtocolVersion::kCtap2 ||
ctap2_version < device::Ctap2Version::kCtap2_1) &&
(has_large_blob || has_cred_blob || has_min_pin_length)) {
return Response::InvalidParams(kRequiresCtap2_1);
}
if (transport == device::FidoTransportProtocol::kInternal &&
std::ranges::any_of(authenticator_manager->GetAuthenticators(),
[](const auto& authenticator) {
return authenticator->transport() ==
device::FidoTransportProtocol::kInternal;
})) {
return Response::InvalidParams(kAlreadyHasInternalAuthenticator);
}
VirtualAuthenticator::Options virt_auth_options;
virt_auth_options.protocol = protocol;
virt_auth_options.transport = *transport;
switch (protocol) {
case device::ProtocolVersion::kU2f:
virt_auth_options.attachment =
device::AuthenticatorAttachment::kCrossPlatform;
break;
case device::ProtocolVersion::kCtap2:
virt_auth_options.ctap2_version = *ctap2_version;
virt_auth_options.attachment =
transport == device::FidoTransportProtocol::kInternal
? device::AuthenticatorAttachment::kPlatform
: device::AuthenticatorAttachment::kCrossPlatform;
virt_auth_options.has_resident_key = has_resident_key;
virt_auth_options.has_user_verification =
options->GetHasUserVerification(/*defaultValue=*/false);
virt_auth_options.has_large_blob = has_large_blob;
virt_auth_options.has_cred_blob = has_cred_blob;
virt_auth_options.has_min_pin_length = has_min_pin_length;
virt_auth_options.has_prf = has_prf;
virt_auth_options.has_hmac_secret = has_hmac_secret;
virt_auth_options.has_hmac_secret_mc = has_hmac_secret_mc;
virt_auth_options.has_cmtg_key = has_cmtg_key;
virt_auth_options.default_backup_eligibility =
options->GetDefaultBackupEligibility(/*defaultValue=*/false);
virt_auth_options.default_backup_state =
options->GetDefaultBackupState(/*defaultValue=*/false);
break;
case device::ProtocolVersion::kUnknown:
NOTREACHED();
}
VirtualAuthenticator* const authenticator =
authenticator_manager->AddAuthenticatorAndReturnNonOwningPointer(
virt_auth_options);
if (!authenticator)
return Response::ServerError(kErrorCreatingAuthenticator);
authenticator->SetUserPresence(
options->GetAutomaticPresenceSimulation(/*defaultValue=*/true));
authenticator->set_user_verified(
options->GetIsUserVerified(/*defaultValue=*/false));
observations_.AddObservation(authenticator);
*out_authenticator_id = authenticator->unique_id();
return Response::Success();
}
Response WebAuthnHandler::RemoveVirtualAuthenticator(
const String& authenticator_id) {
VirtualAuthenticatorManagerImpl* authenticator_manager =
AuthenticatorEnvironment::GetInstance()
->MaybeGetVirtualAuthenticatorManager(frame_host_->frame_tree_node());
if (!authenticator_manager)
return Response::ServerError(kVirtualEnvironmentNotEnabled);
if (!authenticator_manager->RemoveAuthenticator(authenticator_id))
return Response::InvalidParams(kAuthenticatorNotFound);
return Response::Success();
}
Response WebAuthnHandler::SetResponseOverrideBits(
const String& authenticator_id,
std::optional<bool> is_bogus_signature,
std::optional<bool> is_bad_uv,
std::optional<bool> is_bad_up) {
VirtualAuthenticatorManagerImpl* authenticator_manager =
AuthenticatorEnvironment::GetInstance()
->MaybeGetVirtualAuthenticatorManager(frame_host_->frame_tree_node());
if (!authenticator_manager)
return Response::ServerError(kVirtualEnvironmentNotEnabled);
VirtualAuthenticator* authenticator;
Response response = FindAuthenticator(authenticator_id, &authenticator);
if (!response.IsSuccess())
return Response::InvalidParams(kAuthenticatorNotFound);
authenticator->set_bogus_signature(
is_bogus_signature.value_or(/*default_value=*/false));
authenticator->set_bad_uv_bit(is_bad_uv.value_or(/*default_value=*/false));
authenticator->set_bad_up_bit(is_bad_up.value_or(/*default_value=*/false));
return Response::Success();
}
void WebAuthnHandler::AddCredential(
const String& authenticator_id,
std::unique_ptr<WebAuthn::Credential> credential,
std::unique_ptr<AddCredentialCallback> callback) {
VirtualAuthenticator* authenticator;
Response response = FindAuthenticator(authenticator_id, &authenticator);
if (!response.IsSuccess()) {
callback->sendFailure(std::move(response));
return;
}
std::vector<std::unique_ptr<device::VirtualFidoDevice::PrivateKey>> cmtg_keys;
if (authenticator->has_cmtg_key()) {
if (credential->HasCmtgKeys()) {
for (const Binary& key : *credential->GetCmtgKeys()) {
auto parsed_key = device::VirtualFidoDevice::PrivateKey::FromPKCS8(key);
if (!parsed_key) {
callback->sendFailure(Response::InvalidParams(kInvalidCmtgKey));
return;
}
cmtg_keys.push_back(std::move(*parsed_key));
}
}
if (credential->HasActiveCmtgKeyIndex()) {
int index = *credential->GetActiveCmtgKeyIndex();
if (index < 0 || static_cast<size_t>(index) >= cmtg_keys.size()) {
callback->sendFailure(
Response::InvalidParams(kActiveCmtgKeyIndexOutOfBounds));
return;
}
}
} else if (credential->HasCmtgKeys() || credential->HasActiveCmtgKeyIndex() ||
credential->HasGenerateCmtgKeyOnNextOperation()) {
callback->sendFailure(Response::InvalidParams(kCmtgNotSupported));
return;
}
Binary user_handle = credential->GetUserHandle(Binary());
if (credential->HasUserHandle() &&
user_handle.size() > device::kUserHandleMaxLength) {
callback->sendFailure(Response::InvalidParams(
kInvalidUserHandle +
base::NumberToString(device::kUserHandleMaxLength)));
return;
}
if (!credential->HasRpId()) {
callback->sendFailure(Response::InvalidParams(kRpIdRequired));
return;
}
if (credential->HasLargeBlob() && !credential->GetIsResidentCredential()) {
callback->sendFailure(Response::InvalidParams(kRequiresResidentKey));
return;
}
bool credential_created;
std::vector<uint8_t> credential_id =
CopyBinaryToVector(credential->GetCredentialId());
std::optional<uint32_t> counter;
int provided_sign_count = credential->GetSignCount().value_or(0);
if (provided_sign_count < -1) {
callback->sendFailure(Response::InvalidParams(kInvalidSignatureCounter));
return;
}
if (provided_sign_count > -1) {
// -1 is a special value to mean no signature counter.
counter = static_cast<uint32_t>(provided_sign_count);
}
if (credential->GetIsResidentCredential()) {
if (!authenticator->has_resident_key()) {
callback->sendFailure(
Response::InvalidParams(kResidentCredentialNotSupported));
return;
}
if (!credential->HasUserHandle()) {
callback->sendFailure(
Response::InvalidParams(kHandleRequiredForResidentCredential));
return;
}
credential_created = authenticator->AddResidentRegistration(
credential_id, credential->GetRpId(""), credential->GetPrivateKey(),
counter, CopyBinaryToVector(user_handle), credential->GetUserName(""),
credential->GetUserDisplayName(""));
} else {
credential_created =
authenticator->AddRegistration(credential_id, credential->GetRpId(""),
credential->GetPrivateKey(), counter);
}
if (!credential_created) {
callback->sendFailure(Response::ServerError(kCouldNotCreateCredential));
return;
}
if (authenticator->has_cmtg_key()) {
for (auto& key : cmtg_keys) {
CHECK(authenticator->AddCmtgKey(credential_id, std::move(key)));
}
CHECK(authenticator->SetSelectedCmtgKeyIndex(
credential_id, credential->GetActiveCmtgKeyIndex(0)));
CHECK(authenticator->SetGenerateCmtgKeyOnNextOperation(
credential_id, credential->GetGenerateCmtgKeyOnNextOperation(false)));
}
if (credential->HasLargeBlob()) {
authenticator->SetLargeBlob(
credential_id, CopyBinaryToVector(credential->GetLargeBlob({})),
base::BindOnce(
[](std::unique_ptr<AddCredentialCallback> callback, bool success) {
if (!success) {
callback->sendFailure(
Response::ServerError(kCouldNotStoreLargeBlob));
return;
}
callback->sendSuccess();
},
std::move(callback)));
return;
}
// VirtualFidoDevice takes care of setting BE & BS flags to the default
// authenticator values whenever a new credential is created. Only override
// the values if the client specified them.
if (credential->HasBackupEligibility()) {
authenticator->SetBackupEligibility(
credential_id, credential->GetBackupEligibility(/*unused*/ false));
}
if (credential->HasBackupState()) {
authenticator->SetBackupState(credential_id,
credential->GetBackupState(/*unused*/ false));
}
callback->sendSuccess();
}
void WebAuthnHandler::GetCredential(
const String& authenticator_id,
const Binary& credential_id,
std::unique_ptr<GetCredentialCallback> callback) {
VirtualAuthenticator* authenticator;
Response response = FindAuthenticator(authenticator_id, &authenticator);
if (!response.IsSuccess()) {
callback->sendFailure(response);
return;
}
auto registration =
authenticator->registrations().find(CopyBinaryToVector(credential_id));
if (registration == authenticator->registrations().end()) {
callback->sendFailure(Response::InvalidParams(kCredentialNotFound));
return;
}
authenticator->GetLargeBlob(
registration->first,
base::BindOnce(
[](std::unique_ptr<WebAuthn::Credential> registration,
std::unique_ptr<GetCredentialCallback> callback,
const std::optional<std::vector<uint8_t>> blob) {
if (blob) {
registration->SetLargeBlob(Binary::fromVector(std::move(*blob)));
}
callback->sendSuccess(std::move(registration));
},
BuildCredentialFromRegistration(*authenticator,
base::span(registration->first),
registration->second),
std::move(callback)));
}
void WebAuthnHandler::GetCredentials(
const String& authenticator_id,
std::unique_ptr<GetCredentialsCallback> callback) {
VirtualAuthenticator* authenticator;
Response response = FindAuthenticator(authenticator_id, &authenticator);
if (!response.IsSuccess()) {
callback->sendFailure(response);
return;
}
auto aggregator = base::MakeRefCounted<GetCredentialCallbackAggregator>(
std::move(callback));
for (const auto& registration : authenticator->registrations()) {
authenticator->GetLargeBlob(
registration.first,
base::BindOnce(&GetCredentialCallbackAggregator::OnLargeBlob,
aggregator,
BuildCredentialFromRegistration(
*authenticator, base::span(registration.first),
registration.second)));
}
}
Response WebAuthnHandler::RemoveCredential(const String& authenticator_id,
const Binary& credential_id) {
VirtualAuthenticator* authenticator;
Response response = FindAuthenticator(authenticator_id, &authenticator);
if (!response.IsSuccess())
return response;
if (!authenticator->RemoveRegistration(CopyBinaryToVector(credential_id)))
return Response::InvalidParams(kCredentialNotFound);
return Response::Success();
}
Response WebAuthnHandler::ClearCredentials(const String& authenticator_id) {
VirtualAuthenticator* authenticator;
Response response = FindAuthenticator(authenticator_id, &authenticator);
if (!response.IsSuccess())
return response;
authenticator->ClearRegistrations();
return Response::Success();
}
Response WebAuthnHandler::SetUserVerified(const String& authenticator_id,
bool is_user_verified) {
VirtualAuthenticator* authenticator;
Response response = FindAuthenticator(authenticator_id, &authenticator);
if (!response.IsSuccess())
return response;
authenticator->set_user_verified(is_user_verified);
return Response::Success();
}
Response WebAuthnHandler::SetAutomaticPresenceSimulation(
const String& authenticator_id,
bool enabled) {
VirtualAuthenticator* authenticator;
Response response = FindAuthenticator(authenticator_id, &authenticator);
if (!response.IsSuccess())
return response;
authenticator->SetUserPresence(enabled);
return Response::Success();
}
Response WebAuthnHandler::SetCredentialProperties(
const String& authenticator_id,
const Binary& in_credential_id,
std::optional<bool> backup_eligibility,
std::optional<bool> backup_state,
std::optional<int> active_cmtg_key_index,
std::optional<bool> generate_cmtg_key_on_next_operation,
std::optional<int> sign_count) {
VirtualAuthenticator* authenticator;
Response response = FindAuthenticator(authenticator_id, &authenticator);
if (!response.IsSuccess()) {
return response;
}
std::vector<uint8_t> credential_id = CopyBinaryToVector(in_credential_id);
auto registration = authenticator->registrations().find(credential_id);
if (registration == authenticator->registrations().end()) {
return Response::InvalidParams(kCredentialNotFound);
}
if (backup_eligibility.has_value()) {
authenticator->SetBackupEligibility(credential_id,
backup_eligibility.value());
}
if (backup_state.has_value()) {
authenticator->SetBackupState(credential_id, backup_state.value());
}
if (authenticator->has_cmtg_key()) {
if (active_cmtg_key_index.has_value()) {
if (*active_cmtg_key_index < 0 ||
static_cast<size_t>(*active_cmtg_key_index) >=
registration->second.cmtg_keys.size()) {
return Response::InvalidParams(kActiveCmtgKeyIndexOutOfBounds);
}
CHECK(authenticator->SetSelectedCmtgKeyIndex(credential_id,
*active_cmtg_key_index));
}
if (generate_cmtg_key_on_next_operation.has_value()) {
CHECK(authenticator->SetGenerateCmtgKeyOnNextOperation(
credential_id, *generate_cmtg_key_on_next_operation));
}
} else {
if (active_cmtg_key_index.has_value() ||
generate_cmtg_key_on_next_operation.has_value()) {
return Response::InvalidParams(kCmtgNotSupported);
}
}
if (sign_count.has_value()) {
if (*sign_count < -1) {
return Response::InvalidParams(kInvalidSignatureCounter);
}
authenticator->SetSignatureCounter(
credential_id,
// -1 is used to represent no counter available.
*sign_count == -1 ? std::nullopt
: std::make_optional<uint32_t>(*sign_count));
}
return Response::Success();
}
Response WebAuthnHandler::FindAuthenticator(
const String& id,
VirtualAuthenticator** out_authenticator) {
*out_authenticator = nullptr;
VirtualAuthenticatorManagerImpl* authenticator_manager =
AuthenticatorEnvironment::GetInstance()
->MaybeGetVirtualAuthenticatorManager(frame_host_->frame_tree_node());
if (!authenticator_manager)
return Response::ServerError(kVirtualEnvironmentNotEnabled);
*out_authenticator = authenticator_manager->GetAuthenticator(id);
if (!*out_authenticator)
return Response::InvalidParams(kAuthenticatorNotFound);
return Response::Success();
}
void WebAuthnHandler::OnCredentialCreated(
VirtualAuthenticator* authenticator,
const device::VirtualFidoDevice::Credential& credential) {
frontend_->CredentialAdded(
authenticator->unique_id(),
BuildCredentialFromRegistration(*authenticator, credential.first,
*credential.second));
}
void WebAuthnHandler::OnCredentialDeleted(
VirtualAuthenticator* authenticator,
base::span<const uint8_t> credential_id) {
frontend_->CredentialDeleted(authenticator->unique_id(),
Binary::fromSpan(credential_id));
}
void WebAuthnHandler::OnCredentialUpdated(
VirtualAuthenticator* authenticator,
const device::VirtualFidoDevice::Credential& credential) {
frontend_->CredentialUpdated(
authenticator->unique_id(),
BuildCredentialFromRegistration(*authenticator, credential.first,
*credential.second));
}
void WebAuthnHandler::OnAssertion(
VirtualAuthenticator* authenticator,
const device::VirtualFidoDevice::Credential& credential) {
frontend_->CredentialAsserted(
authenticator->unique_id(),
BuildCredentialFromRegistration(*authenticator, credential.first,
*credential.second));
}
void WebAuthnHandler::OnAuthenticatorWillBeDestroyed(
VirtualAuthenticator* authenticator) {
observations_.RemoveObservation(authenticator);
}
} // namespace content::protocol