blob: 31d2a7ca902918ed77cad96b6aa221632d6bbf61 [file] [log] [blame]
// 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/authenticator_get_info_response.h"
#include <utility>
#include "base/containers/contains.h"
#include "base/ranges/algorithm.h"
#include "components/cbor/values.h"
#include "components/cbor/writer.h"
#include "device/fido/fido_parsing_utils.h"
namespace device {
namespace {
template <typename Container>
cbor::Value::ArrayValue ToArrayValue(const Container& container) {
cbor::Value::ArrayValue value;
value.reserve(container.size());
for (const auto& item : container)
value.emplace_back(item);
return value;
}
} // namespace
AuthenticatorGetInfoResponse::AuthenticatorGetInfoResponse(
base::flat_set<ProtocolVersion> in_versions,
base::flat_set<Ctap2Version> in_ctap2_versions,
base::span<const uint8_t, kAaguidLength> in_aaguid)
: versions(std::move(in_versions)),
ctap2_versions(std::move(in_ctap2_versions)),
aaguid(fido_parsing_utils::Materialize(in_aaguid)) {
DCHECK_NE(base::Contains(versions, ProtocolVersion::kCtap2),
ctap2_versions.empty());
}
AuthenticatorGetInfoResponse::AuthenticatorGetInfoResponse(
AuthenticatorGetInfoResponse&& that) = default;
AuthenticatorGetInfoResponse& AuthenticatorGetInfoResponse::operator=(
AuthenticatorGetInfoResponse&& other) = default;
AuthenticatorGetInfoResponse::~AuthenticatorGetInfoResponse() = default;
// static
std::vector<uint8_t> AuthenticatorGetInfoResponse::EncodeToCBOR(
const AuthenticatorGetInfoResponse& response) {
cbor::Value::ArrayValue version_array;
for (const auto& version : response.versions) {
switch (version) {
case ProtocolVersion::kCtap2:
for (const auto& ctap2_version : response.ctap2_versions) {
switch (ctap2_version) {
case Ctap2Version::kCtap2_0:
version_array.emplace_back(kCtap2Version);
break;
case Ctap2Version::kCtap2_1:
version_array.emplace_back(kCtap2_1Version);
break;
}
}
break;
case ProtocolVersion::kU2f:
version_array.emplace_back(kU2fVersion);
break;
case ProtocolVersion::kUnknown:
NOTREACHED();
}
}
cbor::Value::MapValue device_info_map;
device_info_map.emplace(0x01, std::move(version_array));
if (response.extensions)
device_info_map.emplace(0x02, ToArrayValue(*response.extensions));
device_info_map.emplace(0x03, response.aaguid);
device_info_map.emplace(0x04, AsCBOR(response.options));
if (response.max_msg_size) {
device_info_map.emplace(0x05,
base::strict_cast<int64_t>(*response.max_msg_size));
}
if (response.pin_protocols) {
cbor::Value::ArrayValue pin_protocols;
for (const PINUVAuthProtocol p : *response.pin_protocols) {
pin_protocols.push_back(cbor::Value(static_cast<int>(p)));
}
device_info_map.emplace(0x06, std::move(pin_protocols));
}
if (response.max_credential_count_in_list) {
device_info_map.emplace(0x07, base::strict_cast<int64_t>(
*response.max_credential_count_in_list));
}
if (response.max_credential_id_length) {
device_info_map.emplace(
0x08, base::strict_cast<int64_t>(*response.max_credential_id_length));
}
if (response.remaining_discoverable_credentials) {
device_info_map.emplace(0x14,
base::strict_cast<int64_t>(
*response.remaining_discoverable_credentials));
}
if (!response.algorithms.empty()) {
std::vector<cbor::Value> algorithms_cbor;
algorithms_cbor.reserve(response.algorithms.size());
for (const auto& algorithm : response.algorithms) {
// Entries are PublicKeyCredentialParameters
// https://w3c.github.io/webauthn/#dictdef-publickeycredentialparameters
cbor::Value::MapValue entry;
entry.emplace("type", "public-key");
entry.emplace("alg", algorithm);
algorithms_cbor.emplace_back(cbor::Value(entry));
}
device_info_map.emplace(0x0a, std::move(algorithms_cbor));
}
if (response.max_serialized_large_blob_array) {
device_info_map.emplace(
0x0b,
base::strict_cast<int64_t>(*response.max_serialized_large_blob_array));
}
if (response.force_pin_change) {
device_info_map.emplace(0x0c, cbor::Value(*response.force_pin_change));
}
if (response.min_pin_length) {
device_info_map.emplace(
0x0d,
cbor::Value(base::strict_cast<int64_t>(*response.min_pin_length)));
}
if (response.max_cred_blob_length) {
device_info_map.emplace(
0x0f, base::strict_cast<int64_t>(*response.max_cred_blob_length));
}
auto encoded_bytes =
cbor::Writer::Write(cbor::Value(std::move(device_info_map)));
DCHECK(encoded_bytes);
return *encoded_bytes;
}
bool AuthenticatorGetInfoResponse::SupportsAtLeast(
Ctap2Version ctap2_version) const {
return base::ranges::any_of(ctap2_versions,
[ctap2_version](const Ctap2Version& version) {
return version >= ctap2_version;
});
}
} // namespace device