Commit 7789a086 authored by Adam Langley's avatar Adam Langley Committed by Commit Bot

device/fido: split caBLEv2 into its own discovery.

This change extracts all caBLEv2 bits from the caBLEv1 discovery and
puts them in a separate class. This class is not an active discovery: it
depends on BLE adverts getting fed to it from the caBLEv1 discovery. But
this style permits the caBLEv2 discovery to be used in unittests because
the BLE adverts can be fed from anywhere.

Since caBLE only has a single transport value, this means that the
discovery factory can now return a vector of discoveries for a given
transport. It might be the case that we should split the transport
value, but since the v2 discovery depends on the v1 discovery, that's
not as simple as it sounds.

BUG=1002262

Change-Id: Ia3c277e8f7211beb81d352a1cb31918dc643abbe
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2415430
Commit-Queue: Adam Langley <agl@chromium.org>
Reviewed-by: default avatarMartin Kreichgauer <martinkr@google.com>
Cr-Commit-Position: refs/heads/master@{#808709}
parent 06917154
......@@ -70,17 +70,24 @@ std::string Base64(base::span<const uint8_t> in) {
return ret;
}
template <size_t N>
bool CopyBytestring(std::array<uint8_t, N>* out,
const base::Value& dict,
const char* key) {
base::Optional<std::string> GetString(const base::Value& dict,
const char* key) {
const base::Value* v = dict.FindKey(key);
if (!v || !v->is_string()) {
return base::nullopt;
}
return v->GetString();
}
template <size_t N>
bool CopyBytestring(std::array<uint8_t, N>* out,
base::Optional<std::string> value) {
if (!value) {
return false;
}
std::string bytes;
if (!base::Base64Decode(v->GetString(), &bytes) || bytes.size() != N) {
if (!base::Base64Decode(*value, &bytes) || bytes.size() != N) {
return false;
}
......@@ -88,6 +95,30 @@ bool CopyBytestring(std::array<uint8_t, N>* out,
return true;
}
bool CopyBytestring(std::vector<uint8_t>* out,
base::Optional<std::string> value) {
if (!value) {
return false;
}
std::string bytes;
if (!base::Base64Decode(*value, &bytes)) {
return false;
}
out->clear();
out->insert(out->begin(), bytes.begin(), bytes.end());
return true;
}
bool CopyString(std::string* out, base::Optional<std::string> value) {
if (!value) {
return false;
}
*out = *value;
return true;
}
#if defined(OS_MAC)
const char kWebAuthnTouchIdMetadataSecretPrefName[] =
"webauthn.touchid.metadata_secret";
......@@ -96,15 +127,17 @@ const char kWebAuthnTouchIdMetadataSecretPrefName[] =
const char kWebAuthnLastTransportUsedPrefName[] =
"webauthn.last_transport_used";
const char kWebAuthnCablePairingsPrefName[] = "webauthn.cable_pairings";
const char kWebAuthnCablePairingsPrefName[] = "webauthn.cablev2_pairings";
// The |kWebAuthnCablePairingsPrefName| preference contains a list of dicts,
// where each dict has these keys:
const char kPairingPrefIdentity[] = "identity";
const char kPairingPrefName[] = "name";
const char kPairingPrefContactId[] = "contact_id";
const char kPairingPrefTunnelServer[] = "tunnel_server";
const char kPairingPrefId[] = "id";
const char kPairingPrefSecret[] = "secret";
const char kPairingPrefPublicKey[] = "pub_key";
const char kPairingPrefTime[] = "time";
const char kPairingPrefEIDGenKey[] = "eid_gen_key";
const char kPairingPrefPSKGenKey[] = "psk_gen_key";
} // namespace
......@@ -322,11 +355,11 @@ void ChromeAuthenticatorRequestDelegate::ConfigureCable(
base::Optional<device::QRGeneratorKey> qr_generator_key;
bool have_paired_phones = false;
std::vector<std::unique_ptr<device::cablev2::Pairing>> paired_phones;
if (base::FeatureList::IsEnabled(device::kWebAuthPhoneSupport)) {
qr_generator_key.emplace(device::CableDiscoveryData::NewQRKey());
auto paired_phones = GetCablePairings();
paired_phones = GetCablePairings();
have_paired_phones = !paired_phones.empty();
pairings.insert(pairings.end(), paired_phones.begin(), paired_phones.end());
mojo::Remote<device::mojom::UsbDeviceManager> usb_device_manager;
content::GetDeviceService().BindUsbDeviceManager(
......@@ -342,7 +375,8 @@ void ChromeAuthenticatorRequestDelegate::ConfigureCable(
weak_dialog_model_->set_cable_transport_info(
cable_extension_provided, have_paired_phones, qr_generator_key);
discovery_factory->set_cable_data(std::move(pairings), qr_generator_key);
discovery_factory->set_cable_data(std::move(pairings), qr_generator_key,
std::move(paired_phones));
discovery_factory->set_cable_pairing_callback(base::BindRepeating(
&ChromeAuthenticatorRequestDelegate::StoreNewCablePairingInPrefs,
......@@ -595,9 +629,9 @@ bool ChromeAuthenticatorRequestDelegate::ShouldPermitCableExtension(
return origin.IsSameOriginWith(url::Origin::Create(test_site));
}
std::vector<device::CableDiscoveryData>
std::vector<std::unique_ptr<device::cablev2::Pairing>>
ChromeAuthenticatorRequestDelegate::GetCablePairings() {
std::vector<device::CableDiscoveryData> ret;
std::vector<std::unique_ptr<device::cablev2::Pairing>> ret;
if (!base::FeatureList::IsEnabled(device::kWebAuthPhoneSupport)) {
NOTREACHED();
return ret;
......@@ -613,34 +647,31 @@ ChromeAuthenticatorRequestDelegate::GetCablePairings() {
continue;
}
device::CableDiscoveryData discovery;
discovery.version = device::CableDiscoveryData::Version::V2;
discovery.v2.emplace();
discovery.v2->peer_identity.emplace();
if (!CopyBytestring(&discovery.v2->peer_identity.value(), pairing,
kPairingPrefIdentity) ||
!CopyBytestring(&discovery.v2->eid_gen_key, pairing,
kPairingPrefEIDGenKey) ||
!CopyBytestring(&discovery.v2->psk_gen_key, pairing,
kPairingPrefPSKGenKey)) {
auto out_pairing = std::make_unique<device::cablev2::Pairing>();
if (!CopyString(&out_pairing->name, GetString(pairing, kPairingPrefName)) ||
!CopyString(&out_pairing->tunnel_server_domain,
GetString(pairing, kPairingPrefTunnelServer)) ||
!CopyBytestring(&out_pairing->contact_id,
GetString(pairing, kPairingPrefContactId)) ||
!CopyBytestring(&out_pairing->id, GetString(pairing, kPairingPrefId)) ||
!CopyBytestring(&out_pairing->secret,
GetString(pairing, kPairingPrefSecret)) ||
!CopyBytestring(&out_pairing->peer_public_key_x962,
GetString(pairing, kPairingPrefPublicKey))) {
continue;
}
ret.push_back(discovery);
ret.emplace_back(std::move(out_pairing));
}
return ret;
}
void ChromeAuthenticatorRequestDelegate::StoreNewCablePairingInPrefs(
std::unique_ptr<device::CableDiscoveryData> discovery_data) {
std::unique_ptr<device::cablev2::Pairing> pairing) {
// This is called when doing a QR-code pairing with a phone and the phone
// sends long-term pairing information during the handshake. The pairing
// information is saved in preferences for future operations.
DCHECK_EQ(device::CableDiscoveryData::Version::V2, discovery_data->version);
DCHECK(discovery_data->v2->peer_identity.has_value());
DCHECK(discovery_data->v2->peer_name.has_value());
if (!base::FeatureList::IsEnabled(device::kWebAuthPhoneSupport)) {
NOTREACHED();
return;
......@@ -652,30 +683,29 @@ void ChromeAuthenticatorRequestDelegate::StoreNewCablePairingInPrefs(
ListPrefUpdate update(
Profile::FromBrowserContext(browser_context())->GetPrefs(),
kWebAuthnCablePairingsPrefName);
const std::string identity_base64 =
Base64(*discovery_data->v2->peer_identity);
if (std::any_of(update->begin(), update->end(),
[&identity_base64](const auto& value) {
if (!value.is_dict()) {
return false;
}
const base::Value* identity =
value.FindKey(kPairingPrefIdentity);
return identity && identity->is_string() &&
identity->GetString() == identity_base64;
})) {
// This phone is already known, don't add it again.
return;
}
// Find any existing entries with the same public key and replace them. The
// handshake protocol requires the phone to prove possession of the public key
// so it's not possible for an evil phone to displace another's pairing.
const std::string public_key_base64 = Base64(pairing->peer_public_key_x962);
update->EraseListValueIf([&public_key_base64](const auto& value) {
if (!value.is_dict()) {
return false;
}
const base::Value* pref_public_key = value.FindKey(kPairingPrefPublicKey);
return pref_public_key && pref_public_key->is_string() &&
pref_public_key->GetString() == public_key_base64;
});
auto dict = std::make_unique<base::Value>(base::Value::Type::DICTIONARY);
dict->SetKey(kPairingPrefIdentity, base::Value(std::move(identity_base64)));
dict->SetKey(kPairingPrefName,
base::Value(std::move(*discovery_data->v2->peer_name)));
dict->SetKey(kPairingPrefEIDGenKey,
base::Value(Base64(discovery_data->v2->eid_gen_key)));
dict->SetKey(kPairingPrefPSKGenKey,
base::Value(Base64(discovery_data->v2->psk_gen_key)));
dict->SetKey(kPairingPrefPublicKey,
base::Value(std::move(public_key_base64)));
dict->SetKey(kPairingPrefTunnelServer,
base::Value(pairing->tunnel_server_domain));
dict->SetKey(kPairingPrefName, base::Value(std::move(pairing->name)));
dict->SetKey(kPairingPrefContactId, base::Value(Base64(pairing->contact_id)));
dict->SetKey(kPairingPrefId, base::Value(Base64(pairing->id)));
dict->SetKey(kPairingPrefSecret, base::Value(Base64(pairing->secret)));
base::Time::Exploded now;
base::Time::Now().UTCExplode(&now);
......
......@@ -138,10 +138,11 @@ class ChromeAuthenticatorRequestDelegate
bool ShouldPermitCableExtension(const url::Origin& origin);
// GetCablePairings returns any known caBLE pairing data.
virtual std::vector<device::CableDiscoveryData> GetCablePairings();
virtual std::vector<std::unique_ptr<device::cablev2::Pairing>>
GetCablePairings();
void StoreNewCablePairingInPrefs(
std::unique_ptr<device::CableDiscoveryData> discovery_data);
std::unique_ptr<device::cablev2::Pairing> pairing);
content::RenderFrameHost* const render_frame_host_;
// Holds ownership of AuthenticatorRequestDialogModel until
......
......@@ -27,7 +27,7 @@ VirtualFidoDiscoveryFactory::~VirtualFidoDiscoveryFactory() {
}
}
std::unique_ptr<::device::FidoDiscoveryBase>
std::vector<std::unique_ptr<::device::FidoDiscoveryBase>>
VirtualFidoDiscoveryFactory::Create(device::FidoTransportProtocol transport) {
auto discovery = std::make_unique<VirtualFidoDiscovery>(transport);
......@@ -47,7 +47,7 @@ VirtualFidoDiscoveryFactory::Create(device::FidoTransportProtocol transport) {
}
discoveries_.insert(discovery.get());
return discovery;
return SingleDiscovery(std::move(discovery));
}
void VirtualFidoDiscoveryFactory::AuthenticatorAdded(
......
......@@ -46,7 +46,7 @@ class CONTENT_EXPORT VirtualFidoDiscoveryFactory
~VirtualFidoDiscoveryFactory() override;
// device::FidoDiscoveryFactory:
std::unique_ptr<::device::FidoDiscoveryBase> Create(
std::vector<std::unique_ptr<::device::FidoDiscoveryBase>> Create(
device::FidoTransportProtocol transport) override;
bool IsTestOverride() override;
......
......@@ -711,9 +711,10 @@ IN_PROC_BROWSER_TEST_F(WebAuthLocalClientBrowserTest,
// factory as one of the first steps. Here, the request should not have been
// serviced at all, so the fake request should still be pending on the fake
// factory.
auto hid_discovery = discovery_factory_->Create(
::device::FidoTransportProtocol::kUsbHumanInterfaceDevice);
ASSERT_TRUE(!!hid_discovery);
std::vector<std::unique_ptr<device::FidoDiscoveryBase>> discoveries =
discovery_factory_->Create(
::device::FidoTransportProtocol::kUsbHumanInterfaceDevice);
EXPECT_EQ(discoveries.size(), 1u);
// The next active document should be able to successfully call
// navigator.credentials.create({publicKey: ...}) again.
......
......@@ -116,6 +116,8 @@ component("fido") {
"cable/fido_cable_handshake_handler.h",
"cable/fido_tunnel_device.cc",
"cable/fido_tunnel_device.h",
"cable/v2_discovery.cc",
"cable/v2_discovery.h",
"client_data.cc",
"client_data.h",
"credential_management.cc",
......
......@@ -126,24 +126,6 @@ enum class FidoCableDiscovery::CableV1DiscoveryEvent : int {
kMaxValue = kScanningStoppedUnexpectedly,
};
// FidoCableDiscovery::Result -------------------------------------------------
FidoCableDiscovery::Result::Result() = default;
FidoCableDiscovery::Result::Result(
const CableDiscoveryData& in_discovery_data,
const CableEidArray& in_eid,
base::Optional<CableEidArray> in_decrypted_eid,
base::Optional<int> in_ticks_back)
: discovery_data(in_discovery_data),
eid(in_eid),
decrypted_eid(std::move(in_decrypted_eid)),
ticks_back(in_ticks_back) {}
FidoCableDiscovery::Result::Result(const Result& other) = default;
FidoCableDiscovery::Result::~Result() = default;
// FidoCableDiscovery::ObservedDeviceData -------------------------------------
FidoCableDiscovery::ObservedDeviceData::ObservedDeviceData() = default;
......@@ -153,17 +135,11 @@ FidoCableDiscovery::ObservedDeviceData::~ObservedDeviceData() = default;
FidoCableDiscovery::FidoCableDiscovery(
std::vector<CableDiscoveryData> discovery_data,
base::Optional<QRGeneratorKey> qr_generator_key,
base::Optional<
base::RepeatingCallback<void(std::unique_ptr<CableDiscoveryData>)>>
pairing_callback,
network::mojom::NetworkContext* network_context)
FidoDeviceDiscovery::BLEObserver* ble_observer)
: FidoDeviceDiscovery(
FidoTransportProtocol::kCloudAssistedBluetoothLowEnergy),
discovery_data_(std::move(discovery_data)),
qr_generator_key_(std::move(qr_generator_key)),
pairing_callback_(std::move(pairing_callback)),
network_context_(network_context) {
ble_observer_(ble_observer) {
// Windows currently does not support multiple EIDs, thus we ignore any extra
// discovery data.
// TODO(https://crbug.com/837088): Add support for multiple EIDs on Windows.
......@@ -296,8 +272,11 @@ void FidoCableDiscovery::DeviceChanged(BluetoothAdapter* adapter,
void FidoCableDiscovery::DeviceRemoved(BluetoothAdapter* adapter,
BluetoothDevice* device) {
if (IsCableDevice(device) && GetCableDiscoveryData(device)) {
const auto& device_address = device->GetAddress();
const auto& device_address = device->GetAddress();
if (IsCableDevice(device) &&
// It only matters if V1 devices are "removed" because V2 devices do not
// transport data over BLE.
base::Contains(active_devices_, device_address)) {
FIDO_LOG(DEBUG) << "caBLE device removed: " << device_address;
RemoveDevice(FidoCableDevice::GetIdForAddress(device_address));
}
......@@ -476,18 +455,21 @@ void FidoCableDiscovery::CableDeviceFound(BluetoothAdapter* adapter,
return;
}
base::Optional<Result> result = GetCableDiscoveryData(device);
if (!result || base::Contains(active_authenticator_eids_, result->eid)) {
base::Optional<V1DiscoveryDataAndEID> v1_match =
GetCableDiscoveryData(device);
if (!v1_match) {
return;
}
FIDO_LOG(EVENT) << "Found new caBLE device.";
if (result->discovery_data.version == CableDiscoveryData::Version::V1) {
RecordCableV1DiscoveryEventOnce(
CableV1DiscoveryEvent::kFirstCableDeviceFound);
if (base::Contains(active_authenticator_eids_, v1_match->second)) {
return;
}
active_authenticator_eids_.insert(v1_match->second);
active_devices_.insert(device_address);
active_authenticator_eids_.insert(result->eid);
FIDO_LOG(EVENT) << "Found new caBLEv1 device.";
RecordCableV1DiscoveryEventOnce(
CableV1DiscoveryEvent::kFirstCableDeviceFound);
#if defined(OS_CHROMEOS) || defined(OS_LINUX)
// Speed up GATT service discovery on ChromeOS/BlueZ.
......@@ -501,41 +483,21 @@ void FidoCableDiscovery::CableDeviceFound(BluetoothAdapter* adapter,
}
#endif // defined(OS_CHROMEOS) || defined(OS_LINUX)
switch (result->discovery_data.version) {
case CableDiscoveryData::Version::V1: {
auto cable_device =
std::make_unique<FidoCableDevice>(adapter, device_address);
cable_device->set_observer(this);
std::unique_ptr<FidoCableHandshakeHandler> handshake_handler =
CreateV1HandshakeHandler(cable_device.get(), result->discovery_data,
result->eid);
auto* const handshake_handler_ptr = handshake_handler.get();
active_handshakes_.emplace_back(std::move(cable_device),
std::move(handshake_handler));
StopAdvertisements(
base::BindOnce(&FidoCableDiscovery::ConductEncryptionHandshake,
weak_factory_.GetWeakPtr(), handshake_handler_ptr,
result->discovery_data.version));
break;
}
auto cable_device =
std::make_unique<FidoCableDevice>(adapter, device_address);
cable_device->set_observer(this);
case CableDiscoveryData::Version::V2: {
if (!base::FeatureList::IsEnabled(device::kWebAuthPhoneSupport) ||
!network_context_) {
return;
}
// Disabled in order to make each step of a multi-CL change compile.
// TODO(agl): reenable
// AddDevice(...);
break;
}
std::unique_ptr<FidoCableHandshakeHandler> handshake_handler =
CreateV1HandshakeHandler(cable_device.get(), v1_match->first,
v1_match->second);
auto* const handshake_handler_ptr = handshake_handler.get();
active_handshakes_.emplace_back(std::move(cable_device),
std::move(handshake_handler));
case CableDiscoveryData::Version::INVALID:
CHECK(false);
return;
}
StopAdvertisements(
base::BindOnce(&FidoCableDiscovery::ConductEncryptionHandshake,
weak_factory_.GetWeakPtr(), handshake_handler_ptr,
v1_match->first.version));
}
void FidoCableDiscovery::ConductEncryptionHandshake(
......@@ -581,8 +543,8 @@ void FidoCableDiscovery::ValidateAuthenticatorHandshakeMessage(
}
}
base::Optional<FidoCableDiscovery::Result>
FidoCableDiscovery::GetCableDiscoveryData(const BluetoothDevice* device) const {
base::Optional<FidoCableDiscovery::V1DiscoveryDataAndEID>
FidoCableDiscovery::GetCableDiscoveryData(const BluetoothDevice* device) {
base::Optional<CableEidArray> maybe_eid_from_service_data =
MaybeGetEidFromServiceData(device);
std::vector<CableEidArray> uuids = GetUUIDs(device);
......@@ -607,13 +569,12 @@ FidoCableDiscovery::GetCableDiscoveryData(const BluetoothDevice* device) const {
FIDO_LOG(DEBUG) << "New caBLE device " << address << ":";
}
base::Optional<FidoCableDiscovery::Result> result;
base::Optional<FidoCableDiscovery::V1DiscoveryDataAndEID> result;
if (maybe_eid_from_service_data.has_value()) {
result =
GetCableDiscoveryDataFromAuthenticatorEid(*maybe_eid_from_service_data);
FIDO_LOG(DEBUG) << " Service data: "
<< ResultDebugString(*maybe_eid_from_service_data, result);
} else {
FIDO_LOG(DEBUG) << " Service data: <none>";
}
......@@ -621,10 +582,14 @@ FidoCableDiscovery::GetCableDiscoveryData(const BluetoothDevice* device) const {
if (!uuids.empty()) {
FIDO_LOG(DEBUG) << " UUIDs:";
for (const auto& uuid : uuids) {
auto discovery_data = GetCableDiscoveryDataFromAuthenticatorEid(uuid);
FIDO_LOG(DEBUG) << " " << ResultDebugString(uuid, discovery_data);
if (!result && discovery_data) {
result = discovery_data;
auto eid_result = GetCableDiscoveryDataFromAuthenticatorEid(uuid);
FIDO_LOG(DEBUG) << " " << ResultDebugString(uuid, eid_result);
if (!result && eid_result) {
result = std::move(eid_result);
}
if (ble_observer_) {
ble_observer_->OnBLEAdvertSeen(device->GetAddress(), uuid);
}
}
}
......@@ -678,51 +643,13 @@ std::vector<CableEidArray> FidoCableDiscovery::GetUUIDs(
return ret;
}
base::Optional<FidoCableDiscovery::Result>
base::Optional<FidoCableDiscovery::V1DiscoveryDataAndEID>
FidoCableDiscovery::GetCableDiscoveryDataFromAuthenticatorEid(
CableEidArray authenticator_eid) const {
CableEidArray authenticator_eid) {
for (const auto& candidate : discovery_data_) {
if (candidate.version == CableDiscoveryData::Version::V1 &&
candidate.MatchV1(authenticator_eid)) {
return Result(candidate, authenticator_eid, base::nullopt, base::nullopt);
}
}
if (qr_generator_key_) {
// Attempt to match |authenticator_eid| as the result of scanning a QR code.
const int64_t current_tick = CableDiscoveryData::CurrentTimeTick();
// kNumPreviousTicks is the number of previous ticks that will be accepted
// as valid. Ticks are currently 256ms so the value of sixteen translates to
// about four seconds.
constexpr int kNumPreviousTicks = 16;
for (int i = 0; i < kNumPreviousTicks; i++) {
auto qr_secret = CableDiscoveryData::DeriveQRSecret(*qr_generator_key_,
current_tick - i);
auto identity_key_seed = CableDiscoveryData::DeriveIdentityKeySeed(
*qr_generator_key_, current_tick - i);
CableDiscoveryData candidate(qr_secret, identity_key_seed);
CableEidArray decrypted;
if (candidate.MatchV2(authenticator_eid, &decrypted)) {
return Result(candidate, authenticator_eid, decrypted, i);
}
}
if (base::Contains(noted_obsolete_eids_, authenticator_eid)) {
std::array<uint8_t, kCableIdentityKeySeedSize> dummy_seed;
for (int i = kNumPreviousTicks; i < 2 * kNumPreviousTicks; i++) {
auto qr_secret = CableDiscoveryData::DeriveQRSecret(*qr_generator_key_,
current_tick - i);
CableDiscoveryData candidate(qr_secret, dummy_seed);
CableEidArray decrypted;
if (candidate.MatchV2(authenticator_eid, &decrypted)) {
noted_obsolete_eids_.insert(authenticator_eid);
FIDO_LOG(DEBUG)
<< "(EID " << base::HexEncode(authenticator_eid) << " is " << i
<< " ticks old and would be valid but for the cutoff)";
break;
}
}
return V1DiscoveryDataAndEID(candidate, authenticator_eid);
}
}
......@@ -748,7 +675,7 @@ void FidoCableDiscovery::StartInternal() {
// static
std::string FidoCableDiscovery::ResultDebugString(
const CableEidArray& eid,
const base::Optional<FidoCableDiscovery::Result>& result) {
const base::Optional<FidoCableDiscovery::V1DiscoveryDataAndEID>& result) {
static const uint8_t kAppleContinuity[16] = {
0xd0, 0x61, 0x1e, 0x78, 0xbb, 0xb4, 0x45, 0x91,
0xa5, 0xf8, 0x48, 0x79, 0x10, 0xae, 0x43, 0x66,
......@@ -789,22 +716,8 @@ std::string FidoCableDiscovery::ResultDebugString(
return ret;
}
switch (result->discovery_data.version) {
case CableDiscoveryData::Version::V1:
ret += " (version one match";
break;
case CableDiscoveryData::Version::V2:
ret += " (version two match";
break;
case CableDiscoveryData::Version::INVALID:
NOTREACHED();
}
if (!result->ticks_back) {
ret += " against pairing data)";
} else {
ret += " from QR, " + base::NumberToString(*result->ticks_back) +
" tick(s) ago)";
if (result) {
ret += " (version one match)";
}
return ret;
......
......@@ -23,12 +23,6 @@
#include "device/fido/cable/fido_cable_device.h"
#include "device/fido/fido_device_discovery.h"
namespace network {
namespace mojom {
class NetworkContext;
}
} // namespace network
namespace device {
class BluetoothDevice;
......@@ -40,13 +34,8 @@ class COMPONENT_EXPORT(DEVICE_FIDO) FidoCableDiscovery
public BluetoothAdapter::Observer,
public FidoCableDevice::Observer {
public:
FidoCableDiscovery(
std::vector<CableDiscoveryData> discovery_data,
base::Optional<QRGeneratorKey> qr_generator_key,
base::Optional<
base::RepeatingCallback<void(std::unique_ptr<CableDiscoveryData>)>>
pairing_callback,
network::mojom::NetworkContext* network_context);
FidoCableDiscovery(std::vector<CableDiscoveryData> discovery_data,
FidoDeviceDiscovery::BLEObserver* ble_observer);
~FidoCableDiscovery() override;
// FidoDeviceDiscovery:
......@@ -66,26 +55,10 @@ class COMPONENT_EXPORT(DEVICE_FIDO) FidoCableDiscovery
private:
enum class CableV1DiscoveryEvent : int;
// Result represents a successful match of a received EID against a specific
// |FidoDiscoveryData|.
struct Result {
Result();
Result(const CableDiscoveryData& in_discovery_data,
const CableEidArray& in_eid,
base::Optional<CableEidArray> decrypted_eid,
base::Optional<int> ticks_back);
Result(const Result&);
~Result();
CableDiscoveryData discovery_data;
CableEidArray eid;
base::Optional<CableEidArray> decrypted_eid;
// ticks_back is either |base::nullopt|, if the Result is from established
// discovery pairings, or else contains the number of QR ticks back in time
// against which the match was found.
base::Optional<int> ticks_back;
};
// V1DiscoveryDataAndEID represents a match against caBLEv1 pairing data. It
// contains the CableDiscoveryData that matched and the BLE EID that triggered
// the match.
using V1DiscoveryDataAndEID = std::pair<CableDiscoveryData, CableEidArray>;
// ObservedDeviceData contains potential EIDs observed from a BLE device. This
// information is kept in order to de-duplicate device-log entries and make
......@@ -103,8 +76,9 @@ class COMPONENT_EXPORT(DEVICE_FIDO) FidoCableDiscovery
// ResultDebugString returns a string containing a hex dump of |eid| and a
// description of |result|, if present.
static std::string ResultDebugString(const CableEidArray& eid,
const base::Optional<Result>& result);
static std::string ResultDebugString(
const CableEidArray& eid,
const base::Optional<V1DiscoveryDataAndEID>& result);
static base::Optional<CableEidArray> MaybeGetEidFromServiceData(
const BluetoothDevice* device);
static std::vector<CableEidArray> GetUUIDs(const BluetoothDevice* device);
......@@ -138,10 +112,10 @@ class COMPONENT_EXPORT(DEVICE_FIDO) FidoCableDiscovery
FidoCableHandshakeHandler* handshake_handler,
base::Optional<std::vector<uint8_t>> handshake_response);
base::Optional<Result> GetCableDiscoveryData(
const BluetoothDevice* device) const;
base::Optional<Result> GetCableDiscoveryDataFromAuthenticatorEid(
CableEidArray authenticator_eid) const;
base::Optional<V1DiscoveryDataAndEID> GetCableDiscoveryData(
const BluetoothDevice* device);
base::Optional<V1DiscoveryDataAndEID>
GetCableDiscoveryDataFromAuthenticatorEid(CableEidArray authenticator_eid);
void RecordCableV1DiscoveryEventOnce(CableV1DiscoveryEvent event);
// FidoDeviceDiscovery:
......@@ -165,16 +139,17 @@ class COMPONENT_EXPORT(DEVICE_FIDO) FidoCableDiscovery
std::unique_ptr<BluetoothDiscoverySession> discovery_session_;
std::vector<CableDiscoveryData> discovery_data_;
FidoDeviceDiscovery::BLEObserver* const ble_observer_;
// active_authenticator_eids_ contains authenticator EIDs for which a
// handshake is currently running. Further advertisements for the same EIDs
// will be ignored.
std::set<CableEidArray> active_authenticator_eids_;
// active_devices_ contains the BLE addresses of devices for which a handshake
// is already running. Further advertisements from these devices will be
// ignored. However, devices may rotate their BLE address at will so this is
// not completely effective.
// active_devices_ contains the BLE addresses of devices for which a
// handshake is already running. Further advertisements from these devices
// will be ignored. However, devices may rotate their BLE address at will so
// this is not completely effective.
std::set<std::string> active_devices_;
base::Optional<QRGeneratorKey> qr_generator_key_;
......@@ -186,20 +161,12 @@ class COMPONENT_EXPORT(DEVICE_FIDO) FidoCableDiscovery
std::vector<std::pair<std::unique_ptr<FidoCableDevice>,
std::unique_ptr<FidoCableHandshakeHandler>>>
active_handshakes_;
base::Optional<
base::RepeatingCallback<void(std::unique_ptr<CableDiscoveryData>)>>
pairing_callback_;
network::mojom::NetworkContext* const network_context_;
// observed_devices_ caches the information from observed caBLE devices so
// that the device-log isn't spammed.
mutable base::flat_map<std::string, std::unique_ptr<ObservedDeviceData>>
base::flat_map<std::string, std::unique_ptr<ObservedDeviceData>>
observed_devices_;
// noted_obsolete_eids_ remembers QR-code EIDs that have been logged as
// valid-but-expired in order to avoid spamming the device-log.
mutable base::flat_set<CableEidArray> noted_obsolete_eids_;
bool has_v1_discovery_data_ = false;
base::flat_set<CableV1DiscoveryEvent> recorded_events_;
......
......@@ -326,9 +326,7 @@ class FakeFidoCableDiscovery : public FidoCableDiscovery {
explicit FakeFidoCableDiscovery(
std::vector<CableDiscoveryData> discovery_data)
: FidoCableDiscovery(std::move(discovery_data),
BogusQRGeneratorKey(),
/*pairing_callback=*/base::nullopt,
/*network_context=*/nullptr) {}
/*ble_observer=*/nullptr) {}
~FakeFidoCableDiscovery() override = default;
private:
......@@ -342,12 +340,6 @@ class FakeFidoCableDiscovery : public FidoCableDiscovery {
return std::make_unique<FakeHandshakeHandler>(
device, nonce, discovery_data.v1->session_pre_key);
}
static std::array<uint8_t, kCableQRDataSize> BogusQRGeneratorKey() {
std::array<uint8_t, kCableQRDataSize> ret;
memset(ret.data(), 0, ret.size());
return ret;
}
};
} // namespace
......
// Copyright 2020 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/cable/v2_discovery.h"
#include "base/bind.h"
#include "base/callback.h"
#include "base/strings/string_number_conversions.h"
#include "device/fido/cable/v2_handshake.h"
#include "device/fido/fido_parsing_utils.h"
#include "components/device_event_log/device_event_log.h"
#include "device/fido/cable/fido_tunnel_device.h"
#include "third_party/boringssl/src/include/openssl/aes.h"
namespace device {
namespace cablev2 {
Discovery::Discovery(
network::mojom::NetworkContext* network_context,
QRGeneratorKey qr_generator_key,
std::vector<std::unique_ptr<Pairing>> pairings,
base::Optional<base::RepeatingCallback<void(std::unique_ptr<Pairing>)>>
pairing_callback)
: FidoDeviceDiscovery(
FidoTransportProtocol::kCloudAssistedBluetoothLowEnergy),
network_context_(network_context),
local_identity_seed_(fido_parsing_utils::Materialize(
base::span<const uint8_t, kCableIdentityKeySeedSize>(
qr_generator_key.data(),
kCableIdentityKeySeedSize))),
qr_secret_(fido_parsing_utils::Materialize(
base::span<const uint8_t, kCableQRSecretSize>(
qr_generator_key.data() + kCableIdentityKeySeedSize,
kCableQRSecretSize))),
eid_key_(Derive<EXTENT(eid_key_)>(qr_secret_,
base::span<const uint8_t>(),
DerivedValueType::kEIDKey)),
pairings_(std::move(pairings)),
pairing_callback_(std::move(pairing_callback)) {
// TODO(agl): disabled in order to separate out CLs. Re-enable.
// static_assert(EXTENT(qr_generator_key) ==
// kCableIdentityKeySeedSize + kCableQRSecretSize,
// "");
}
Discovery::~Discovery() = default;
void Discovery::StartInternal() {
DCHECK(!started_);
for (auto& pairing : pairings_) {
tunnels_pending_advert_.emplace_back(std::make_unique<FidoTunnelDevice>(
network_context_, std::move(pairing)));
}
pairings_.clear();
started_ = true;
NotifyDiscoveryStarted(true);
std::vector<CableEidArray> pending_eids(std::move(pending_eids_));
for (const auto& eid : pending_eids) {
OnBLEAdvertSeen("", eid);
}
}
void Discovery::OnBLEAdvertSeen(const std::string& address,
const CableEidArray& eid) {
if (!started_) {
pending_eids_.push_back(eid);
return;
}
if (base::Contains(observed_eids_, eid)) {
return;
}
observed_eids_.insert(eid);
// Check whether the EID satisfies any pending tunnels.
for (std::vector<std::unique_ptr<FidoTunnelDevice>>::iterator i =
tunnels_pending_advert_.begin();
i != tunnels_pending_advert_.end(); i++) {
if (!(*i)->MatchEID(eid)) {
continue;
}
FIDO_LOG(DEBUG) << " (" << base::HexEncode(eid)
<< " matches pending tunnel)";
std::unique_ptr<FidoTunnelDevice> device(std::move(*i));
tunnels_pending_advert_.erase(i);
AddDevice(std::move(device));
return;
}
// Check whether the EID matches a QR code.
AES_KEY aes_key;
CHECK(AES_set_decrypt_key(eid_key_.data(),
/*bits=*/8 * eid_key_.size(), &aes_key) == 0);
CableEidArray plaintext;
static_assert(EXTENT(plaintext) == AES_BLOCK_SIZE, "EIDs are not AES blocks");
AES_decrypt(/*in=*/eid.data(), /*out=*/plaintext.data(), &aes_key);
if (cablev2::eid::IsValid(plaintext)) {
FIDO_LOG(DEBUG) << " (" << base::HexEncode(eid) << " matches QR code)";
AddDevice(std::make_unique<cablev2::FidoTunnelDevice>(
network_context_,
base::BindOnce(&Discovery::AddPairing, weak_factory_.GetWeakPtr()),
qr_secret_, local_identity_seed_, eid, plaintext));
return;
}
FIDO_LOG(DEBUG) << " (" << base::HexEncode(eid) << ": no v2 match)";
}
void Discovery::AddPairing(std::unique_ptr<Pairing> pairing) {
if (!pairing_callback_) {
return;
}
pairing_callback_->Run(std::move(pairing));
}
} // namespace cablev2
} // namespace device
// Copyright 2020 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.
#ifndef DEVICE_FIDO_CABLE_V2_DISCOVERY_H_
#define DEVICE_FIDO_CABLE_V2_DISCOVERY_H_
#include <memory>
#include <vector>
#include "base/component_export.h"
#include "base/callback.h"
#include "base/containers/flat_set.h"
#include "base/optional.h"
#include "base/memory/weak_ptr.h"
#include "device/fido/cable/cable_discovery_data.h"
#include "device/fido/cable/v2_constants.h"
#include "device/fido/fido_device_discovery.h"
#include "services/network/public/mojom/network_context.mojom-forward.h"
namespace device {
namespace cablev2 {
struct Pairing;
class FidoTunnelDevice;
// Discovery creates caBLEv2 devices, either based on |pairings|, or when a BLE
// advert is seen that matches |qr_generator_key|. It does not actively scan for
// BLE adverts itself. Rather it depends on |OnBLEAdvertSeen| getting called.
class COMPONENT_EXPORT(DEVICE_FIDO) Discovery
: public FidoDeviceDiscovery,
public FidoDeviceDiscovery::BLEObserver {
public:
Discovery(
network::mojom::NetworkContext* network_context,
QRGeneratorKey qr_generator_key,
std::vector<std::unique_ptr<Pairing>> pairings,
// pairing_callback will be called when a QR-initiated connection receives
// pairing information from the peer.
base::Optional<base::RepeatingCallback<void(std::unique_ptr<Pairing>)>>
pairing_callback);
~Discovery() override;
Discovery(const Discovery&) = delete;
Discovery& operator=(const Discovery&) = delete;
// FidoDeviceDiscovery:
void StartInternal() override;
// BLEObserver:
void OnBLEAdvertSeen(const std::string& address,
const CableEidArray& eid) override;
private:
void AddPairing(std::unique_ptr<Pairing> pairing);
network::mojom::NetworkContext* const network_context_;
const std::array<uint8_t, kCableIdentityKeySeedSize> local_identity_seed_;
const std::array<uint8_t, kCableQRSecretSize> qr_secret_;
const std::array<uint8_t, kEIDKeySize> eid_key_;
std::vector<std::unique_ptr<Pairing>> pairings_;
const base::Optional<base::RepeatingCallback<void(std::unique_ptr<Pairing>)>>
pairing_callback_;
std::vector<std::unique_ptr<FidoTunnelDevice>> tunnels_pending_advert_;
base::flat_set<CableEidArray> observed_eids_;
bool started_ = false;
std::vector<CableEidArray> pending_eids_;
base::WeakPtrFactory<Discovery> weak_factory_{this};
};
} // namespace cablev2
} // namespace device
#endif // DEVICE_FIDO_CABLE_V2_DISCOVERY_H_
......@@ -79,23 +79,23 @@ FakeFidoDiscovery* FakeFidoDiscoveryFactory::ForgeNextPlatformDiscovery(
return next_platform_discovery_.get();
}
std::unique_ptr<FidoDiscoveryBase> FakeFidoDiscoveryFactory::Create(
FidoTransportProtocol transport) {
std::vector<std::unique_ptr<FidoDiscoveryBase>>
FakeFidoDiscoveryFactory::Create(FidoTransportProtocol transport) {
switch (transport) {
case FidoTransportProtocol::kUsbHumanInterfaceDevice:
return std::move(next_hid_discovery_);
return SingleDiscovery(std::move(next_hid_discovery_));
case FidoTransportProtocol::kNearFieldCommunication:
return std::move(next_nfc_discovery_);
return SingleDiscovery(std::move(next_nfc_discovery_));
case FidoTransportProtocol::kBluetoothLowEnergy:
case FidoTransportProtocol::kAndroidAccessory:
return nullptr;
return {};
case FidoTransportProtocol::kCloudAssistedBluetoothLowEnergy:
return std::move(next_cable_discovery_);
return SingleDiscovery(std::move(next_cable_discovery_));
case FidoTransportProtocol::kInternal:
return std::move(next_platform_discovery_);
return SingleDiscovery(std::move(next_platform_discovery_));
}
NOTREACHED();
return nullptr;
return {};
}
} // namespace test
......
......@@ -111,7 +111,7 @@ class FakeFidoDiscoveryFactory : public device::FidoDiscoveryFactory {
StartMode mode = StartMode::kManual);
// device::FidoDiscoveryFactory:
std::unique_ptr<FidoDiscoveryBase> Create(
std::vector<std::unique_ptr<FidoDiscoveryBase>> Create(
FidoTransportProtocol transport) override;
private:
......
......@@ -147,10 +147,11 @@ TEST_F(FakeFidoDiscoveryFactoryTest, ForgesUsbFactoryFunction) {
fake_fido_discovery_factory_.ForgeNextHidDiscovery();
ASSERT_EQ(FidoTransportProtocol::kUsbHumanInterfaceDevice,
injected_fake_discovery->transport());
auto produced_discovery = fake_fido_discovery_factory_.Create(
FidoTransportProtocol::kUsbHumanInterfaceDevice);
EXPECT_TRUE(produced_discovery);
EXPECT_EQ(injected_fake_discovery, produced_discovery.get());
std::vector<std::unique_ptr<FidoDiscoveryBase>> produced_discoveries =
fake_fido_discovery_factory_.Create(
FidoTransportProtocol::kUsbHumanInterfaceDevice);
ASSERT_EQ(produced_discoveries.size(), 1u);
EXPECT_EQ(injected_fake_discovery, produced_discoveries[0].get());
}
#endif
......
......@@ -14,6 +14,7 @@
namespace device {
FidoDeviceDiscovery::BLEObserver::~BLEObserver() = default;
FidoDeviceDiscovery::Observer::~Observer() = default;
FidoDeviceDiscovery::FidoDeviceDiscovery(FidoTransportProtocol transport)
......
......@@ -27,6 +27,15 @@ class FidoDeviceAuthenticator;
class COMPONENT_EXPORT(DEVICE_FIDO) FidoDeviceDiscovery
: public FidoDiscoveryBase {
public:
// BLEObserver is an interface for discoveries that watch for BLE adverts.
class BLEObserver {
public:
virtual ~BLEObserver();
virtual void OnBLEAdvertSeen(const std::string& address,
const std::array<uint8_t, 16>& eid) = 0;
};
enum class State {
kIdle,
kStarting,
......
......@@ -8,6 +8,7 @@
#include "device/bluetooth/bluetooth_adapter_factory.h"
#include "device/fido/aoa/android_accessory_discovery.h"
#include "device/fido/cable/fido_cable_discovery.h"
#include "device/fido/cable/v2_discovery.h"
#include "device/fido/features.h"
#include "device/fido/fido_discovery_base.h"
......@@ -35,39 +36,60 @@ namespace device {
FidoDiscoveryFactory::FidoDiscoveryFactory() = default;
FidoDiscoveryFactory::~FidoDiscoveryFactory() = default;
std::unique_ptr<FidoDiscoveryBase> FidoDiscoveryFactory::Create(
std::vector<std::unique_ptr<FidoDiscoveryBase>> FidoDiscoveryFactory::Create(
FidoTransportProtocol transport) {
switch (transport) {
case FidoTransportProtocol::kUsbHumanInterfaceDevice:
return std::make_unique<FidoHidDiscovery>(hid_ignore_list_);
return SingleDiscovery(
std::make_unique<FidoHidDiscovery>(hid_ignore_list_));
case FidoTransportProtocol::kBluetoothLowEnergy:
return nullptr;
return {};
case FidoTransportProtocol::kCloudAssistedBluetoothLowEnergy:
if (device::BluetoothAdapterFactory::Get()->IsLowEnergySupported() &&
(cable_data_.has_value() || qr_generator_key_.has_value())) {
return std::make_unique<FidoCableDiscovery>(
cable_data_.value_or(std::vector<CableDiscoveryData>()),
qr_generator_key_, cable_pairing_callback_, network_context_);
std::unique_ptr<cablev2::Discovery> v2_discovery;
if (qr_generator_key_.has_value()) {
v2_discovery = std::make_unique<cablev2::Discovery>(
network_context_, *qr_generator_key_, std::move(v2_pairings_),
std::move(cable_pairing_callback_));
}
std::unique_ptr<FidoDiscoveryBase> v1_discovery =
std::make_unique<FidoCableDiscovery>(
cable_data_.value_or(std::vector<CableDiscoveryData>()),
v2_discovery ? v2_discovery.get() : nullptr);
std::vector<std::unique_ptr<FidoDiscoveryBase>> ret;
if (v2_discovery) {
ret.emplace_back(std::move(v2_discovery));
}
ret.emplace_back(std::move(v1_discovery));
return ret;
}
return nullptr;
return {};
case FidoTransportProtocol::kNearFieldCommunication:
// TODO(https://crbug.com/825949): Add NFC support.
return nullptr;
case FidoTransportProtocol::kInternal:
return {};
case FidoTransportProtocol::kInternal: {
#if defined(OS_MAC) || defined(OS_CHROMEOS)
return MaybeCreatePlatformDiscovery();
std::unique_ptr<FidoDiscoveryBase> discovery =
MaybeCreatePlatformDiscovery();
if (discovery) {
return SingleDiscovery(std::move(discovery));
}
return {};
#else
return nullptr;
return {};
#endif
}
case FidoTransportProtocol::kAndroidAccessory:
if (usb_device_manager_) {
return std::make_unique<AndroidAccessoryDiscovery>(
std::move(usb_device_manager_.value()));
return SingleDiscovery(std::make_unique<AndroidAccessoryDiscovery>(
std::move(usb_device_manager_.value())));
}
return nullptr;
return {};
}
NOTREACHED() << "Unhandled transport type";
return nullptr;
return {};
}
bool FidoDiscoveryFactory::IsTestOverride() {
......@@ -76,9 +98,11 @@ bool FidoDiscoveryFactory::IsTestOverride() {
void FidoDiscoveryFactory::set_cable_data(
std::vector<CableDiscoveryData> cable_data,
base::Optional<QRGeneratorKey> qr_generator_key) {
base::Optional<QRGeneratorKey> qr_generator_key,
std::vector<std::unique_ptr<cablev2::Pairing>> v2_pairings) {
cable_data_ = std::move(cable_data);
qr_generator_key_ = std::move(qr_generator_key);
v2_pairings_ = std::move(v2_pairings);
}
void FidoDiscoveryFactory::set_usb_device_manager(
......@@ -92,7 +116,7 @@ void FidoDiscoveryFactory::set_network_context(
}
void FidoDiscoveryFactory::set_cable_pairing_callback(
base::RepeatingCallback<void(std::unique_ptr<CableDiscoveryData>)>
base::RepeatingCallback<void(std::unique_ptr<cablev2::Pairing>)>
pairing_callback) {
cable_pairing_callback_.emplace(std::move(pairing_callback));
}
......@@ -102,6 +126,19 @@ void FidoDiscoveryFactory::set_hid_ignore_list(
hid_ignore_list_ = std::move(hid_ignore_list);
}
// static
std::vector<std::unique_ptr<FidoDiscoveryBase>>
FidoDiscoveryFactory::SingleDiscovery(
std::unique_ptr<FidoDiscoveryBase> discovery) {
if (!discovery) {
return {};
}
std::vector<std::unique_ptr<FidoDiscoveryBase>> ret;
ret.emplace_back(std::move(discovery));
return ret;
}
#if defined(OS_WIN)
void FidoDiscoveryFactory::set_win_webauthn_api(WinWebAuthnApi* api) {
win_webauthn_api_ = api;
......
......@@ -38,10 +38,10 @@ class COMPONENT_EXPORT(DEVICE_FIDO) FidoDiscoveryFactory {
FidoDiscoveryFactory();
virtual ~FidoDiscoveryFactory();
// Instantiates a FidoDiscoveryBase for the given transport.
// Instantiates one or more FidoDiscoveryBases for the given transport.
//
// FidoTransportProtocol::kUsbHumanInterfaceDevice is not valid on Android.
virtual std::unique_ptr<FidoDiscoveryBase> Create(
virtual std::vector<std::unique_ptr<FidoDiscoveryBase>> Create(
FidoTransportProtocol transport);
// Returns whether the current instance is an override injected by the
......@@ -49,8 +49,10 @@ class COMPONENT_EXPORT(DEVICE_FIDO) FidoDiscoveryFactory {
virtual bool IsTestOverride();
// set_cable_data configures caBLE obtained via a WebAuthn extension.
void set_cable_data(std::vector<CableDiscoveryData> cable_data,
base::Optional<QRGeneratorKey> qr_generator_key);
void set_cable_data(
std::vector<CableDiscoveryData> cable_data,
base::Optional<QRGeneratorKey> qr_generator_key,
std::vector<std::unique_ptr<cablev2::Pairing>> v2_pairings);
void set_usb_device_manager(mojo::Remote<device::mojom::UsbDeviceManager>);
......@@ -60,7 +62,7 @@ class COMPONENT_EXPORT(DEVICE_FIDO) FidoDiscoveryFactory {
// called when a QR handshake results in a phone wishing to pair with this
// browser.
void set_cable_pairing_callback(
base::RepeatingCallback<void(std::unique_ptr<CableDiscoveryData>)>);
base::RepeatingCallback<void(std::unique_ptr<cablev2::Pairing>)>);
void set_hid_ignore_list(base::flat_set<VidPid> hid_ignore_list);
......@@ -84,6 +86,10 @@ class COMPONENT_EXPORT(DEVICE_FIDO) FidoDiscoveryFactory {
WinWebAuthnApi* win_webauthn_api() const;
#endif // defined(OS_WIN)
protected:
static std::vector<std::unique_ptr<FidoDiscoveryBase>> SingleDiscovery(
std::unique_ptr<FidoDiscoveryBase> discovery);
private:
#if defined(OS_MAC) || defined(OS_CHROMEOS)
std::unique_ptr<FidoDiscoveryBase> MaybeCreatePlatformDiscovery() const;
......@@ -97,8 +103,9 @@ class COMPONENT_EXPORT(DEVICE_FIDO) FidoDiscoveryFactory {
network::mojom::NetworkContext* network_context_ = nullptr;
base::Optional<std::vector<CableDiscoveryData>> cable_data_;
base::Optional<QRGeneratorKey> qr_generator_key_;
std::vector<std::unique_ptr<cablev2::Pairing>> v2_pairings_;
base::Optional<
base::RepeatingCallback<void(std::unique_ptr<CableDiscoveryData>)>>
base::RepeatingCallback<void(std::unique_ptr<cablev2::Pairing>)>>
cable_pairing_callback_;
#if defined(OS_WIN)
WinWebAuthnApi* win_webauthn_api_ = nullptr;
......
......@@ -62,9 +62,9 @@ void FidoRequestHandlerBase::InitDiscoveries(
const base::flat_set<FidoTransportProtocol>& available_transports) {
transport_availability_info_.available_transports = available_transports;
for (const auto transport : available_transports) {
std::unique_ptr<FidoDiscoveryBase> discovery =
std::vector<std::unique_ptr<FidoDiscoveryBase>> discoveries =
fido_discovery_factory->Create(transport);
if (discovery == nullptr) {
if (discoveries.empty()) {
// This can occur in tests when a ScopedVirtualU2fDevice is in effect and
// HID transports are not configured or when caBLE discovery data isn't
// available.
......@@ -72,8 +72,10 @@ void FidoRequestHandlerBase::InitDiscoveries(
continue;
}
discovery->set_observer(this);
discoveries_.push_back(std::move(discovery));
for (auto& discovery : discoveries) {
discovery->set_observer(this);
discoveries_.emplace_back(std::move(discovery));
}
}
// Check if the platform supports BLE before trying to get a power manager.
......
......@@ -80,13 +80,13 @@ VirtualFidoDevice::State* VirtualFidoDeviceFactory::mutable_state() {
return state_.get();
}
std::unique_ptr<FidoDiscoveryBase> VirtualFidoDeviceFactory::Create(
FidoTransportProtocol transport) {
std::vector<std::unique_ptr<FidoDiscoveryBase>>
VirtualFidoDeviceFactory::Create(FidoTransportProtocol transport) {
if (transport != transport_) {
return nullptr;
return {};
}
return std::make_unique<VirtualFidoDeviceDiscovery>(
transport_, state_, supported_protocol_, ctap2_config_);
return SingleDiscovery(std::make_unique<VirtualFidoDeviceDiscovery>(
transport_, state_, supported_protocol_, ctap2_config_));
}
bool VirtualFidoDeviceFactory::IsTestOverride() {
......
......@@ -39,7 +39,7 @@ class VirtualFidoDeviceFactory : public device::FidoDiscoveryFactory {
protected:
// device::FidoDiscoveryFactory:
std::unique_ptr<FidoDiscoveryBase> Create(
std::vector<std::unique_ptr<FidoDiscoveryBase>> Create(
FidoTransportProtocol transport) override;
bool IsTestOverride() override;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment