Commit f96166b9 authored by Jun Choi's avatar Jun Choi Committed by Commit Bot

Add handshake protocol to Cable discovery

After connecting to Cable authenticator using advertisement/scanning,
Cable protocol requires one more round trip of BLE control messages to
be sent to establish shared secret key for encryption. Add this
handshake protocol to FidoCableDiscovery.

Bug: 849307
Change-Id: I388fa43dae60e97e027dafa1f9f430a2569ca981
Reviewed-on: https://chromium-review.googlesource.com/1089794
Commit-Queue: Jun Choi <hongjunchoi@chromium.org>
Reviewed-by: default avatarDaniel Cheng <dcheng@chromium.org>
Reviewed-by: default avatarJan Wilken Dörrie <jdoerrie@chromium.org>
Cr-Commit-Position: refs/heads/master@{#568334}
parent fb51f91a
......@@ -180,13 +180,13 @@ TypeConverter<std::vector<::device::FidoCableDiscovery::CableDiscoveryData>,
std::copy(data->authenticator_eid.begin(), data->authenticator_eid.end(),
authenticator_eid.begin());
::device::FidoCableDiscovery::SessionKeyArray session_key;
DCHECK_EQ(session_key.size(), data->session_pre_key.size());
::device::FidoCableDiscovery::SessionPreKeyArray session_pre_key;
DCHECK_EQ(session_pre_key.size(), data->session_pre_key.size());
std::copy(data->session_pre_key.begin(), data->session_pre_key.end(),
session_key.begin());
session_pre_key.begin());
discovery_data.push_back(::device::FidoCableDiscovery::CableDiscoveryData{
data->version, client_eid, authenticator_eid, session_key});
data->version, client_eid, authenticator_eid, session_pre_key});
}
return discovery_data;
......
......@@ -6,7 +6,6 @@
#include <utility>
#include "base/command_line.h"
#include "base/strings/string_piece.h"
#include "base/threading/thread_task_runner_handle.h"
#include "device/fido/fido_ble_connection.h"
......@@ -16,10 +15,6 @@
namespace device {
namespace switches {
constexpr char kEnableCableEncryption[] = "enable-cable-encryption";
} // namespace switches
namespace {
// Maximum size of EncryptionData::read_sequence_num or
......@@ -27,12 +22,6 @@ namespace {
// counter larger than |kMaxCounter| FidoCableDevice should error out.
constexpr size_t kMaxCounter = (1 << 24) - 1;
// static
bool IsEncryptionEnabled() {
base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
return command_line->HasSwitch(switches::kEnableCableEncryption);
}
base::Optional<std::vector<uint8_t>> ConstructEncryptionNonce(
base::span<const uint8_t> nonce,
bool is_sender_client,
......@@ -49,17 +38,20 @@ base::Optional<std::vector<uint8_t>> ConstructEncryptionNonce(
}
bool EncryptOutgoingMessage(
const FidoCableDevice::EncryptionData& encryption_data,
const base::Optional<FidoCableDevice::EncryptionData>& encryption_data,
std::vector<uint8_t>* message_to_encrypt) {
if (!encryption_data)
return false;
const auto nonce = ConstructEncryptionNonce(
encryption_data.nonce, true /* is_sender_client */,
encryption_data.write_sequence_num);
encryption_data->nonce, true /* is_sender_client */,
encryption_data->write_sequence_num);
if (!nonce)
return false;
DCHECK_EQ(nonce->size(), encryption_data.aes_key.NonceLength());
DCHECK_EQ(nonce->size(), encryption_data->aes_key.NonceLength());
std::string ciphertext;
bool encryption_success = encryption_data.aes_key.Seal(
bool encryption_success = encryption_data->aes_key.Seal(
fido_parsing_utils::ConvertToStringPiece(*message_to_encrypt),
fido_parsing_utils::ConvertToStringPiece(*nonce),
std::string(1, base::strict_cast<uint8_t>(FidoBleDeviceCommand::kMsg)),
......@@ -131,23 +123,14 @@ FidoCableDevice::~FidoCableDevice() = default;
void FidoCableDevice::DeviceTransact(std::vector<uint8_t> command,
DeviceCallback callback) {
if (!encryption_data_) {
if (!EncryptOutgoingMessage(encryption_data_, &command)) {
base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE, base::BindOnce(std::move(callback), base::nullopt));
state_ = State::kDeviceError;
return;
}
if (IsEncryptionEnabled()) {
if (!EncryptOutgoingMessage(*encryption_data_, &command)) {
base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE, base::BindOnce(std::move(callback), base::nullopt));
state_ = State::kDeviceError;
return;
}
++encryption_data_->write_sequence_num;
}
AddToPendingFrames(FidoBleDeviceCommand::kMsg, std::move(command),
std::move(callback));
......@@ -159,8 +142,7 @@ void FidoCableDevice::OnResponseFrame(FrameCallback callback,
ResetTransaction();
state_ = frame ? State::kReady : State::kDeviceError;
if (IsEncryptionEnabled() && frame &&
frame->command() != FidoBleDeviceCommand::kControl) {
if (frame && frame->command() != FidoBleDeviceCommand::kControl) {
if (!DecryptIncomingMessage(encryption_data_, &frame.value())) {
state_ = State::kDeviceError;
frame = base::nullopt;
......
......@@ -149,11 +149,6 @@ class FidoCableDeviceTest : public Test {
device()->Connect();
}
void SetUpEncryptionSwitch() {
base::CommandLine::ForCurrentProcess()->AppendSwitch(
"enable-cable-encryption");
}
FidoCableDevice* device() { return device_.get(); }
MockFidoBleConnection* connection() { return connection_; }
FakeCableAuthenticator* authenticator() { return &authenticator_; }
......@@ -168,7 +163,6 @@ class FidoCableDeviceTest : public Test {
};
TEST_F(FidoCableDeviceTest, TestCaBleDeviceSendData) {
SetUpEncryptionSwitch();
ConnectWithLength(kControlPointLength);
EXPECT_CALL(*connection(), WriteControlPointPtr(_, _))
......@@ -197,7 +191,6 @@ TEST_F(FidoCableDeviceTest, TestCaBleDeviceSendData) {
// Test that FidoCableDevice properly updates counters when sending/receiving
// multiple requests.
TEST_F(FidoCableDeviceTest, TestCableDeviceSendMultipleRequests) {
SetUpEncryptionSwitch();
ConnectWithLength(kControlPointLength);
EXPECT_CALL(*connection(), WriteControlPointPtr(_, _))
.Times(2)
......@@ -241,7 +234,6 @@ TEST_F(FidoCableDeviceTest, TestCableDeviceSendMultipleRequests) {
TEST_F(FidoCableDeviceTest, TestCableDeviceFailOnIncorrectSessionKey) {
constexpr char kIncorrectSessionKey[] = "11111111111111111111111111111111";
SetUpEncryptionSwitch();
ConnectWithLength(kControlPointLength);
EXPECT_CALL(*connection(), WriteControlPointPtr(_, _))
......@@ -271,7 +263,6 @@ TEST_F(FidoCableDeviceTest, TestCableDeviceFailOnIncorrectSessionKey) {
TEST_F(FidoCableDeviceTest, TestCableDeviceFailOnUnexpectedCounter) {
constexpr uint32_t kIncorrectAuthenticatorCounter = 1;
SetUpEncryptionSwitch();
ConnectWithLength(kControlPointLength);
EXPECT_CALL(*connection(), WriteControlPointPtr(_, _))
......@@ -307,7 +298,6 @@ TEST_F(FidoCableDeviceTest, TestCableDeviceFailOnUnexpectedCounter) {
// the expected counter value -- should return an error.
TEST_F(FidoCableDeviceTest, TestCableDeviceErrorOnMaxCounter) {
ConnectWithLength(kControlPointLength);
SetUpEncryptionSwitch();
EXPECT_CALL(*connection(), WriteControlPointPtr(_, _))
.WillOnce(Invoke([this](const auto& data, auto* cb) {
......@@ -335,26 +325,4 @@ TEST_F(FidoCableDeviceTest, TestCableDeviceErrorOnMaxCounter) {
EXPECT_FALSE(value);
}
TEST_F(FidoCableDeviceTest, TestEncryptionDisabledWithoutCommandLineSwitch) {
ConnectWithLength(kControlPointLength);
EXPECT_CALL(*connection(), WriteControlPointPtr(_, _))
.WillOnce(Invoke([this](const auto& data, auto* cb) {
base::SequencedTaskRunnerHandle::Get()->PostTask(
FROM_HERE, base::BindOnce(std::move(*cb), true));
base::SequencedTaskRunnerHandle::Get()->PostTask(
FROM_HERE, base::BindOnce(connection()->read_callback(), data));
}));
TestDeviceCallbackReceiver callback_receiver;
device()->DeviceTransact(fido_parsing_utils::Materialize(kTestData),
callback_receiver.callback());
callback_receiver.WaitForCallback();
const auto& value = callback_receiver.value();
ASSERT_TRUE(value);
EXPECT_THAT(*value, ::testing::ElementsAreArray(kTestData));
}
} // namespace device
......@@ -19,6 +19,7 @@
#include "device/bluetooth/bluetooth_uuid.h"
#include "device/fido/fido_ble_uuids.h"
#include "device/fido/fido_cable_device.h"
#include "device/fido/fido_cable_handshake_handler.h"
#include "device/fido/fido_parsing_utils.h"
namespace device {
......@@ -122,11 +123,11 @@ FidoCableDiscovery::CableDiscoveryData::CableDiscoveryData(
uint8_t version,
const EidArray& client_eid,
const EidArray& authenticator_eid,
const SessionKeyArray& session_key)
const SessionPreKeyArray& session_pre_key)
: version(version),
client_eid(client_eid),
authenticator_eid(authenticator_eid),
session_key(session_key) {}
session_pre_key(session_pre_key) {}
FidoCableDiscovery::CableDiscoveryData::CableDiscoveryData(
const CableDiscoveryData& data) = default;
......@@ -148,6 +149,15 @@ FidoCableDiscovery::~FidoCableDiscovery() {
advertisement.second->Unregister(base::DoNothing(), base::DoNothing());
}
std::unique_ptr<FidoCableHandshakeHandler>
FidoCableDiscovery::CreateHandshakeHandler(
FidoCableDevice* device,
base::span<const uint8_t, kSessionPreKeySize> session_pre_key,
base::span<const uint8_t, 8> nonce) {
return std::make_unique<FidoCableHandshakeHandler>(device, nonce,
session_pre_key);
}
void FidoCableDiscovery::DeviceAdded(BluetoothAdapter* adapter,
BluetoothDevice* device) {
if (!IsCableDevice(device))
......@@ -254,11 +264,42 @@ void FidoCableDiscovery::CableDeviceFound(BluetoothAdapter* adapter,
found_cable_device_data->client_eid, 0, &nonce);
if (!extract_success)
return;
auto cable_device = std::make_unique<FidoCableDevice>(device->GetAddress());
cable_device->SetEncryptionData(
std::string(found_cable_device_data->session_key.begin(),
found_cable_device_data->session_key.end()),
nonce);
// At most one handshake messages should be exchanged for each Cable device.
if (!base::ContainsKey(cable_handshake_handlers_, cable_device->GetId())) {
ConductEncryptionHandshake(std::move(cable_device),
found_cable_device_data->session_pre_key, nonce);
}
}
void FidoCableDiscovery::ConductEncryptionHandshake(
std::unique_ptr<FidoCableDevice> cable_device,
base::span<const uint8_t, kSessionPreKeySize> session_pre_key,
base::span<const uint8_t, 8> nonce) {
auto handshake_handler =
CreateHandshakeHandler(cable_device.get(), session_pre_key, nonce);
auto* const handshake_handler_ptr = handshake_handler.get();
cable_handshake_handlers_.emplace(cable_device->GetId(),
std::move(handshake_handler));
handshake_handler_ptr->InitiateCableHandshake(
base::BindOnce(&FidoCableDiscovery::ValidateAuthenticatorHandshakeMessage,
weak_factory_.GetWeakPtr(), std::move(cable_device),
handshake_handler_ptr));
}
void FidoCableDiscovery::ValidateAuthenticatorHandshakeMessage(
std::unique_ptr<FidoCableDevice> cable_device,
FidoCableHandshakeHandler* handshake_handler,
base::Optional<std::vector<uint8_t>> handshake_response) {
if (!handshake_response)
return;
if (!handshake_handler->ValidateAuthenticatorHandshakeMessage(
*handshake_response))
return;
AddDevice(std::move(cable_device));
}
......
......@@ -9,11 +9,12 @@
#include <array>
#include <map>
#include <set>
#include <memory>
#include <string>
#include <vector>
#include "base/component_export.h"
#include "base/containers/span.h"
#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "base/memory/weak_ptr.h"
......@@ -21,16 +22,18 @@
namespace device {
class FidoCableDevice;
class BluetoothDevice;
class BluetoothAdvertisement;
class FidoCableHandshakeHandler;
class COMPONENT_EXPORT(DEVICE_FIDO) FidoCableDiscovery
: public FidoBleDiscoveryBase {
public:
static constexpr size_t kEphemeralIdSize = 16;
static constexpr size_t kSessionKeySize = 32;
static constexpr size_t kSessionPreKeySize = 32;
using EidArray = std::array<uint8_t, kEphemeralIdSize>;
using SessionKeyArray = std::array<uint8_t, kSessionKeySize>;
using SessionPreKeyArray = std::array<uint8_t, kSessionPreKeySize>;
// Encapsulates information required to discover Cable device per single
// credential. When multiple credentials are enrolled to a single account
......@@ -43,7 +46,7 @@ class COMPONENT_EXPORT(DEVICE_FIDO) FidoCableDiscovery
CableDiscoveryData(uint8_t version,
const EidArray& client_eid,
const EidArray& authenticator_eid,
const SessionKeyArray& session_key);
const SessionPreKeyArray& session_pre_key);
CableDiscoveryData(const CableDiscoveryData& data);
CableDiscoveryData& operator=(const CableDiscoveryData& other);
~CableDiscoveryData();
......@@ -51,12 +54,18 @@ class COMPONENT_EXPORT(DEVICE_FIDO) FidoCableDiscovery
uint8_t version;
EidArray client_eid;
EidArray authenticator_eid;
SessionKeyArray session_key;
SessionPreKeyArray session_pre_key;
};
FidoCableDiscovery(std::vector<CableDiscoveryData> discovery_data);
~FidoCableDiscovery() override;
protected:
virtual std::unique_ptr<FidoCableHandshakeHandler> CreateHandshakeHandler(
FidoCableDevice* device,
base::span<const uint8_t, kSessionPreKeySize> session_pre_key,
base::span<const uint8_t, 8> nonce);
private:
FRIEND_TEST_ALL_PREFIXES(FidoCableDiscoveryTest,
TestUnregisterAdvertisementUponDestruction);
......@@ -83,6 +92,15 @@ class COMPONENT_EXPORT(DEVICE_FIDO) FidoCableDiscovery
// once all advertisements has been processed.
void RecordAdvertisementResult(bool is_success);
void CableDeviceFound(BluetoothAdapter* adapter, BluetoothDevice* device);
void ConductEncryptionHandshake(
std::unique_ptr<FidoCableDevice> device,
base::span<const uint8_t, kSessionPreKeySize> session_pre_key,
base::span<const uint8_t, 8> nonce);
void ValidateAuthenticatorHandshakeMessage(
std::unique_ptr<FidoCableDevice> cable_device,
FidoCableHandshakeHandler* handshake_handler,
base::Optional<std::vector<uint8_t>> handshake_response);
const CableDiscoveryData* GetFoundCableDiscoveryData(
const BluetoothDevice* device) const;
......@@ -90,6 +108,8 @@ class COMPONENT_EXPORT(DEVICE_FIDO) FidoCableDiscovery
size_t advertisement_success_counter_ = 0;
size_t advertisement_failure_counter_ = 0;
std::map<EidArray, scoped_refptr<BluetoothAdvertisement>> advertisements_;
std::map<std::string, std::unique_ptr<FidoCableHandshakeHandler>>
cable_handshake_handlers_;
base::WeakPtrFactory<FidoCableDiscovery> weak_factory_;
DISALLOW_COPY_AND_ASSIGN(FidoCableDiscovery);
......
......@@ -8,6 +8,7 @@
#include <memory>
#include <utility>
#include "base/containers/span.h"
#include "base/stl_util.h"
#include "build/build_config.h"
#include "device/bluetooth/bluetooth_adapter_factory.h"
......@@ -16,6 +17,7 @@
#include "device/bluetooth/test/mock_bluetooth_adapter.h"
#include "device/fido/fido_ble_device.h"
#include "device/fido/fido_ble_uuids.h"
#include "device/fido/fido_cable_handshake_handler.h"
#include "device/fido/fido_parsing_utils.h"
#include "device/fido/mock_fido_discovery_observer.h"
#include "testing/gmock/include/gmock/gmock.h"
......@@ -47,7 +49,7 @@ constexpr FidoCableDiscovery::EidArray kInvalidAuthenticatorEid = {
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00}};
constexpr FidoCableDiscovery::SessionKeyArray kTestSessionKey = {
constexpr FidoCableDiscovery::SessionPreKeyArray kTestSessionPreKey = {
{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}};
......@@ -63,7 +65,7 @@ constexpr FidoCableDiscovery::EidArray kSecondaryAuthenticatorEid = {
{0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee,
0xee, 0xee, 0xee, 0xee}};
constexpr FidoCableDiscovery::SessionKeyArray kSecondarySessionKey = {
constexpr FidoCableDiscovery::SessionPreKeyArray kSecondarySessionPreKey = {
{0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd}};
......@@ -203,6 +205,44 @@ class CableMockAdapter : public MockBluetoothAdapter {
~CableMockAdapter() override = default;
};
class FakeHandshakeHandler : public FidoCableHandshakeHandler {
public:
FakeHandshakeHandler(FidoCableDevice* device,
base::span<const uint8_t, 8> nonce,
base::span<const uint8_t, 32> session_pre_key)
: FidoCableHandshakeHandler(device, nonce, session_pre_key) {}
~FakeHandshakeHandler() override = default;
void InitiateCableHandshake(FidoDevice::DeviceCallback callback) override {
std::move(callback).Run(std::vector<uint8_t>());
}
bool ValidateAuthenticatorHandshakeMessage(
base::span<const uint8_t> response) override {
return true;
}
};
// Fake discovery that encapsulates exactly the same behavior as
// FidoCableDiscovery except that it uses FakeHandshakeHandler instead of
// FidoHandshakeHandler to conduct handshake with the authenticator.
class FakeFidoCableDiscovery : public FidoCableDiscovery {
public:
explicit FakeFidoCableDiscovery(
std::vector<CableDiscoveryData> discovery_data)
: FidoCableDiscovery(std::move(discovery_data)) {}
~FakeFidoCableDiscovery() override = default;
private:
std::unique_ptr<FidoCableHandshakeHandler> CreateHandshakeHandler(
FidoCableDevice* device,
base::span<const uint8_t, kSessionPreKeySize> session_pre_key,
base::span<const uint8_t, 8> nonce) override {
return std::make_unique<FakeHandshakeHandler>(device, nonce,
session_pre_key);
}
};
} // namespace
class FidoCableDiscoveryTest : public ::testing::Test {
......@@ -210,8 +250,8 @@ class FidoCableDiscoveryTest : public ::testing::Test {
std::unique_ptr<FidoCableDiscovery> CreateDiscovery() {
std::vector<FidoCableDiscovery::CableDiscoveryData> discovery_data;
discovery_data.emplace_back(kTestCableVersionNumber, kClientEid,
kAuthenticatorEid, kTestSessionKey);
return std::make_unique<FidoCableDiscovery>(std::move(discovery_data));
kAuthenticatorEid, kTestSessionPreKey);
return std::make_unique<FakeFidoCableDiscovery>(std::move(discovery_data));
}
base::test::ScopedTaskEnvironment scoped_task_environment_;
......@@ -273,11 +313,12 @@ TEST_F(FidoCableDiscoveryTest, TestDiscoveryFindsIncorrectDevice) {
TEST_F(FidoCableDiscoveryTest, TestDiscoveryWithMultipleEids) {
std::vector<FidoCableDiscovery::CableDiscoveryData> discovery_data;
discovery_data.emplace_back(kTestCableVersionNumber, kClientEid,
kAuthenticatorEid, kTestSessionKey);
kAuthenticatorEid, kTestSessionPreKey);
discovery_data.emplace_back(kTestCableVersionNumber, kSecondaryClientEid,
kSecondaryAuthenticatorEid, kSecondarySessionKey);
kSecondaryAuthenticatorEid,
kSecondarySessionPreKey);
auto cable_discovery =
std::make_unique<FidoCableDiscovery>(std::move(discovery_data));
std::make_unique<FakeFidoCableDiscovery>(std::move(discovery_data));
NiceMock<MockFidoDiscoveryObserver> mock_observer;
EXPECT_CALL(mock_observer, DeviceAdded(_, _));
cable_discovery->set_observer(&mock_observer);
......@@ -308,11 +349,12 @@ TEST_F(FidoCableDiscoveryTest, TestDiscoveryWithMultipleEids) {
TEST_F(FidoCableDiscoveryTest, TestDiscoveryWithPartialAdvertisementSuccess) {
std::vector<FidoCableDiscovery::CableDiscoveryData> discovery_data;
discovery_data.emplace_back(kTestCableVersionNumber, kClientEid,
kAuthenticatorEid, kTestSessionKey);
kAuthenticatorEid, kTestSessionPreKey);
discovery_data.emplace_back(kTestCableVersionNumber, kSecondaryClientEid,
kSecondaryAuthenticatorEid, kSecondarySessionKey);
kSecondaryAuthenticatorEid,
kSecondarySessionPreKey);
auto cable_discovery =
std::make_unique<FidoCableDiscovery>(std::move(discovery_data));
std::make_unique<FakeFidoCableDiscovery>(std::move(discovery_data));
NiceMock<MockFidoDiscoveryObserver> mock_observer;
EXPECT_CALL(mock_observer, DeviceAdded(_, _));
cable_discovery->set_observer(&mock_observer);
......@@ -341,11 +383,12 @@ TEST_F(FidoCableDiscoveryTest, TestDiscoveryWithPartialAdvertisementSuccess) {
TEST_F(FidoCableDiscoveryTest, TestDiscoveryWithAdvertisementFailures) {
std::vector<FidoCableDiscovery::CableDiscoveryData> discovery_data;
discovery_data.emplace_back(kTestCableVersionNumber, kClientEid,
kAuthenticatorEid, kTestSessionKey);
kAuthenticatorEid, kTestSessionPreKey);
discovery_data.emplace_back(kTestCableVersionNumber, kSecondaryClientEid,
kSecondaryAuthenticatorEid, kSecondarySessionKey);
kSecondaryAuthenticatorEid,
kSecondarySessionPreKey);
auto cable_discovery =
std::make_unique<FidoCableDiscovery>(std::move(discovery_data));
std::make_unique<FakeFidoCableDiscovery>(std::move(discovery_data));
NiceMock<MockFidoDiscoveryObserver> mock_observer;
EXPECT_CALL(mock_observer, DeviceAdded(_, _)).Times(0);
......
......@@ -32,10 +32,10 @@ class COMPONENT_EXPORT(DEVICE_FIDO) FidoCableHandshakeHandler {
FidoCableHandshakeHandler(FidoCableDevice* device,
base::span<const uint8_t, 8> nonce,
base::span<const uint8_t, 32> session_pre_key);
~FidoCableHandshakeHandler();
virtual ~FidoCableHandshakeHandler();
void InitiateCableHandshake(FidoDevice::DeviceCallback callback);
bool ValidateAuthenticatorHandshakeMessage(
virtual void InitiateCableHandshake(FidoDevice::DeviceCallback callback);
virtual bool ValidateAuthenticatorHandshakeMessage(
base::span<const uint8_t> response);
private:
......
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