Commit 4d4269c3 authored by Adam Langley's avatar Adam Langley Committed by Commit Bot

device/fido: add caBLE v2 handshake infrastructure.

This change isn't intended to have any semantic effect but adds
infrastructure for a caBLE v2 handshake based around Noise NNpsk0. The
implementation has been run against the Noise Explorer implementation[1]
to confirm that it matches the spec.

[1] https://noiseexplorer.com/patterns/NNpsk0/

Change-Id: Iff92bcddfb5b4d07280ef4df5331e471d18bdd18
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1752936
Commit-Queue: Adam Langley <agl@chromium.org>
Reviewed-by: default avatarMartin Kreichgauer <martinkr@google.com>
Cr-Commit-Position: refs/heads/master@{#688339}
parent dae91f52
......@@ -305,6 +305,21 @@ fuzzer_test("fido_cable_handshake_handler_fuzzer") {
libfuzzer_options = [ "max_len=2048" ]
}
fuzzer_test("fido_cable_handshake_handler_v2_fuzzer") {
sources = [
"cable/fido_cable_handshake_handler_v2_fuzzer.cc",
]
deps = [
":fido",
"//base",
"//base/test:test_support",
"//device/bluetooth:mocks",
"//testing/gmock",
"//testing/gtest",
]
libfuzzer_options = [ "max_len=2048" ]
}
is_linux_without_udev = is_linux && !use_udev
source_set("test_support") {
......
......@@ -23,6 +23,7 @@
#include "device/fido/ble/fido_ble_uuids.h"
#include "device/fido/cable/fido_cable_device.h"
#include "device/fido/cable/fido_cable_handshake_handler.h"
#include "device/fido/features.h"
#include "device/fido/fido_parsing_utils.h"
#include "third_party/boringssl/src/include/openssl/digest.h"
#include "third_party/boringssl/src/include/openssl/hkdf.h"
......@@ -189,13 +190,39 @@ FidoCableDiscovery::~FidoCableDiscovery() {
advertisement.second->Unregister(base::DoNothing(), base::DoNothing());
}
std::unique_ptr<FidoCableHandshakeHandler>
base::Optional<std::unique_ptr<FidoCableHandshakeHandler>>
FidoCableDiscovery::CreateHandshakeHandler(
FidoCableDevice* device,
base::span<const uint8_t, kCableSessionPreKeySize> session_pre_key,
base::span<const uint8_t, 8> nonce) {
return std::make_unique<FidoCableHandshakeHandler>(device, nonce,
session_pre_key);
const CableDiscoveryData* discovery_data) {
std::unique_ptr<FidoCableHandshakeHandler> handler;
switch (discovery_data->version) {
case 1: {
// Nonce is embedded as first 8 bytes of client EID.
std::array<uint8_t, 8> nonce;
const bool ok = fido_parsing_utils::ExtractArray(
discovery_data->client_eid, 0, &nonce);
DCHECK(ok);
handler.reset(new FidoCableV1HandshakeHandler(
device, nonce, discovery_data->session_pre_key));
break;
}
case 2:
if (!base::FeatureList::IsEnabled(device::kWebAuthPhoneSupport)) {
return base::nullopt;
}
handler.reset(new FidoCableV2HandshakeHandler(
device, discovery_data->session_pre_key));
break;
default:
FIDO_LOG(DEBUG) << "Dropping caBLE handshake request for unknown version "
<< discovery_data->version;
return base::nullopt;
}
return handler;
}
void FidoCableDiscovery::DeviceAdded(BluetoothAdapter* adapter,
......@@ -353,17 +380,19 @@ void FidoCableDiscovery::CableDeviceFound(BluetoothAdapter* adapter,
StopAdvertisements(
base::BindOnce(&FidoCableDiscovery::ConductEncryptionHandshake,
weak_factory_.GetWeakPtr(), std::move(cable_device),
found_cable_device_data->session_pre_key, nonce));
*found_cable_device_data));
}
void FidoCableDiscovery::ConductEncryptionHandshake(
std::unique_ptr<FidoCableDevice> cable_device,
base::span<const uint8_t, kCableSessionPreKeySize> 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_back(std::move(handshake_handler));
CableDiscoveryData discovery_data) {
base::Optional<std::unique_ptr<FidoCableHandshakeHandler>> handshake_handler =
CreateHandshakeHandler(cable_device.get(), &discovery_data);
if (!handshake_handler) {
return;
}
auto* const handshake_handler_ptr = handshake_handler->get();
cable_handshake_handlers_.emplace_back(std::move(*handshake_handler));
handshake_handler_ptr->InitiateCableHandshake(
base::BindOnce(&FidoCableDiscovery::ValidateAuthenticatorHandshakeMessage,
......
......@@ -35,10 +35,9 @@ class COMPONENT_EXPORT(DEVICE_FIDO) FidoCableDiscovery
~FidoCableDiscovery() override;
protected:
virtual std::unique_ptr<FidoCableHandshakeHandler> CreateHandshakeHandler(
FidoCableDevice* device,
base::span<const uint8_t, kCableSessionPreKeySize> session_pre_key,
base::span<const uint8_t, 8> nonce);
virtual base::Optional<std::unique_ptr<FidoCableHandshakeHandler>>
CreateHandshakeHandler(FidoCableDevice* device,
const CableDiscoveryData* discovery_data);
private:
FRIEND_TEST_ALL_PREFIXES(FidoCableDiscoveryTest,
......@@ -76,10 +75,8 @@ class COMPONENT_EXPORT(DEVICE_FIDO) FidoCableDiscovery
// |callback|.
void StopAdvertisements(base::OnceClosure callback);
void CableDeviceFound(BluetoothAdapter* adapter, BluetoothDevice* device);
void ConductEncryptionHandshake(
std::unique_ptr<FidoCableDevice> device,
base::span<const uint8_t, kCableSessionPreKeySize> session_pre_key,
base::span<const uint8_t, 8> nonce);
void ConductEncryptionHandshake(std::unique_ptr<FidoCableDevice> cable_device,
CableDiscoveryData discovery_data);
void ValidateAuthenticatorHandshakeMessage(
std::unique_ptr<FidoCableDevice> cable_device,
FidoCableHandshakeHandler* handshake_handler,
......
......@@ -266,12 +266,12 @@ class CableMockAdapter : public MockBluetoothAdapter {
~CableMockAdapter() override = default;
};
class FakeHandshakeHandler : public FidoCableHandshakeHandler {
class FakeHandshakeHandler : public FidoCableV1HandshakeHandler {
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) {}
: FidoCableV1HandshakeHandler(device, nonce, session_pre_key) {}
~FakeHandshakeHandler() override = default;
void InitiateCableHandshake(FidoDevice::DeviceCallback callback) override {
......@@ -295,12 +295,16 @@ class FakeFidoCableDiscovery : public FidoCableDiscovery {
~FakeFidoCableDiscovery() override = default;
private:
std::unique_ptr<FidoCableHandshakeHandler> CreateHandshakeHandler(
FidoCableDevice* device,
base::span<const uint8_t, kCableSessionPreKeySize> session_pre_key,
base::span<const uint8_t, 8> nonce) override {
return std::make_unique<FakeHandshakeHandler>(device, nonce,
session_pre_key);
base::Optional<std::unique_ptr<FidoCableHandshakeHandler>>
CreateHandshakeHandler(FidoCableDevice* device,
const CableDiscoveryData* discovery_data) override {
// Nonce is embedded as first 8 bytes of client EID.
std::array<uint8_t, 8> nonce;
const bool ok =
fido_parsing_utils::ExtractArray(discovery_data->client_eid, 0, &nonce);
DCHECK(ok);
return std::make_unique<FakeHandshakeHandler>(
device, nonce, discovery_data->session_pre_key);
}
};
......
......@@ -5,21 +5,30 @@
#include "device/fido/cable/fido_cable_handshake_handler.h"
#include <algorithm>
#include <tuple>
#include <utility>
#include "base/bind.h"
#include "base/containers/span.h"
#include "base/strings/string_number_conversions.h"
#include "base/threading/thread_task_runner_handle.h"
#include "components/cbor/reader.h"
#include "components/cbor/values.h"
#include "components/cbor/writer.h"
#include "components/device_event_log/device_event_log.h"
#include "crypto/aead.h"
#include "crypto/hkdf.h"
#include "crypto/hmac.h"
#include "crypto/random.h"
#include "device/fido/cable/fido_cable_device.h"
#include "device/fido/fido_constants.h"
#include "device/fido/fido_parsing_utils.h"
#include "third_party/boringssl/src/include/openssl/digest.h"
#include "third_party/boringssl/src/include/openssl/ec_key.h"
#include "third_party/boringssl/src/include/openssl/ecdh.h"
#include "third_party/boringssl/src/include/openssl/hkdf.h"
#include "third_party/boringssl/src/include/openssl/obj.h"
#include "third_party/boringssl/src/include/openssl/sha.h"
namespace device {
......@@ -76,7 +85,9 @@ ConstructHandshakeMessage(base::StringPiece handshake_key,
} // namespace
FidoCableHandshakeHandler::FidoCableHandshakeHandler(
FidoCableHandshakeHandler::~FidoCableHandshakeHandler() {}
FidoCableV1HandshakeHandler::FidoCableV1HandshakeHandler(
FidoCableDevice* cable_device,
base::span<const uint8_t, 8> nonce,
base::span<const uint8_t, 32> session_pre_key)
......@@ -91,9 +102,9 @@ FidoCableHandshakeHandler::FidoCableHandshakeHandler(
client_session_random_.size());
}
FidoCableHandshakeHandler::~FidoCableHandshakeHandler() = default;
FidoCableV1HandshakeHandler::~FidoCableV1HandshakeHandler() = default;
void FidoCableHandshakeHandler::InitiateCableHandshake(
void FidoCableV1HandshakeHandler::InitiateCableHandshake(
FidoDevice::DeviceCallback callback) {
auto handshake_message =
ConstructHandshakeMessage(handshake_key_, client_session_random_);
......@@ -108,7 +119,7 @@ void FidoCableHandshakeHandler::InitiateCableHandshake(
fido_parsing_utils::Materialize(*handshake_message), std::move(callback));
}
bool FidoCableHandshakeHandler::ValidateAuthenticatorHandshakeMessage(
bool FidoCableV1HandshakeHandler::ValidateAuthenticatorHandshakeMessage(
base::span<const uint8_t> response) {
crypto::HMAC hmac(crypto::HMAC::SHA256);
if (!hmac.Init(handshake_key_))
......@@ -158,7 +169,8 @@ bool FidoCableHandshakeHandler::ValidateAuthenticatorHandshakeMessage(
return true;
}
std::string FidoCableHandshakeHandler::GetEncryptionKeyAfterSuccessfulHandshake(
std::string
FidoCableV1HandshakeHandler::GetEncryptionKeyAfterSuccessfulHandshake(
base::span<const uint8_t, 16> authenticator_random_nonce) const {
std::vector<uint8_t> nonce_message;
fido_parsing_utils::Append(&nonce_message, nonce_);
......@@ -172,4 +184,206 @@ std::string FidoCableHandshakeHandler::GetEncryptionKeyAfterSuccessfulHandshake(
kCableDeviceEncryptionKeyInfo);
}
FidoCableV2HandshakeHandler::FidoCableV2HandshakeHandler(
FidoCableDevice* cable_device,
base::span<const uint8_t, 32> session_pre_key)
: cable_device_(cable_device),
session_pre_key_(fido_parsing_utils::Materialize(session_pre_key)) {}
FidoCableV2HandshakeHandler::~FidoCableV2HandshakeHandler() {}
namespace {
// P256PointSize is the number of bytes in an X9.62 encoding of a P-256 point.
constexpr size_t P256PointSize = 65;
// HKDF2 implements the functions with the same name from Noise[1], specialized
// to the case where |num_outputs| is two.
//
// [1] https://www.noiseprotocol.org/noise.html#hash-functions
std::tuple<std::array<uint8_t, 32>, std::array<uint8_t, 32>> HKDF2(
base::span<const uint8_t, 32> ck,
base::span<const uint8_t> ikm) {
uint8_t output[32 * 2];
HKDF(output, sizeof(output), EVP_sha256(), ikm.data(), ikm.size(), ck.data(),
ck.size(), /*salt=*/nullptr, 0);
std::array<uint8_t, 32> a, b;
memcpy(a.data(), &output[0], 32);
memcpy(b.data(), &output[32], 32);
return std::make_tuple(a, b);
}
// HKDF3 implements the functions with the same name from Noise[1], specialized
// to the case where |num_outputs| is three.
//
// [1] https://www.noiseprotocol.org/noise.html#hash-functions
std::tuple<std::array<uint8_t, 32>,
std::array<uint8_t, 32>,
std::array<uint8_t, 32>>
HKDF3(base::span<const uint8_t, 32> ck, base::span<const uint8_t> ikm) {
uint8_t output[32 * 3];
HKDF(output, sizeof(output), EVP_sha256(), ikm.data(), ikm.size(), ck.data(),
ck.size(), /*salt=*/nullptr, 0);
std::array<uint8_t, 32> a, b, c;
memcpy(a.data(), &output[0], 32);
memcpy(b.data(), &output[32], 32);
memcpy(c.data(), &output[64], 32);
return std::make_tuple(a, b, c);
}
} // namespace
void FidoCableV2HandshakeHandler::InitiateCableHandshake(
FidoDevice::DeviceCallback callback) {
// See https://www.noiseprotocol.org/noise.html#the-handshakestate-object
static const char kProtocolName[] = "Noise_NNpsk0_P256_AESGCM_SHA256";
static_assert(sizeof(kProtocolName) == crypto::kSHA256Length,
"name may need padding if not HASHLEN bytes long");
static_assert(
std::tuple_size<decltype(chaining_key_)>::value == crypto::kSHA256Length,
"chaining_key_ is wrong size");
static_assert(std::tuple_size<decltype(h_)>::value == crypto::kSHA256Length,
"h_ is wrong size");
memcpy(chaining_key_.data(), kProtocolName, sizeof(kProtocolName));
h_ = chaining_key_;
static const uint8_t kPrologue[] = "caBLE QR code handshake";
MixHash(kPrologue);
MixKeyAndHash(session_pre_key_);
ephemeral_key_.reset(EC_KEY_new_by_curve_name(NID_X9_62_prime256v1));
CHECK(EC_KEY_generate_key(ephemeral_key_.get()));
uint8_t ephemeral_key_public_bytes[P256PointSize];
CHECK_EQ(sizeof(ephemeral_key_public_bytes),
EC_POINT_point2oct(
EC_KEY_get0_group(ephemeral_key_.get()),
EC_KEY_get0_public_key(ephemeral_key_.get()),
POINT_CONVERSION_UNCOMPRESSED, ephemeral_key_public_bytes,
sizeof(ephemeral_key_public_bytes), /*ctx=*/nullptr));
MixHash(ephemeral_key_public_bytes);
MixKey(ephemeral_key_public_bytes);
std::vector<uint8_t> ciphertext = Encrypt(base::span<const uint8_t>());
MixHash(ciphertext);
std::vector<uint8_t> handshake_message;
handshake_message.reserve(sizeof(ephemeral_key_public_bytes) +
ciphertext.size());
handshake_message.insert(
handshake_message.end(), ephemeral_key_public_bytes,
ephemeral_key_public_bytes + sizeof(ephemeral_key_public_bytes));
handshake_message.insert(handshake_message.end(), ciphertext.begin(),
ciphertext.end());
cable_device_->SendHandshakeMessage(std::move(handshake_message),
std::move(callback));
}
bool FidoCableV2HandshakeHandler::ValidateAuthenticatorHandshakeMessage(
base::span<const uint8_t> response) {
if (response.size() < P256PointSize) {
return false;
}
auto peer_point_bytes = response.subspan(0, P256PointSize);
auto ciphertext = response.subspan(P256PointSize);
bssl::UniquePtr<EC_POINT> peer_point(
EC_POINT_new(EC_KEY_get0_group(ephemeral_key_.get())));
uint8_t shared_key[32];
if (!EC_POINT_oct2point(EC_KEY_get0_group(ephemeral_key_.get()),
peer_point.get(), peer_point_bytes.data(),
peer_point_bytes.size(), /*ctx=*/nullptr) ||
!ECDH_compute_key(shared_key, sizeof(shared_key), peer_point.get(),
ephemeral_key_.get(), /*kdf=*/nullptr)) {
return false;
}
MixHash(peer_point_bytes);
MixKey(peer_point_bytes);
MixKey(shared_key);
auto maybe_plaintext = Decrypt(ciphertext);
if (!maybe_plaintext || !maybe_plaintext->empty()) {
return false;
}
// Here the spec says to do MixHash(ciphertext), but there are no more
// handshake messages so that's moot.
// MixHash(ciphertext);
std::array<uint8_t, 32> key1, unused_key2;
std::tie(key1, unused_key2) =
HKDF2(chaining_key_, base::span<const uint8_t>());
uint8_t zero_nonce[8] = {0};
cable_device_->SetEncryptionData(
std::string(reinterpret_cast<const char*>(key1.data()), key1.size()),
zero_nonce);
return true;
}
void FidoCableV2HandshakeHandler::MixHash(base::span<const uint8_t> in) {
// See https://www.noiseprotocol.org/noise.html#the-symmetricstate-object
SHA256_CTX ctx;
SHA256_Init(&ctx);
SHA256_Update(&ctx, h_.data(), h_.size());
SHA256_Update(&ctx, in.data(), in.size());
SHA256_Final(h_.data(), &ctx);
}
void FidoCableV2HandshakeHandler::MixKey(base::span<const uint8_t> ikm) {
// See https://www.noiseprotocol.org/noise.html#the-symmetricstate-object
std::array<uint8_t, 32> temp_k;
std::tie(chaining_key_, temp_k) = HKDF2(chaining_key_, ikm);
InitializeKey(temp_k);
}
void FidoCableV2HandshakeHandler::MixKeyAndHash(base::span<const uint8_t> ikm) {
// See https://www.noiseprotocol.org/noise.html#the-symmetricstate-object
std::array<uint8_t, 32> temp_h, temp_k;
std::tie(chaining_key_, temp_h, temp_k) = HKDF3(chaining_key_, ikm);
MixHash(temp_h);
InitializeKey(temp_k);
}
void FidoCableV2HandshakeHandler::InitializeKey(
base::span<const uint8_t, 32> key) {
// See https://www.noiseprotocol.org/noise.html#the-cipherstate-object
DCHECK_EQ(symmetric_key_.size(), key.size());
memcpy(symmetric_key_.data(), key.data(), symmetric_key_.size());
symmetric_nonce_ = 0;
}
std::vector<uint8_t> FidoCableV2HandshakeHandler::Encrypt(
base::span<const uint8_t> plaintext) {
uint8_t nonce[12] = {0};
nonce[8] = symmetric_nonce_ >> 24;
nonce[9] = symmetric_nonce_ >> 16;
nonce[10] = symmetric_nonce_ >> 8;
nonce[11] = symmetric_nonce_;
symmetric_nonce_++;
crypto::Aead aead(crypto::Aead::AES_256_GCM);
aead.Init(symmetric_key_);
return aead.Seal(base::span<const uint8_t>(), nonce, h_);
}
base::Optional<std::vector<uint8_t>> FidoCableV2HandshakeHandler::Decrypt(
base::span<const uint8_t> ciphertext) {
uint8_t nonce[12] = {0};
nonce[8] = symmetric_nonce_ >> 24;
nonce[9] = symmetric_nonce_ >> 16;
nonce[10] = symmetric_nonce_ >> 8;
nonce[11] = symmetric_nonce_;
symmetric_nonce_++;
crypto::Aead aead(crypto::Aead::AES_256_GCM);
aead.Init(symmetric_key_);
return aead.Open(ciphertext, nonce, h_);
}
} // namespace device
......@@ -16,27 +16,41 @@
#include "base/gtest_prod_util.h"
#include "base/macros.h"
#include "base/memory/weak_ptr.h"
#include "base/optional.h"
#include "device/fido/fido_device.h"
#include "third_party/boringssl/src/include/openssl/base.h"
namespace device {
class FidoCableDevice;
// FidoCableHandshakeHandler abstracts over the different versions of caBLE
// handshakes.
class FidoCableHandshakeHandler {
public:
virtual ~FidoCableHandshakeHandler() = 0;
virtual void InitiateCableHandshake(FidoDevice::DeviceCallback callback) = 0;
virtual bool ValidateAuthenticatorHandshakeMessage(
base::span<const uint8_t> response) = 0;
};
// Handles exchanging handshake messages with external authenticator and
// validating the handshake messages to derive a shared session key to be used
// for message encryption.
// See: fido-client-to-authenticator-protocol.html#cable-encryption-handshake of
// the most up-to-date spec.
class COMPONENT_EXPORT(DEVICE_FIDO) FidoCableHandshakeHandler {
class COMPONENT_EXPORT(DEVICE_FIDO) FidoCableV1HandshakeHandler
: public FidoCableHandshakeHandler {
public:
FidoCableHandshakeHandler(FidoCableDevice* device,
base::span<const uint8_t, 8> nonce,
base::span<const uint8_t, 32> session_pre_key);
virtual ~FidoCableHandshakeHandler();
FidoCableV1HandshakeHandler(FidoCableDevice* device,
base::span<const uint8_t, 8> nonce,
base::span<const uint8_t, 32> session_pre_key);
~FidoCableV1HandshakeHandler() override;
virtual void InitiateCableHandshake(FidoDevice::DeviceCallback callback);
virtual bool ValidateAuthenticatorHandshakeMessage(
base::span<const uint8_t> response);
// FidoCableHandshakeHandler:
void InitiateCableHandshake(FidoDevice::DeviceCallback callback) override;
bool ValidateAuthenticatorHandshakeMessage(
base::span<const uint8_t> response) override;
private:
FRIEND_TEST_ALL_PREFIXES(FidoCableHandshakeHandlerTest, HandShakeSuccess);
......@@ -52,9 +66,43 @@ class COMPONENT_EXPORT(DEVICE_FIDO) FidoCableHandshakeHandler {
std::array<uint8_t, 16> client_session_random_;
std::string handshake_key_;
base::WeakPtrFactory<FidoCableHandshakeHandler> weak_factory_{this};
base::WeakPtrFactory<FidoCableV1HandshakeHandler> weak_factory_{this};
DISALLOW_COPY_AND_ASSIGN(FidoCableV1HandshakeHandler);
};
// FidoCableV2HandshakeHandler implements an NNpsk0[1] handshake that provides
// forward secrecy.
//
// [1] https://noiseexplorer.com/patterns/NNpsk0/
class COMPONENT_EXPORT(DEVICE_FIDO) FidoCableV2HandshakeHandler
: public FidoCableHandshakeHandler {
public:
FidoCableV2HandshakeHandler(FidoCableDevice* device,
base::span<const uint8_t, 32> session_pre_key);
~FidoCableV2HandshakeHandler() override;
// FidoCableHandshakeHandler:
void InitiateCableHandshake(FidoDevice::DeviceCallback callback) override;
bool ValidateAuthenticatorHandshakeMessage(
base::span<const uint8_t> response) override;
DISALLOW_COPY_AND_ASSIGN(FidoCableHandshakeHandler);
private:
void MixHash(base::span<const uint8_t> in);
void MixKey(base::span<const uint8_t> ikm);
void MixKeyAndHash(base::span<const uint8_t> ikm);
void InitializeKey(base::span<const uint8_t, 32> key);
std::vector<uint8_t> Encrypt(base::span<const uint8_t> plaintext);
base::Optional<std::vector<uint8_t>> Decrypt(
base::span<const uint8_t> ciphertext);
FidoCableDevice* const cable_device_;
std::array<uint8_t, 32> session_pre_key_;
std::array<uint8_t, 32> chaining_key_;
std::array<uint8_t, 32> h_;
std::array<uint8_t, 32> symmetric_key_;
uint32_t symmetric_nonce_;
bssl::UniquePtr<EC_KEY> ephemeral_key_;
};
} // namespace device
......
......@@ -37,8 +37,9 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* raw_data, size_t size) {
auto adapter =
base::MakeRefCounted<::testing::NiceMock<device::MockBluetoothAdapter>>();
device::FidoCableDevice test_cable_device(adapter.get(), kTestDeviceAddress);
device::FidoCableHandshakeHandler handshake_handler(
device::FidoCableV1HandshakeHandler handshake_handler_v1(
&test_cable_device, kTestNonce, kTestSessionPreKey);
handshake_handler.ValidateAuthenticatorHandshakeMessage(data_span);
handshake_handler_v1.ValidateAuthenticatorHandshakeMessage(data_span);
return 0;
}
......@@ -264,11 +264,11 @@ class FidoCableHandshakeHandlerTest : public Test {
connection_->read_callback() = device_->GetReadCallbackForTesting();
}
std::unique_ptr<FidoCableHandshakeHandler> CreateHandshakeHandler(
std::unique_ptr<FidoCableV1HandshakeHandler> CreateHandshakeHandler(
std::array<uint8_t, 8> nonce,
std::array<uint8_t, 32> session_pre_key) {
return std::make_unique<FidoCableHandshakeHandler>(device_.get(), nonce,
session_pre_key);
return std::make_unique<FidoCableV1HandshakeHandler>(device_.get(), nonce,
session_pre_key);
}
void ConnectWithLength(uint16_t length) {
......
// 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 <stddef.h>
#include <stdint.h>
#include <array>
#include "base/containers/span.h"
#include "base/memory/ref_counted.h"
#include "device/bluetooth/test/mock_bluetooth_adapter.h"
#include "device/fido/cable/fido_cable_device.h"
#include "device/fido/cable/fido_cable_handshake_handler.h"
#include "device/fido/fido_constants.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace {
constexpr std::array<uint8_t, 32> 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,
}};
constexpr char kTestDeviceAddress[] = "Fake_Address";
} // namespace
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* raw_data, size_t size) {
auto data_span = base::make_span(raw_data, size);
auto adapter =
base::MakeRefCounted<::testing::NiceMock<device::MockBluetoothAdapter>>();
device::FidoCableDevice test_cable_device(adapter.get(), kTestDeviceAddress);
test_cable_device.SetStateForTesting(
device::FidoCableDevice::State::kDeviceError);
device::FidoCableV2HandshakeHandler handshake_handler_v2(&test_cable_device,
kTestSessionPreKey);
handshake_handler_v2.InitiateCableHandshake(base::DoNothing());
handshake_handler_v2.ValidateAuthenticatorHandshakeMessage(data_span);
return 0;
}
......@@ -25,4 +25,7 @@ extern const base::Feature kWebAuthBiometricEnrollment{
extern const base::Feature kWebAuthCredentialManagement{
"WebAuthenticationCredentialManagement", base::FEATURE_ENABLED_BY_DEFAULT};
extern const base::Feature kWebAuthPhoneSupport{
"WebAuthenticationPhoneSupport", base::FEATURE_DISABLED_BY_DEFAULT};
} // namespace device
......@@ -28,6 +28,10 @@ extern const base::Feature kWebAuthBiometricEnrollment;
COMPONENT_EXPORT(DEVICE_FIDO)
extern const base::Feature kWebAuthCredentialManagement;
// Enable using a phone as a generic security key.
COMPONENT_EXPORT(DEVICE_FIDO)
extern const base::Feature kWebAuthPhoneSupport;
} // namespace device
#endif // DEVICE_FIDO_FEATURES_H_
......@@ -115,6 +115,7 @@ class COMPONENT_EXPORT(DEVICE_FIDO) FidoDevice {
}
State state_for_testing() const { return state_; }
void SetStateForTesting(State state) { state_ = state; }
protected:
void OnDeviceInfoReceived(base::OnceClosure done,
......
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