blob: 153380bfc0c3e1c3c79dc1afef5376c886ecbcdf [file] [log] [blame]
// Copyright 2018 The Fuchsia 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 "src/connectivity/bluetooth/core/bt-host/public/pw_bluetooth_sapphire/internal/host/sm/security_manager.h"
#include <chrono>
#include <cstdlib>
#include "src/connectivity/bluetooth/core/bt-host/public/pw_bluetooth_sapphire/internal/host/common/macros.h"
#include "src/connectivity/bluetooth/core/bt-host/public/pw_bluetooth_sapphire/internal/host/common/random.h"
#include "src/connectivity/bluetooth/core/bt-host/public/pw_bluetooth_sapphire/internal/host/gap/gap.h"
#include "src/connectivity/bluetooth/core/bt-host/public/pw_bluetooth_sapphire/internal/host/hci-spec/link_key.h"
#include "src/connectivity/bluetooth/core/bt-host/public/pw_bluetooth_sapphire/internal/host/hci/connection.h"
#include "src/connectivity/bluetooth/core/bt-host/public/pw_bluetooth_sapphire/internal/host/hci/fake_low_energy_connection.h"
#include "src/connectivity/bluetooth/core/bt-host/public/pw_bluetooth_sapphire/internal/host/l2cap/fake_channel_test.h"
#include "src/connectivity/bluetooth/core/bt-host/public/pw_bluetooth_sapphire/internal/host/sm/ecdh_key.h"
#include "src/connectivity/bluetooth/core/bt-host/public/pw_bluetooth_sapphire/internal/host/sm/error.h"
#include "src/connectivity/bluetooth/core/bt-host/public/pw_bluetooth_sapphire/internal/host/sm/packet.h"
#include "src/connectivity/bluetooth/core/bt-host/public/pw_bluetooth_sapphire/internal/host/sm/smp.h"
#include "src/connectivity/bluetooth/core/bt-host/public/pw_bluetooth_sapphire/internal/host/sm/types.h"
#include "src/connectivity/bluetooth/core/bt-host/public/pw_bluetooth_sapphire/internal/host/sm/util.h"
#include "src/connectivity/bluetooth/core/bt-host/public/pw_bluetooth_sapphire/internal/host/testing/controller_test.h"
#include "src/connectivity/bluetooth/core/bt-host/public/pw_bluetooth_sapphire/internal/host/testing/mock_controller.h"
#include "src/connectivity/bluetooth/core/bt-host/public/pw_bluetooth_sapphire/internal/host/testing/test_helpers.h"
#include "src/connectivity/bluetooth/core/bt-host/public/pw_bluetooth_sapphire/internal/host/testing/test_packets.h"
#include "src/connectivity/bluetooth/core/bt-host/public/pw_bluetooth_sapphire/internal/host/transport/error.h"
namespace bt::sm {
namespace {
const DeviceAddress kLocalAddr(DeviceAddress::Type::kLEPublic,
{0xA6, 0xA5, 0xA4, 0xA3, 0xA2, 0xA1});
const DeviceAddress kPeerAddr(DeviceAddress::Type::kLERandom,
{0xB6, 0xB5, 0xB4, 0xB3, 0xB2, 0xB1});
const PairingRandomValue kHardCodedPairingRandom = {0x0,
0x1,
0x2,
0x3,
0x4,
0x5,
0x6,
0x7,
0x8,
0x9,
0xA,
0xB,
0xC,
0xD,
0xE,
0xF};
constexpr hci_spec::ConnectionHandle kConnectionHandle(1);
class SecurityManagerTest : public l2cap::testing::FakeChannelTest,
public sm::Delegate {
public:
SecurityManagerTest() : weak_delegate_(this) {}
~SecurityManagerTest() override = default;
protected:
void SetUp() override {
l2cap::testing::FakeChannelTest::SetUp();
InitializeTransport();
}
void TearDown() override {
RunUntilIdle();
DestroySecurityManager();
fake_link_.reset();
transport_.reset();
l2cap::testing::FakeChannelTest::TearDown();
}
void NewSecurityManager(Role role,
IOCapability ioc,
BondableMode bondable_mode) {
// Setup fake SMP channel.
ChannelOptions options(l2cap::kLESMPChannelId);
fake_chan_ = CreateFakeChannel(options);
fake_chan_->SetSendCallback(
fit::bind_member<&SecurityManagerTest::OnDataReceived>(this),
dispatcher());
// Setup a fake logical link.
auto link_role = role == Role::kInitiator
? pw::bluetooth::emboss::ConnectionRole::CENTRAL
: pw::bluetooth::emboss::ConnectionRole::PERIPHERAL;
if (fake_link_) {
auto status_event = testing::CommandStatusPacket(
hci_spec::kDisconnect, pw::bluetooth::emboss::StatusCode::SUCCESS);
auto disconnect_complete =
testing::DisconnectionCompletePacket(kConnectionHandle);
EXPECT_CMD_PACKET_OUT(controller_,
testing::DisconnectPacket(kConnectionHandle),
&status_event,
&disconnect_complete);
fake_link_.reset();
RunUntilIdle();
}
fake_link_ = std::make_unique<hci::testing::FakeLowEnergyConnection>(
kConnectionHandle,
kLocalAddr,
kPeerAddr,
link_role,
transport_->GetWeakPtr());
pairing_ = SecurityManager::Create(fake_link_->GetWeakPtr(),
fake_chan_->GetWeakPtr(),
ioc,
weak_delegate_.GetWeakPtr(),
bondable_mode,
gap::LESecurityMode::Mode1,
dispatcher());
}
void DestroySecurityManager() { pairing_ = nullptr; }
// sm::Delegate override:
void ConfirmPairing(ConfirmCallback confirm) override {
if (confirm_delegate_) {
confirm_delegate_(std::move(confirm));
} else {
confirm(true);
}
}
// sm::Delegate override:
void DisplayPasskey(uint32_t passkey,
DisplayMethod method,
ConfirmCallback confirm) override {
if (display_delegate_) {
display_delegate_(passkey, method, std::move(confirm));
} else {
ADD_FAILURE() << "No passkey display delegate set for "
<< util::DisplayMethodToString(method) << " pairing";
}
}
// sm::Delegate override:
void RequestPasskey(PasskeyResponseCallback respond) override {
if (request_passkey_delegate_) {
request_passkey_delegate_(std::move(respond));
} else {
ADD_FAILURE()
<< "No passkey entry delegate set for passkey entry pairing";
}
}
std::optional<IdentityInfo> OnIdentityInformationRequest() override {
local_id_info_callback_count_++;
return local_id_info_;
}
// Called by |pairing_| when the pairing procedure ends.
void OnPairingComplete(Result<> status) override {
pairing_complete_count_++;
pairing_complete_status_ = status;
}
// Called by |pairing_| when a new LTK is obtained.
void OnNewPairingData(const PairingData& pairing_data) override {
pairing_data_callback_count_++;
pairing_data_ = pairing_data;
}
// Called by |pairing_| when any encryption procedure fails.
void OnAuthenticationFailure(hci::Result<> status) override {
auth_failure_callback_count_++;
auth_failure_status_ = status;
}
// Called by |pairing_| when the link security properties change.
void OnNewSecurityProperties(const SecurityProperties& sec) override {
new_sec_props_count_++;
new_sec_props_ = sec;
}
void UpgradeSecurity(SecurityLevel level) {
BT_DEBUG_ASSERT(pairing_);
pairing_->UpgradeSecurity(level, [this](auto status, const auto& props) {
security_callback_count_++;
security_status_ = status;
sec_props_ = props;
});
}
// Called when SMP sends a packet over the fake channel.
void OnDataReceived(std::unique_ptr<const ByteBuffer> packet) {
BT_DEBUG_ASSERT(packet);
PacketReader reader(packet.get());
switch (reader.code()) {
case kPairingFailed:
pairing_failed_count_++;
received_error_code_ = reader.payload<PairingFailedParams>();
break;
case kSecurityRequest:
security_request_count_++;
security_auth_req_ = reader.payload<AuthReqField>();
break;
case kPairingRequest:
pairing_request_count_++;
packet->Copy(&local_pairing_cmd_);
break;
case kPairingResponse:
pairing_response_count_++;
packet->Copy(&local_pairing_cmd_);
break;
case kPairingPublicKey:
pairing_public_key_count_++;
public_ecdh_key_ = EcdhKey::ParseFromPublicKey(
reader.payload<PairingPublicKeyParams>());
break;
case kPairingConfirm:
pairing_confirm_count_++;
pairing_confirm_ = reader.payload<PairingConfirmValue>();
break;
case kPairingRandom:
pairing_random_count_++;
pairing_random_ = reader.payload<PairingRandomValue>();
break;
case kPairingDHKeyCheck:
pairing_dhkey_check_count_++;
pairing_dhkey_check_ = reader.payload<PairingDHKeyCheckValueE>();
break;
case kEncryptionInformation:
enc_info_count_++;
enc_info_ = reader.payload<EncryptionInformationParams>();
break;
case kCentralIdentification: {
const auto& params = reader.payload<CentralIdentificationParams>();
central_ident_count_++;
ediv_ = le16toh(params.ediv);
rand_ = le64toh(params.rand);
break;
}
case kIdentityInformation:
id_info_count_++;
id_info_ = reader.payload<UInt128>();
break;
case kIdentityAddressInformation: {
const auto& params = reader.payload<IdentityAddressInformationParams>();
id_addr_info_count_++;
id_addr_info_ = DeviceAddress(params.type == AddressType::kStaticRandom
? DeviceAddress::Type::kLERandom
: DeviceAddress::Type::kLEPublic,
params.bd_addr);
break;
}
default:
FAIL() << "Sent unsupported SMP command";
}
}
// Emulates the receipt of pairing features (both as initiator and responder).
void ReceivePairingFeatures(const PairingRequestParams& params,
bool peer_initiator = false) {
PacketWriter writer(peer_initiator ? kPairingRequest : kPairingResponse,
&peer_pairing_cmd_);
*writer.mutable_payload<PairingRequestParams>() = params;
fake_chan()->Receive(peer_pairing_cmd_);
}
void ReceivePairingFeatures(IOCapability ioc = IOCapability::kNoInputNoOutput,
AuthReqField auth_req = 0,
uint8_t max_enc_key_size = kMaxEncryptionKeySize,
bool peer_initiator = false) {
PairingRequestParams pairing_params;
std::memset(&pairing_params, 0, sizeof(pairing_params));
pairing_params.io_capability = ioc;
pairing_params.auth_req = auth_req;
pairing_params.max_encryption_key_size = max_enc_key_size;
ReceivePairingFeatures(pairing_params, peer_initiator);
}
void ReceivePairingFailed(ErrorCode error_code) {
StaticByteBuffer<sizeof(Header) + sizeof(ErrorCode)> buffer;
PacketWriter writer(kPairingFailed, &buffer);
*writer.mutable_payload<PairingFailedParams>() = error_code;
fake_chan()->Receive(buffer);
}
void ReceivePairingPublicKey(const PairingPublicKeyParams& key) {
StaticByteBuffer<util::PacketSize<PairingPublicKeyParams>()> buffer;
PacketWriter writer(kPairingPublicKey, &buffer);
std::memcpy(
writer.mutable_payload_bytes(), &key, sizeof(PairingPublicKeyParams));
fake_chan()->Receive(buffer);
}
void ReceivePairingConfirm(const UInt128& confirm) {
Receive128BitCmd(kPairingConfirm, confirm);
}
void ReceivePairingRandom(const UInt128& random) {
Receive128BitCmd(kPairingRandom, random);
}
void ReceivePairingDHKeyCheck(const UInt128& check) {
Receive128BitCmd(kPairingDHKeyCheck, check);
}
void ReceiveEncryptionInformation(const UInt128& ltk) {
Receive128BitCmd(kEncryptionInformation, ltk);
}
void ReceiveCentralIdentification(uint64_t random, uint16_t ediv) {
StaticByteBuffer<sizeof(Header) + sizeof(CentralIdentificationParams)>
buffer;
PacketWriter writer(kCentralIdentification, &buffer);
auto* params = writer.mutable_payload<CentralIdentificationParams>();
params->ediv = htole16(ediv);
params->rand = htole64(random);
fake_chan()->Receive(buffer);
}
void ReceiveIdentityResolvingKey(const UInt128& irk) {
Receive128BitCmd(kIdentityInformation, irk);
}
void ReceiveNonBondablePairingResponse() {
// clang-format off
const StaticByteBuffer kResponse(
0x02, // code: Pairing Response
0x00, // IO cap.: DisplayOnly
0x00, // OOB: not present
0x00, // AuthReq: no bonding, MITM not required
0x07, // encr. key size: 7 (default min)
0x00, // initiator keys: none
0x00 // responder keys: none - nonbondable mode
);
// clang-format on
fake_chan()->Receive(kResponse);
}
void ReceiveIdentityAddress(const DeviceAddress& address) {
StaticByteBuffer<sizeof(Header) + sizeof(IdentityAddressInformationParams)>
buffer;
PacketWriter writer(kIdentityAddressInformation, &buffer);
auto* params = writer.mutable_payload<IdentityAddressInformationParams>();
params->type = address.type() == DeviceAddress::Type::kLEPublic
? AddressType::kPublic
: AddressType::kStaticRandom;
params->bd_addr = address.value();
fake_chan()->Receive(buffer);
}
void ReceiveSecurityRequest(AuthReqField auth_req = 0u) {
StaticByteBuffer<sizeof(Header) + sizeof(AuthReqField)> buffer;
buffer[0] = kSecurityRequest;
buffer[1] = auth_req;
fake_chan()->Receive(buffer);
RunUntilIdle();
}
void GenerateLegacyConfirmValue(const UInt128& random,
UInt128* out_value,
bool peer_initiator = false,
uint32_t tk = 0) {
BT_DEBUG_ASSERT(out_value);
tk = htole32(tk);
UInt128 tk128;
tk128.fill(0);
std::memcpy(tk128.data(), &tk, sizeof(tk));
const ByteBuffer *preq, *pres;
const DeviceAddress *init_addr, *rsp_addr;
if (peer_initiator) {
preq = &peer_pairing_cmd();
pres = &local_pairing_cmd();
init_addr = &kPeerAddr;
rsp_addr = &kLocalAddr;
} else {
preq = &local_pairing_cmd();
pres = &peer_pairing_cmd();
init_addr = &kLocalAddr;
rsp_addr = &kPeerAddr;
}
util::C1(tk128, random, *preq, *pres, *init_addr, *rsp_addr, out_value);
}
UInt128 GenerateScConfirmValue(const LocalEcdhKey& peer_key,
const UInt128& random,
Role local_role,
bool gen_initiator_confirm,
uint8_t r = 0) {
BT_ASSERT_MSG(public_ecdh_key_.has_value(),
"cannot compute confirm, missing key!");
UInt256 pka = public_ecdh_key_->GetPublicKeyX(),
pkb = peer_key.GetPublicKeyX();
if (local_role == Role::kResponder) {
std::swap(pka, pkb);
}
return gen_initiator_confirm ? util::F4(pka, pkb, random, r).value()
: util::F4(pkb, pka, random, r).value();
}
SecurityManager* pairing() const { return pairing_.get(); }
l2cap::testing::FakeChannel* fake_chan() const { return fake_chan_.get(); }
hci::testing::FakeLowEnergyConnection* fake_link() const {
return fake_link_.get();
}
int security_callback_count() const { return security_callback_count_; }
const std::optional<ErrorCode>& received_error_code() const {
return received_error_code_;
}
const Result<>& security_status() const { return security_status_; }
const SecurityProperties& sec_props() const { return sec_props_; }
int pairing_complete_count() const { return pairing_complete_count_; }
const Result<>& pairing_complete_status() const {
return pairing_complete_status_;
}
int pairing_data_callback_count() const {
return pairing_data_callback_count_;
}
int auth_failure_callback_count() const {
return auth_failure_callback_count_;
}
const hci::Result<>& auth_failure_status() const {
return auth_failure_status_;
}
int local_id_info_callback_count() const {
return local_id_info_callback_count_;
}
int new_sec_props_count() const { return new_sec_props_count_; }
const SecurityProperties& new_sec_props() const { return new_sec_props_; }
const std::optional<LTK>& peer_ltk() const { return pairing_data_.peer_ltk; }
const std::optional<LTK>& local_ltk() const {
return pairing_data_.local_ltk;
}
const std::optional<Key>& irk() const { return pairing_data_.irk; }
const std::optional<DeviceAddress>& identity() const {
return pairing_data_.identity_address;
}
const std::optional<Key>& csrk() const { return pairing_data_.csrk; }
using ConfirmDelegate = fit::function<void(ConfirmCallback)>;
void set_confirm_delegate(ConfirmDelegate delegate) {
confirm_delegate_ = std::move(delegate);
}
using DisplayDelegate =
fit::function<void(uint32_t, DisplayMethod, ConfirmCallback)>;
void set_display_delegate(DisplayDelegate delegate) {
display_delegate_ = std::move(delegate);
}
// sm::Delegate override:
using RequestPasskeyDelegate = fit::function<void(PasskeyResponseCallback)>;
void set_request_passkey_delegate(RequestPasskeyDelegate delegate) {
request_passkey_delegate_ = std::move(delegate);
}
void set_local_id_info(std::optional<IdentityInfo> info) {
local_id_info_ = info;
}
int security_request_count() const { return security_request_count_; }
int pairing_failed_count() const { return pairing_failed_count_; }
int pairing_request_count() const { return pairing_request_count_; }
int pairing_response_count() const { return pairing_response_count_; }
int pairing_public_key_count() const { return pairing_public_key_count_; }
int pairing_confirm_count() const { return pairing_confirm_count_; }
int pairing_random_count() const { return pairing_random_count_; }
int pairing_dhkey_check_count() const { return pairing_dhkey_check_count_; }
int enc_info_count() const { return enc_info_count_; }
int id_info_count() const { return id_info_count_; }
int id_addr_info_count() const { return id_addr_info_count_; }
int central_ident_count() const { return central_ident_count_; }
AuthReqField security_request_payload() const { return security_auth_req_; }
const std::optional<EcdhKey>& public_ecdh_key() const {
return public_ecdh_key_;
}
const UInt128& pairing_confirm() const { return pairing_confirm_; }
const UInt128& pairing_random() const { return pairing_random_; }
const UInt128& pairing_dhkey_check() const { return pairing_dhkey_check_; }
const UInt128& enc_info() const { return enc_info_; }
const UInt128& id_info() const { return id_info_; }
const DeviceAddress& id_addr_info() const { return id_addr_info_; }
uint16_t ediv() const { return ediv_; }
uint64_t rand() const { return rand_; }
const PairingData& pairing_data() const { return pairing_data_; }
const ByteBuffer& local_pairing_cmd() const { return local_pairing_cmd_; }
const ByteBuffer& peer_pairing_cmd() const { return peer_pairing_cmd_; }
private:
void Receive128BitCmd(Code cmd_code, const UInt128& value) {
StaticByteBuffer<sizeof(Header) + sizeof(UInt128)> buffer;
PacketWriter writer(cmd_code, &buffer);
*writer.mutable_payload<UInt128>() = value;
fake_chan()->Receive(buffer);
}
void InitializeTransport() {
// Ensure any tasks posted by an existing transport are dispatched.
RunUntilIdle();
auto mock_controller =
std::make_unique<bt::testing::MockController>(dispatcher());
controller_ = mock_controller->GetWeakPtr();
transport_ = std::make_unique<hci::Transport>(std::move(mock_controller),
dispatcher());
std::optional<bool> init_success;
transport_->Initialize([&](bool success) { init_success = success; });
RunUntilIdle();
ASSERT_TRUE(init_success.has_value());
ASSERT_TRUE(init_success.value());
transport_->InitializeACLDataChannel(hci::DataBufferInfo(1, 1),
hci::DataBufferInfo(1, 1));
}
testing::MockController::WeakPtr controller_;
std::unique_ptr<hci::Transport> transport_;
// We store the preq/pres values here to generate a valid confirm value for
// the fake side.
StaticByteBuffer<sizeof(Header) + sizeof(PairingRequestParams)>
local_pairing_cmd_, peer_pairing_cmd_;
// Number of times the security callback given to UpgradeSecurity has been
// called and the most recent parameters that it was called with.
int security_callback_count_ = 0;
Result<> security_status_ = fit::ok();
SecurityProperties sec_props_;
// Number of times the pairing data callback has been called and the most
// recent value that it was called with.
int pairing_data_callback_count_ = 0;
PairingData pairing_data_;
// Number of times the link security properties have been notified via
// OnNewSecurityProperties().
int new_sec_props_count_ = 0;
SecurityProperties new_sec_props_;
// State tracking the OnPairingComplete event.
int pairing_complete_count_ = 0;
Result<> pairing_complete_status_ = fit::ok();
// State tracking the OnAuthenticationFailure event.
int auth_failure_callback_count_ = 0;
hci::Result<> auth_failure_status_ = fit::ok();
// State tracking the OnIdentityInformationRequest event.
int local_id_info_callback_count_ = 0;
std::optional<IdentityInfo> local_id_info_;
// Delegate functions used to respond to user input requests from the Security
// Manager.
ConfirmDelegate confirm_delegate_;
DisplayDelegate display_delegate_;
RequestPasskeyDelegate request_passkey_delegate_;
// Counts of commands that we have sent out to the peer.
int security_request_count_ = 0;
int pairing_failed_count_ = 0;
int pairing_request_count_ = 0;
int pairing_response_count_ = 0;
int pairing_public_key_count_ = 0;
int pairing_confirm_count_ = 0;
int pairing_random_count_ = 0;
int pairing_dhkey_check_count_ = 0;
int enc_info_count_ = 0;
int id_info_count_ = 0;
int id_addr_info_count_ = 0;
int central_ident_count_ = 0;
// Values that have we have sent to the peer.
AuthReqField security_auth_req_ = 0;
std::optional<EcdhKey> public_ecdh_key_;
UInt128 pairing_confirm_ = {};
UInt128 pairing_random_ = {};
UInt128 pairing_dhkey_check_ = {};
UInt128 enc_info_ = {};
UInt128 id_info_ = {};
DeviceAddress id_addr_info_;
uint16_t ediv_ = 0;
uint64_t rand_ = 0;
std::optional<ErrorCode> received_error_code_;
std::unique_ptr<l2cap::testing::FakeChannel> fake_chan_;
std::unique_ptr<hci::testing::FakeLowEnergyConnection> fake_link_;
std::unique_ptr<SecurityManager> pairing_;
WeakSelf<Delegate> weak_delegate_;
BT_DISALLOW_COPY_AND_ASSIGN_ALLOW_MOVE(SecurityManagerTest);
};
class InitiatorPairingTest : public SecurityManagerTest {
public:
InitiatorPairingTest() = default;
~InitiatorPairingTest() override = default;
void SetUp() override {
SecurityManagerTest::SetUp();
SetUpSecurityManager();
}
void SetUpSecurityManager(
IOCapability ioc = IOCapability::kDisplayOnly,
BondableMode bondable_mode = BondableMode::Bondable) {
NewSecurityManager(Role::kInitiator, ioc, bondable_mode);
}
void GenerateMatchingLegacyConfirmAndRandom(UInt128* out_confirm,
UInt128* out_random,
uint32_t tk = 0) {
BT_DEBUG_ASSERT(out_confirm);
BT_DEBUG_ASSERT(out_random);
*out_random = kHardCodedPairingRandom;
GenerateLegacyConfirmValue(
*out_random, out_confirm, /*peer_initiator=*/false, tk);
}
struct MatchingPair {
UInt128 confirm;
UInt128 random;
};
MatchingPair GenerateMatchingScConfirmAndRandom(const LocalEcdhKey& peer_key,
uint8_t r = 0) {
MatchingPair pair;
pair.random = kHardCodedPairingRandom;
pair.confirm = GenerateScConfirmValue(peer_key,
pair.random,
Role::kInitiator,
/*gen_initiator_confirm=*/false,
r);
return pair;
}
// Emulate legacy pairing up until before encryption with STK. Returns the STK
// that the initiator is expected to encrypt the link with in |out_stk|.
//
// This will not resolve the encryption request that is made by using the STK
// before this function returns (this is to unit test encryption failure). Use
// FastForwardToPhase3() to also emulate successful encryption.
void FastForwardToSTK(UInt128* out_stk,
SecurityLevel level = SecurityLevel::kEncrypted,
KeyDistGenField remote_keys = 0,
KeyDistGenField local_keys = 0,
uint8_t max_key_size = kMaxEncryptionKeySize,
BondableMode bondable_mode = BondableMode::Bondable) {
UpgradeSecurity(level);
PairingRequestParams pairing_params;
pairing_params.io_capability = IOCapability::kNoInputNoOutput;
AuthReqField bondable = (bondable_mode == BondableMode::Bondable)
? AuthReq::kBondingFlag
: 0,
mitm_protected = (level >= SecurityLevel::kAuthenticated)
? AuthReq::kMITM
: 0;
pairing_params.auth_req = mitm_protected | bondable;
pairing_params.max_encryption_key_size = max_key_size;
pairing_params.initiator_key_dist_gen = local_keys;
pairing_params.responder_key_dist_gen = remote_keys;
ReceivePairingFeatures(pairing_params);
// Run the loop until the harness caches the feature exchange PDUs (preq &
// pres) so that we can generate a valid confirm value.
RunUntilIdle();
UInt128 sconfirm, srand;
GenerateMatchingLegacyConfirmAndRandom(&sconfirm, &srand);
ReceivePairingConfirm(sconfirm);
ReceivePairingRandom(srand);
RunUntilIdle();
EXPECT_EQ(1, pairing_confirm_count());
EXPECT_EQ(1, pairing_random_count());
EXPECT_EQ(0, pairing_failed_count());
EXPECT_EQ(0, security_callback_count());
BT_DEBUG_ASSERT(out_stk);
UInt128 tk;
tk.fill(0);
util::S1(tk, srand, pairing_random(), out_stk);
}
void FastForwardToPhase3(
UInt128* out_encryption_key,
bool secure_connections = false,
SecurityLevel level = SecurityLevel::kEncrypted,
KeyDistGenField remote_keys = 0,
KeyDistGenField local_keys = 0,
uint8_t max_key_size = kMaxEncryptionKeySize,
BondableMode bondable_mode = BondableMode::Bondable) {
if (secure_connections) {
FastForwardToScLtk(
out_encryption_key, level, remote_keys, local_keys, bondable_mode);
} else {
FastForwardToSTK(out_encryption_key,
level,
remote_keys,
local_keys,
max_key_size,
bondable_mode);
}
ASSERT_TRUE(fake_link()->ltk());
EXPECT_EQ(1, fake_link()->start_encryption_count());
// Resolve the encryption request.
fake_link()->TriggerEncryptionChangeCallback(fit::ok(/*enabled=*/true));
RunUntilIdle();
EXPECT_EQ(1, new_sec_props_count());
EXPECT_EQ(level, new_sec_props().level());
}
void FastForwardToScLtk(UInt128* out_ltk,
SecurityLevel level = SecurityLevel::kEncrypted,
KeyDistGenField peer_keys = 0,
KeyDistGenField local_keys = 0,
BondableMode bondable = BondableMode::Bondable) {
UpgradeSecurity(level);
RunUntilIdle();
ASSERT_EQ(1, pairing_request_count());
PairingRequestParams pres;
pres.io_capability = IOCapability::kDisplayYesNo;
pres.oob_data_flag = OOBDataFlag::kNotPresent;
AuthReqField bondable_flag =
(bondable == BondableMode::Bondable) ? AuthReq::kBondingFlag : 0;
AuthReqField mitm_flag =
(level >= SecurityLevel::kAuthenticated) ? AuthReq::kMITM : 0;
pres.auth_req = AuthReq::kSC | mitm_flag | bondable_flag;
pres.max_encryption_key_size = kMaxEncryptionKeySize;
pres.initiator_key_dist_gen = local_keys;
pres.responder_key_dist_gen = peer_keys;
ReceivePairingFeatures(pres);
RunUntilIdle();
ASSERT_TRUE(public_ecdh_key().has_value());
LocalEcdhKey peer_key = *LocalEcdhKey::Create();
ReceivePairingPublicKey(peer_key.GetSerializedPublicKey());
RunUntilIdle();
// We're in SC Numeric Comparison/Just Works, so as initiator we should not
// send a confirm.
ASSERT_EQ(0, pairing_confirm_count());
MatchingPair phase_2_vals = GenerateMatchingScConfirmAndRandom(peer_key);
ReceivePairingConfirm(phase_2_vals.confirm);
RunUntilIdle();
ASSERT_EQ(1, pairing_random_count());
// If using MITM, we expect to be in Numeric Comparison
ConfirmCallback display_cb = nullptr;
if (mitm_flag != 0) {
uint32_t kExpectedDisplayVal =
*util::G2(public_ecdh_key()->GetPublicKeyX(),
peer_key.GetPublicKeyX(),
pairing_random(),
phase_2_vals.random) %
1000000;
set_display_delegate(
[kExpectedDisplayVal, &display_cb](uint32_t compare_value,
Delegate::DisplayMethod method,
ConfirmCallback cb) {
ASSERT_TRUE(method == Delegate::DisplayMethod::kComparison);
ASSERT_EQ(kExpectedDisplayVal, compare_value);
display_cb = std::move(cb);
});
}
ReceivePairingRandom(phase_2_vals.random);
RunUntilIdle();
if (mitm_flag != 0) {
ASSERT_TRUE(display_cb);
display_cb(true);
} // Else we are content to use the default confirm delegate behavior to
// accept the pairing.
util::F5Results f5 = *util::F5(peer_key.CalculateDhKey(*public_ecdh_key()),
pairing_random(),
phase_2_vals.random,
kLocalAddr,
kPeerAddr);
UInt128 r_array{0};
PacketReader reader(&local_pairing_cmd());
PairingResponseParams preq = reader.payload<PairingRequestParams>();
UInt128 dhkey_check_a = *util::F6(f5.mac_key,
pairing_random(),
phase_2_vals.random,
r_array,
preq.auth_req,
preq.oob_data_flag,
preq.io_capability,
kLocalAddr,
kPeerAddr);
UInt128 dhkey_check_b = *util::F6(f5.mac_key,
phase_2_vals.random,
pairing_random(),
r_array,
pres.auth_req,
pres.oob_data_flag,
pres.io_capability,
kPeerAddr,
kLocalAddr);
RunUntilIdle();
EXPECT_EQ(1, pairing_dhkey_check_count());
ASSERT_EQ(dhkey_check_a, pairing_dhkey_check());
ReceivePairingDHKeyCheck(dhkey_check_b);
RunUntilIdle();
EXPECT_EQ(0, pairing_failed_count());
EXPECT_EQ(0, security_callback_count());
ASSERT_TRUE(out_ltk);
*out_ltk = f5.ltk;
}
private:
BT_DISALLOW_COPY_AND_ASSIGN_ALLOW_MOVE(InitiatorPairingTest);
};
class ResponderPairingTest : public SecurityManagerTest {
public:
ResponderPairingTest() = default;
~ResponderPairingTest() override = default;
void SetUp() override {
SecurityManagerTest::SetUp();
SetUpSecurityManager();
}
void SetUpSecurityManager(
IOCapability ioc = IOCapability::kDisplayOnly,
BondableMode bondable_mode = BondableMode::Bondable) {
NewSecurityManager(Role::kResponder, ioc, bondable_mode);
}
void GenerateMatchingLegacyConfirmAndRandom(UInt128* out_confirm,
UInt128* out_random,
uint32_t tk = 0) {
BT_DEBUG_ASSERT(out_confirm);
BT_DEBUG_ASSERT(out_random);
*out_random = kHardCodedPairingRandom;
GenerateLegacyConfirmValue(
*out_random, out_confirm, /*peer_initiator=*/true, tk);
}
struct MatchingPair {
UInt128 confirm;
UInt128 random;
};
MatchingPair GenerateMatchingScConfirmAndRandom(const LocalEcdhKey& peer_key,
uint8_t r = 0) {
MatchingPair pair;
pair.random = kHardCodedPairingRandom;
pair.confirm = GenerateScConfirmValue(peer_key,
pair.random,
Role::kResponder,
/*gen_initiator_confirm=*/true,
r);
return pair;
}
void ReceivePairingRequest(IOCapability ioc = IOCapability::kNoInputNoOutput,
AuthReqField auth_req = 0,
uint8_t max_enc_key_size = kMaxEncryptionKeySize) {
ReceivePairingFeatures(
ioc, auth_req, max_enc_key_size, /*peer_initiator=*/true);
}
void FastForwardToSTK(UInt128* out_stk,
SecurityLevel level = SecurityLevel::kEncrypted,
KeyDistGenField remote_keys = 0,
KeyDistGenField local_keys = 0,
uint8_t max_key_size = kMaxEncryptionKeySize,
BondableMode bondable_mode = BondableMode::Bondable) {
PairingRequestParams pairing_params;
pairing_params.io_capability = IOCapability::kNoInputNoOutput;
AuthReqField bondable = (bondable_mode == BondableMode::Bondable)
? AuthReq::kBondingFlag
: 0,
mitm_protected = (level >= SecurityLevel::kAuthenticated)
? AuthReq::kMITM
: 0;
pairing_params.auth_req = mitm_protected | bondable;
pairing_params.max_encryption_key_size = max_key_size;
pairing_params.initiator_key_dist_gen = remote_keys;
pairing_params.responder_key_dist_gen = local_keys;
ReceivePairingFeatures(pairing_params, /*peer_initiator=*/true);
// Run the loop until the harness caches the feature exchange PDUs (preq &
// pres) so that we can generate a valid confirm value.
RunUntilIdle();
EXPECT_EQ(0, pairing_request_count());
EXPECT_EQ(1, pairing_response_count());
// The initiator should start the confirm/random exchange to generate the
// Phase 2 keys.
EXPECT_EQ(0, pairing_confirm_count());
EXPECT_EQ(0, pairing_random_count());
UInt128 mconfirm, mrand;
GenerateMatchingLegacyConfirmAndRandom(&mconfirm, &mrand);
ReceivePairingConfirm(mconfirm);
RunUntilIdle();
EXPECT_EQ(1, pairing_confirm_count());
EXPECT_EQ(0, pairing_random_count());
ReceivePairingRandom(mrand);
RunUntilIdle();
EXPECT_EQ(1, pairing_confirm_count());
EXPECT_EQ(1, pairing_random_count());
EXPECT_EQ(0, pairing_failed_count());
EXPECT_EQ(0, security_callback_count());
BT_DEBUG_ASSERT(out_stk);
UInt128 tk;
tk.fill(0);
util::S1(tk, pairing_random(), mrand, out_stk);
}
void FastForwardToPhase3(
UInt128* out_encryption_key,
bool secure_connections = false,
SecurityLevel level = SecurityLevel::kEncrypted,
KeyDistGenField remote_keys = 0,
KeyDistGenField local_keys = 0,
uint8_t max_key_size = kMaxEncryptionKeySize,
BondableMode bondable_mode = BondableMode::Bondable) {
if (secure_connections) {
FastForwardToScLtk(
out_encryption_key, level, remote_keys, local_keys, bondable_mode);
} else {
FastForwardToSTK(out_encryption_key,
level,
remote_keys,
local_keys,
max_key_size,
bondable_mode);
}
ASSERT_TRUE(fake_link()->ltk());
// No local start encryption request should be made.
EXPECT_EQ(0, fake_link()->start_encryption_count());
// Pretend that the initiator succeeded in encrypting the connection.
fake_link()->TriggerEncryptionChangeCallback(fit::ok(/*enabled=*/true));
RunUntilIdle();
EXPECT_EQ(1, new_sec_props_count());
EXPECT_EQ(level, new_sec_props().level());
}
void FastForwardToScLtk(UInt128* out_ltk,
SecurityLevel level = SecurityLevel::kEncrypted,
KeyDistGenField peer_keys = 0,
KeyDistGenField local_keys = 0,
BondableMode bondable = BondableMode::Bondable) {
PairingRequestParams preq;
preq.io_capability = IOCapability::kDisplayYesNo;
preq.oob_data_flag = OOBDataFlag::kNotPresent;
AuthReqField bondable_flag =
(bondable == BondableMode::Bondable) ? AuthReq::kBondingFlag : 0;
AuthReqField mitm_flag =
(level >= SecurityLevel::kAuthenticated) ? AuthReq::kMITM : 0;
preq.auth_req = AuthReq::kSC | mitm_flag | bondable_flag;
preq.max_encryption_key_size = kMaxEncryptionKeySize;
preq.initiator_key_dist_gen = local_keys;
preq.responder_key_dist_gen = peer_keys;
ReceivePairingFeatures(preq, /*peer_initiator=*/true);
RunUntilIdle();
ASSERT_EQ(1, pairing_response_count());
LocalEcdhKey peer_key = *LocalEcdhKey::Create();
ReceivePairingPublicKey(peer_key.GetSerializedPublicKey());
RunUntilIdle();
ASSERT_TRUE(public_ecdh_key().has_value());
ASSERT_EQ(1, pairing_public_key_count());
// We are in Just Works or Numeric Comparison based on IOCapabilities/MITM
// preferences, so we expect the confirm value immediately after the public
// key.
ASSERT_EQ(1, pairing_confirm_count());
std::optional<uint32_t> display_val;
if (mitm_flag != 0) {
set_display_delegate([&](uint32_t compare_value,
Delegate::DisplayMethod method,
ConfirmCallback cb) {
ASSERT_TRUE(method == Delegate::DisplayMethod::kComparison);
display_val = compare_value;
cb(true);
});
} // Else we are content to use the default confirm delegate behavior to
// accept the pairing.
auto peer_rand = Random<PairingRandomValue>();
ReceivePairingRandom(peer_rand);
RunUntilIdle();
ASSERT_EQ(1, pairing_random_count());
ASSERT_EQ(GenerateScConfirmValue(
peer_key, pairing_random(), Role::kResponder, false),
pairing_confirm());
if (mitm_flag != 0) {
ASSERT_TRUE(display_val.has_value());
uint32_t kExpectedDisplayVal =
*util::G2(peer_key.GetPublicKeyX(),
public_ecdh_key()->GetPublicKeyX(),
peer_rand,
pairing_random()) %
1000000;
EXPECT_EQ(kExpectedDisplayVal, display_val);
}
util::F5Results f5 = *util::F5(peer_key.CalculateDhKey(*public_ecdh_key()),
peer_rand,
pairing_random(),
kPeerAddr,
kLocalAddr);
UInt128 r_array{0};
PacketReader reader(&local_pairing_cmd());
PairingResponseParams pres = reader.payload<PairingResponseParams>();
UInt128 dhkey_check_a = *util::F6(f5.mac_key,
peer_rand,
pairing_random(),
r_array,
preq.auth_req,
preq.oob_data_flag,
preq.io_capability,
kPeerAddr,
kLocalAddr);
UInt128 dhkey_check_b = *util::F6(f5.mac_key,
pairing_random(),
peer_rand,
r_array,
pres.auth_req,
pres.oob_data_flag,
pres.io_capability,
kLocalAddr,
kPeerAddr);
ReceivePairingDHKeyCheck(dhkey_check_a);
RunUntilIdle();
EXPECT_EQ(1, pairing_dhkey_check_count());
ASSERT_EQ(dhkey_check_b, pairing_dhkey_check());
EXPECT_EQ(0, pairing_failed_count());
EXPECT_EQ(0, pairing_complete_count());
ASSERT_TRUE(out_ltk);
*out_ltk = f5.ltk;
}
private:
BT_DISALLOW_COPY_AND_ASSIGN_ALLOW_MOVE(ResponderPairingTest);
};
// Calling `Abort` with no in-progress security upgrade should not cause a
// PairingComplete event.
TEST_F(InitiatorPairingTest, AbortNoSecurityUpgradeInProgress) {
pairing()->Abort();
RunUntilIdle();
EXPECT_EQ(0, pairing_complete_count());
}
// Disconnecting with no in-progress security upgrade should not cause a
// PairingComplete event.
TEST_F(InitiatorPairingTest, DisconnectNoSecurityUpgradeInProgress) {
fake_chan()->Close();
RunUntilIdle();
EXPECT_EQ(0, pairing_complete_count());
}
// Requesting pairing at the current security level should succeed immediately.
TEST_F(InitiatorPairingTest, UpgradeSecurityCurrentLevel) {
UpgradeSecurity(SecurityLevel::kNoSecurity);
RunUntilIdle();
// No pairing requests should have been made.
EXPECT_EQ(0, pairing_request_count());
EXPECT_EQ(0, pairing_complete_count());
// Pairing should succeed.
EXPECT_EQ(1, security_callback_count());
EXPECT_EQ(fit::ok(), security_status());
EXPECT_EQ(SecurityLevel::kNoSecurity, sec_props().level());
EXPECT_EQ(0u, sec_props().enc_key_size());
EXPECT_FALSE(sec_props().secure_connections());
}
// Peer aborts during Phase 1.
TEST_F(InitiatorPairingTest, PairingFailedInPhase1) {
UpgradeSecurity(SecurityLevel::kEncrypted);
RunUntilIdle();
// Pairing not complete yet but we should be in Phase 1.
EXPECT_EQ(0, security_callback_count());
EXPECT_EQ(1, pairing_request_count());
ReceivePairingFailed(ErrorCode::kPairingNotSupported);
RunUntilIdle();
EXPECT_EQ(1, security_callback_count());
EXPECT_EQ(1, pairing_request_count());
EXPECT_EQ(ToResult(ErrorCode::kPairingNotSupported), security_status());
EXPECT_EQ(1, pairing_complete_count());
EXPECT_EQ(security_status(), pairing_complete_status());
}
// Local aborts during Phase 1.
TEST_F(InitiatorPairingTest, PairingAbortedInPhase1) {
UpgradeSecurity(SecurityLevel::kEncrypted);
RunUntilIdle();
// Pairing not complete yet but we should be in Phase 1.
EXPECT_EQ(0, security_callback_count());
EXPECT_EQ(1, pairing_request_count());
pairing()->Abort();
RunUntilIdle();
EXPECT_EQ(1, security_callback_count());
EXPECT_EQ(1, pairing_request_count());
EXPECT_EQ(ToResult(ErrorCode::kUnspecifiedReason), security_status());
EXPECT_EQ(1, pairing_complete_count());
EXPECT_EQ(security_status(), pairing_complete_status());
}
// Local resets I/O capabilities while pairing. This should abort any ongoing
// pairing and the new I/O capabilities should be used in following pairing
// requests.
TEST_F(InitiatorPairingTest, SecurityManagerResetDuringPairing) {
UpgradeSecurity(SecurityLevel::kEncrypted);
RunUntilIdle();
// Pairing not complete yet but we should be in Phase 1.
EXPECT_EQ(0, security_callback_count());
EXPECT_EQ(1, pairing_request_count());
pairing()->Reset(IOCapability::kNoInputNoOutput);
RunUntilIdle();
EXPECT_EQ(1, security_callback_count());
EXPECT_EQ(1, pairing_request_count());
EXPECT_EQ(ToResult(ErrorCode::kUnspecifiedReason), security_status());
EXPECT_EQ(1, pairing_complete_count());
EXPECT_EQ(security_status(), pairing_complete_status());
UpgradeSecurity(SecurityLevel::kEncrypted);
RunUntilIdle();
// Should have sent a new pairing request.
EXPECT_EQ(2, pairing_request_count());
// Make sure that the new request has the new I/O capabilities.
const auto& params = local_pairing_cmd().view(1).To<PairingRequestParams>();
EXPECT_EQ(IOCapability::kNoInputNoOutput, params.io_capability);
}
TEST_F(InitiatorPairingTest, ReceiveConfirmValueWhileNotPairing) {
UInt128 confirm;
ReceivePairingConfirm(confirm);
RunUntilIdle();
// Nothing should happen.
EXPECT_EQ(0, pairing_confirm_count());
EXPECT_EQ(0, pairing_random_count());
EXPECT_EQ(0, pairing_failed_count());
EXPECT_EQ(0, security_callback_count());
}
TEST_F(InitiatorPairingTest, ReceiveConfirmValueInPhase1) {
UpgradeSecurity(SecurityLevel::kEncrypted);
RunUntilIdle();
UInt128 confirm;
ReceivePairingConfirm(confirm);
RunUntilIdle();
EXPECT_EQ(0, pairing_confirm_count());
EXPECT_EQ(0, pairing_random_count());
EXPECT_EQ(1, pairing_failed_count());
EXPECT_EQ(1, security_callback_count());
EXPECT_EQ(ToResult(ErrorCode::kUnspecifiedReason), security_status());
EXPECT_EQ(1, pairing_complete_count());
EXPECT_EQ(security_status(), pairing_complete_status());
}
TEST_F(InitiatorPairingTest,
RejectUnauthenticatedPairingInSecureConnectionsOnlyMode) {
SetUpSecurityManager(IOCapability::kKeyboardDisplay);
pairing()->set_security_mode(gap::LESecurityMode::SecureConnectionsOnly);
// In SC Only mode, SM should translate this "encrypted" request into a MITM
// requirement.
UpgradeSecurity(SecurityLevel::kEncrypted);
// The peer has NoInputNoOutput IOCapabilities, thus cannot perform
// authenticated pairing.
ReceivePairingFeatures(IOCapability::kNoInputNoOutput,
AuthReq::kBondingFlag | AuthReq::kSC);
RunUntilIdle();
EXPECT_EQ(1, pairing_failed_count());
EXPECT_EQ(1, security_callback_count());
EXPECT_EQ(ToResult(ErrorCode::kAuthenticationRequirements),
security_status());
EXPECT_EQ(1, pairing_complete_count());
EXPECT_EQ(security_status(), pairing_complete_status());
}
TEST_F(InitiatorPairingTest,
RejectUnauthenticatedEncryptionInSecureConnectionsOnlyMode) {
pairing()->set_security_mode(gap::LESecurityMode::SecureConnectionsOnly);
const LTK kUnauthenticatedLtk(SecurityProperties(/*encrypted=*/true,
/*authenticated=*/false,
/*secure_connections=*/true,
kMaxEncryptionKeySize),
hci_spec::LinkKey());
pairing()->AssignLongTermKey(kUnauthenticatedLtk);
RunUntilIdle();
// After setting SC Only mode, assigning and encrypting with an
// unauthenticated LTK should cause the channel to be disconnected with an
// authentication failure.
fake_link()->TriggerEncryptionChangeCallback(fit::ok(/*enabled=*/true));
RunUntilIdle();
EXPECT_EQ(1, auth_failure_callback_count());
EXPECT_EQ(ToResult(HostError::kInsufficientSecurity), auth_failure_status());
EXPECT_TRUE(fake_chan()->link_error());
}
TEST_F(InitiatorPairingTest,
AllowSecureAuthenticatedPairingInSecureConnectionsOnlyMode) {
SetUpSecurityManager(IOCapability::kDisplayYesNo);
pairing()->set_security_mode(gap::LESecurityMode::SecureConnectionsOnly);
UInt128 enc_key;
FastForwardToPhase3(&enc_key,
/*secure_connections=*/true,
SecurityLevel::kSecureAuthenticated);
RunUntilIdle();
// After setting SC Only mode, secure authenticated pairing should still
// complete successfully.
EXPECT_EQ(1, pairing_data_callback_count());
EXPECT_TRUE(peer_ltk().has_value());
EXPECT_EQ(0, pairing_failed_count());
EXPECT_EQ(1, security_callback_count());
EXPECT_EQ(1, pairing_complete_count());
EXPECT_EQ(fit::ok(), security_status());
EXPECT_EQ(security_status(), pairing_complete_status());
EXPECT_EQ(SecurityLevel::kSecureAuthenticated, sec_props().level());
}
// In Phase 2 but still waiting to receive TK.
TEST_F(InitiatorPairingTest, ReceiveConfirmValueWhileWaitingForUserInput) {
bool tk_requested = false;
set_confirm_delegate([&](ConfirmCallback) { tk_requested = true; });
UpgradeSecurity(SecurityLevel::kEncrypted);
ReceivePairingFeatures();
RunUntilIdle();
EXPECT_TRUE(tk_requested);
UInt128 confirm;
ReceivePairingConfirm(confirm);
RunUntilIdle();
EXPECT_EQ(0, pairing_confirm_count());
EXPECT_EQ(0, pairing_random_count());
EXPECT_EQ(1, pairing_failed_count());
EXPECT_EQ(1, security_callback_count());
EXPECT_EQ(ToResult(ErrorCode::kUnspecifiedReason), security_status());
EXPECT_EQ(1, pairing_complete_count());
EXPECT_EQ(security_status(), pairing_complete_status());
}
// SecurityManager destroyed when waiting for Just Works user confirmation.
TEST_F(InitiatorPairingTest,
SecurityManagerDestroyedStateWhileWaitingForUserInput) {
ConfirmCallback respond;
set_confirm_delegate([&](ConfirmCallback rsp) { respond = std::move(rsp); });
UpgradeSecurity(SecurityLevel::kEncrypted);
ReceivePairingFeatures();
RunUntilIdle();
EXPECT_TRUE(respond);
DestroySecurityManager();
// This should proceed safely.
respond(true);
RunUntilIdle();
}
// Pairing no longer in progress when waiting for Just Works user confirmation.
TEST_F(InitiatorPairingTest, PairingAbortedWhileWaitingForUserInput) {
ConfirmCallback respond;
set_confirm_delegate([&](ConfirmCallback rsp) { respond = std::move(rsp); });
UpgradeSecurity(SecurityLevel::kEncrypted);
ReceivePairingFeatures();
RunUntilIdle();
EXPECT_TRUE(respond);
ReceivePairingFailed(ErrorCode::kPairingNotSupported);
RunUntilIdle();
EXPECT_EQ(1, security_callback_count());
EXPECT_EQ(ToResult(ErrorCode::kPairingNotSupported), security_status());
EXPECT_EQ(1, pairing_complete_count());
EXPECT_EQ(security_status(), pairing_complete_status());
// This should have no effect.
respond(true);
RunUntilIdle();
EXPECT_EQ(1, pairing_request_count());
EXPECT_EQ(0, pairing_response_count());
EXPECT_EQ(0, pairing_confirm_count());
EXPECT_EQ(0, pairing_random_count());
EXPECT_EQ(0, pairing_failed_count());
EXPECT_EQ(1, security_callback_count());
EXPECT_EQ(1, pairing_complete_count());
EXPECT_EQ(0, pairing_data_callback_count());
}
// Pairing procedure stopped and restarted when TKResponse runs. The TKResponse
// does not belong to the current pairing.
TEST_F(InitiatorPairingTest, PairingRestartedWhileWaitingForTK) {
ConfirmCallback respond;
set_confirm_delegate([&](ConfirmCallback rsp) { respond = std::move(rsp); });
UpgradeSecurity(SecurityLevel::kEncrypted);
ReceivePairingFeatures();
RunUntilIdle();
EXPECT_TRUE(respond);
// Stop pairing.
ReceivePairingFailed(ErrorCode::kPairingNotSupported);
RunUntilIdle();
EXPECT_EQ(1, security_callback_count());
EXPECT_EQ(ToResult(ErrorCode::kPairingNotSupported), security_status());
EXPECT_EQ(1, pairing_complete_count());
EXPECT_EQ(security_status(), pairing_complete_status());
// Reset the delegate so that |respond| doesn't get overwritten by the second
// pairing.
set_confirm_delegate(nullptr);
UpgradeSecurity(SecurityLevel::kEncrypted);
ReceivePairingFeatures();
RunUntilIdle();
EXPECT_EQ(2, pairing_request_count());
EXPECT_EQ(0, pairing_response_count());
EXPECT_EQ(1, pairing_confirm_count());
EXPECT_EQ(0, pairing_random_count());
EXPECT_EQ(0, pairing_failed_count());
EXPECT_EQ(1, security_callback_count());
EXPECT_EQ(0, pairing_data_callback_count());
// This should have no effect.
respond(true);
RunUntilIdle();
EXPECT_EQ(2, pairing_request_count());
EXPECT_EQ(0, pairing_response_count());
EXPECT_EQ(1, pairing_confirm_count());
EXPECT_EQ(0, pairing_random_count());
EXPECT_EQ(0, pairing_failed_count());
EXPECT_EQ(1, security_callback_count());
EXPECT_EQ(1, pairing_complete_count());
EXPECT_EQ(0, pairing_data_callback_count());
}
TEST_F(InitiatorPairingTest, ReceiveRandomValueWhileNotPairing) {
UInt128 random;
ReceivePairingRandom(random);
RunUntilIdle();
// Nothing should happen.
EXPECT_EQ(0, pairing_confirm_count());
EXPECT_EQ(0, pairing_random_count());
EXPECT_EQ(0, pairing_failed_count());
EXPECT_EQ(0, security_callback_count());
}
TEST_F(InitiatorPairingTest, ReceiveRandomValueInPhase1) {
UpgradeSecurity(SecurityLevel::kEncrypted);
RunUntilIdle();
UInt128 random;
ReceivePairingRandom(random);
RunUntilIdle();
EXPECT_EQ(0, pairing_confirm_count());
EXPECT_EQ(0, pairing_random_count());
EXPECT_EQ(1, pairing_failed_count());
EXPECT_EQ(1, security_callback_count());
EXPECT_EQ(ToResult(ErrorCode::kUnspecifiedReason), security_status());
EXPECT_EQ(1, pairing_complete_count());
EXPECT_EQ(security_status(), pairing_complete_status());
}
// In Phase 2 but still waiting to receive TK.
TEST_F(InitiatorPairingTest, ReceiveRandomValueWhileWaitingForTK) {
bool confirmation_requested = false;
set_confirm_delegate([&](ConfirmCallback) { confirmation_requested = true; });
UpgradeSecurity(SecurityLevel::kEncrypted);
ReceivePairingFeatures();
RunUntilIdle();
EXPECT_TRUE(confirmation_requested);
UInt128 random;
ReceivePairingRandom(random);
RunUntilIdle();
EXPECT_EQ(0, pairing_confirm_count());
EXPECT_EQ(0, pairing_random_count());
EXPECT_EQ(1, pairing_failed_count());
EXPECT_EQ(1, security_callback_count());
EXPECT_EQ(ToResult(ErrorCode::kUnspecifiedReason), security_status());
EXPECT_EQ(1, pairing_complete_count());
EXPECT_EQ(security_status(), pairing_complete_status());
}
TEST_F(InitiatorPairingTest, LegacyPhase2SconfirmValueReceivedTwice) {
UpgradeSecurity(SecurityLevel::kEncrypted);
RunUntilIdle();
ReceivePairingFeatures();
RunUntilIdle();
// Should have received Mconfirm.
EXPECT_EQ(1, pairing_confirm_count());
EXPECT_EQ(0, pairing_random_count());
EXPECT_EQ(0, security_callback_count());
UInt128 confirm;
ReceivePairingConfirm(confirm);
RunUntilIdle();
// Should have received Mrand.
EXPECT_EQ(1, pairing_confirm_count());
EXPECT_EQ(1, pairing_random_count());
EXPECT_EQ(0, security_callback_count());
// Send Mconfirm again
ReceivePairingConfirm(confirm);
RunUntilIdle();
EXPECT_EQ(1, pairing_confirm_count());
EXPECT_EQ(1, pairing_random_count());
EXPECT_EQ(1, pairing_failed_count());
EXPECT_EQ(1, security_callback_count());
EXPECT_EQ(ToResult(ErrorCode::kUnspecifiedReason), security_status());
EXPECT_EQ(1, pairing_complete_count());
EXPECT_EQ(security_status(), pairing_complete_status());
}
TEST_F(InitiatorPairingTest, LegacyPhase2ReceiveRandomValueInWrongOrder) {
UpgradeSecurity(SecurityLevel::kEncrypted);
RunUntilIdle();
ReceivePairingFeatures();
RunUntilIdle();
// Should have received Mconfirm.
EXPECT_EQ(1, pairing_confirm_count());
EXPECT_EQ(0, pairing_random_count());
EXPECT_EQ(0, security_callback_count());
UInt128 random;
ReceivePairingRandom(random);
RunUntilIdle();
// Should have aborted pairing if Srand arrives before Srand.
EXPECT_EQ(1, pairing_confirm_count());
EXPECT_EQ(0, pairing_random_count());
EXPECT_EQ(1, pairing_failed_count());
EXPECT_EQ(1, security_callback_count());
EXPECT_EQ(ToResult(ErrorCode::kUnspecifiedReason), security_status());
EXPECT_EQ(1, pairing_complete_count());
EXPECT_EQ(security_status(), pairing_complete_status());
}
TEST_F(InitiatorPairingTest, LegacyPhase2SconfirmValueInvalid) {
UpgradeSecurity(SecurityLevel::kEncrypted);
RunUntilIdle();
// Pick I/O capabilities and MITM flags that will result in Just Works
// pairing.
ReceivePairingFeatures();
RunUntilIdle();
// Should have received Mconfirm.
EXPECT_EQ(1, pairing_confirm_count());
EXPECT_EQ(0, pairing_random_count());
EXPECT_EQ(0, security_callback_count());
// Receive Sconfirm and Srand values that don't match.
UInt128 confirm, random;
confirm.fill(0);
random.fill(1);
ReceivePairingConfirm(confirm);
RunUntilIdle();
// Should have received Mrand.
EXPECT_EQ(1, pairing_confirm_count());
EXPECT_EQ(1, pairing_random_count());
EXPECT_EQ(0, security_callback_count());
// Our Mconfirm/Mrand should be correct.
UInt128 expected_confirm;
GenerateLegacyConfirmValue(pairing_random(), &expected_confirm);
EXPECT_EQ(expected_confirm, pairing_confirm());
// Send the non-matching Srandom.
ReceivePairingRandom(random);
RunUntilIdle();
EXPECT_EQ(1, pairing_confirm_count());
EXPECT_EQ(1, pairing_random_count());
EXPECT_EQ(1, pairing_failed_count());
EXPECT_EQ(1, security_callback_count());
EXPECT_EQ(ToResult(ErrorCode::kConfirmValueFailed), security_status());
EXPECT_EQ(1, pairing_complete_count());
EXPECT_EQ(security_status(), pairing_complete_status());
}
TEST_F(InitiatorPairingTest, LegacyPhase2RandomValueReceivedTwice) {
UpgradeSecurity(SecurityLevel::kEncrypted);
RunUntilIdle();
// Pick I/O capabilities and MITM flags that will result in Just Works
// pairing.
ReceivePairingFeatures();
RunUntilIdle();
// Should have received Mconfirm.
EXPECT_EQ(1, pairing_confirm_count());
EXPECT_EQ(0, pairing_random_count());
EXPECT_EQ(0, security_callback_count());
// Receive Sconfirm and Srand values that match.
UInt128 confirm, random;
GenerateMatchingLegacyConfirmAndRandom(&confirm, &random);
ReceivePairingConfirm(confirm);
RunUntilIdle();
// Should have received Mrand.
EXPECT_EQ(1, pairing_confirm_count());
EXPECT_EQ(1, pairing_random_count());
EXPECT_EQ(0, security_callback_count());
// Our Mconfirm/Mrand should be correct.
UInt128 expected_confirm;
GenerateLegacyConfirmValue(pairing_random(), &expected_confirm);
EXPECT_EQ(expected_confirm, pairing_confirm());
// Send Srandom.
ReceivePairingRandom(random);
RunUntilIdle();
EXPECT_EQ(1, pairing_confirm_count());
EXPECT_EQ(1, pairing_random_count());
EXPECT_EQ(0, pairing_failed_count());
EXPECT_EQ(0, security_callback_count());
// Send Srandom again.
ReceivePairingRandom(random);
RunUntilIdle();
EXPECT_EQ(1, pairing_confirm_count());
EXPECT_EQ(1, pairing_random_count());
EXPECT_EQ(1, pairing_failed_count());
EXPECT_EQ(1, security_callback_count());
EXPECT_EQ(ToResult(ErrorCode::kUnspecifiedReason), security_status());
EXPECT_EQ(1, pairing_complete_count());
EXPECT_EQ(security_status(), pairing_complete_status());
}
TEST_F(InitiatorPairingTest, LegacyPhase2ConfirmValuesExchanged) {
UpgradeSecurity(SecurityLevel::kEncrypted);
RunUntilIdle();
// Pick I/O capabilities and MITM flags that will result in Just Works
// pairing.
ReceivePairingFeatures();
RunUntilIdle();
// Should have received Mconfirm.
EXPECT_EQ(1, pairing_confirm_count());
EXPECT_EQ(0, pairing_random_count());
EXPECT_EQ(0, security_callback_count());
// Receive Sconfirm and Srand values that match.
UInt128 confirm, random;
GenerateMatchingLegacyConfirmAndRandom(&confirm, &random);
ReceivePairingConfirm(confirm);
RunUntilIdle();
// Should have received Mrand.
EXPECT_EQ(1, pairing_confirm_count());
EXPECT_EQ(1, pairing_random_count());
EXPECT_EQ(0, security_callback_count());
// Our Mconfirm/Mrand should be correct.
UInt128 expected_confirm;
GenerateLegacyConfirmValue(pairing_random(), &expected_confirm);
EXPECT_EQ(expected_confirm, pairing_confirm());
// Send Srandom.
ReceivePairingRandom(random);
RunUntilIdle();
EXPECT_EQ(1, pairing_confirm_count());
EXPECT_EQ(1, pairing_random_count());
EXPECT_EQ(0, pairing_failed_count());
EXPECT_EQ(0, security_callback_count());
}
// TK delegate rejects pairing. When pairing method is "PasskeyEntryInput", this
// should result in a "Passkey Entry Failed" error.
TEST_F(InitiatorPairingTest, LegacyPhase2TKDelegateRejectsPasskeyInput) {
SetUpSecurityManager(IOCapability::kKeyboardOnly);
bool tk_requested = false;
PasskeyResponseCallback respond;
set_request_passkey_delegate([&](PasskeyResponseCallback cb_rsp) {
tk_requested = true;
respond = std::move(cb_rsp);
});
UpgradeSecurity(SecurityLevel::kEncrypted);
RunUntilIdle();
// Pick I/O capabilities and MITM flags that will result in Passkey Entry
// pairing.
ReceivePairingFeatures(IOCapability::kDisplayOnly, AuthReq::kMITM);
RunUntilIdle();
ASSERT_TRUE(tk_requested);
// Reject pairing.
respond(-1);
RunUntilIdle();
EXPECT_EQ(0, pairing_confirm_count());
EXPECT_EQ(0, pairing_random_count());
EXPECT_EQ(1, pairing_failed_count());
EXPECT_EQ(1, security_callback_count());
EXPECT_EQ(ToResult(ErrorCode::kPasskeyEntryFailed), security_status());
}
// TK delegate rejects pairing.
TEST_F(InitiatorPairingTest, LegacyPhase2TKDelegateRejectsPairing) {
bool tk_requested = false;
ConfirmCallback respond;
set_confirm_delegate([&](ConfirmCallback cb_rsp) {
tk_requested = true;
respond = std::move(cb_rsp);
});
UpgradeSecurity(SecurityLevel::kEncrypted);
RunUntilIdle();
ReceivePairingFeatures();
RunUntilIdle();
ASSERT_TRUE(tk_requested);
// Reject pairing.
respond(false);
RunUntilIdle();
EXPECT_EQ(0, pairing_confirm_count());
EXPECT_EQ(0, pairing_random_count());
EXPECT_EQ(1, pairing_failed_count());
EXPECT_EQ(1, security_callback_count());
EXPECT_EQ(ToResult(ErrorCode::kUnspecifiedReason), security_status());
}
TEST_F(InitiatorPairingTest, IgnoresExpiredConfirmRequestCallback) {
ConfirmCallback respond = nullptr;
set_confirm_delegate([&](ConfirmCallback rsp) { respond = std::move(rsp); });
UpgradeSecurity(SecurityLevel::kEncrypted);
RunUntilIdle();
ReceivePairingFeatures();
RunUntilIdle();
ASSERT_TRUE(respond);
ConfirmCallback first_pairing_cb = std::move(respond);
pairing()->Abort();
RunUntilIdle();
EXPECT_EQ(1, pairing_failed_count());
// We reset the respond variable so we can "catch" the next PairingDelegate
// request in the same variable (the `set_confirm_delegate` callback still has
// the reference to `respond`)
respond = nullptr;
// Start a separate pairing from the one captured in `first_pairing_cb`, which
// was `Abort`ed
UpgradeSecurity(SecurityLevel::kEncrypted);
RunUntilIdle();
ReceivePairingFeatures();
RunUntilIdle();
first_pairing_cb(true);
RunUntilIdle();
// The callback from the `Abort`ed pairing should be ignored, while calling
// `respond`, which is associated with the active pairing, should cause the
// expected Pairing Confirm to be sent.
EXPECT_EQ(0, pairing_confirm_count());
ASSERT_TRUE(respond);
respond(true);
RunUntilIdle();
EXPECT_EQ(1, pairing_confirm_count());
}
TEST_F(InitiatorPairingTest, IgnoresExpiredDisplayRequestCallback) {
SetUpSecurityManager(IOCapability::kDisplayOnly);
ConfirmCallback respond = nullptr;
set_display_delegate(
[&](uint32_t /**/, Delegate::DisplayMethod method, ConfirmCallback rsp) {
ASSERT_EQ(Delegate::DisplayMethod::kPeerEntry, method);
respond = std::move(rsp);
});
// Must request MITM to test PasskeyEntryDisplay instead of JustWorks pairing
UpgradeSecurity(SecurityLevel::kAuthenticated);
RunUntilIdle();
ReceivePairingFeatures(IOCapability::kKeyboardOnly);
RunUntilIdle();
ASSERT_TRUE(respond);
ConfirmCallback first_pairing_cb = std::move(respond);
pairing()->Abort();
RunUntilIdle();
EXPECT_EQ(1, pairing_failed_count());
// We reset the respond variable so we can "catch" the next PairingDelegate
// request in the same variable (the `set_display_delegate` callback still has
// the reference to `respond`)
respond = nullptr;
// Start a separate pairing from the one captured in `first_pairing_cb`, which
// was `Abort`ed
UpgradeSecurity(SecurityLevel::kAuthenticated);
RunUntilIdle();
ReceivePairingFeatures(IOCapability::kKeyboardOnly);
RunUntilIdle();
first_pairing_cb(true);
RunUntilIdle();
// The callback from the `Abort`ed pairing should be ignored, while calling
// `respond`, which is associated with the active pairing, should cause the
// expected Pairing Confirm to be sent.
EXPECT_EQ(0, pairing_confirm_count());
ASSERT_TRUE(respond);
respond(true);
RunUntilIdle();
EXPECT_EQ(1, pairing_confirm_count());
}
TEST_F(InitiatorPairingTest, IgnoresExpiredPasskeyEntryInputCallback) {
SetUpSecurityManager(IOCapability::kKeyboardOnly);
PasskeyResponseCallback passkey_cb = nullptr;
set_request_passkey_delegate(
[&](PasskeyResponseCallback cb) { passkey_cb = std::move(cb); });
// Must request MITM to test PasskeyEntryInput instead of JustWorks pairing
UpgradeSecurity(SecurityLevel::kAuthenticated);
RunUntilIdle();
ReceivePairingFeatures(IOCapability::kDisplayOnly);
RunUntilIdle();
ASSERT_TRUE(passkey_cb);
PasskeyResponseCallback first_pairing_cb = std::move(passkey_cb);
pairing()->Abort();
RunUntilIdle();
EXPECT_EQ(1, pairing_failed_count());
// We reset the respond variable so we can "catch" the next PairingDelegate
// request in the same variable (the `set_display_delegate` callback still has
// the reference to `respond`)
passkey_cb = nullptr;
// Start a separate pairing from the one captured in `first_pairing_cb`, which
// was `Abort`ed
UpgradeSecurity(SecurityLevel::kAuthenticated);
RunUntilIdle();
ReceivePairingFeatures(IOCapability::kDisplayOnly);
RunUntilIdle();
const int32_t kGenericPositive6DigitNumber = 123456;
first_pairing_cb(kGenericPositive6DigitNumber);
RunUntilIdle();
// The callback from the `Abort`ed pairing should be ignored, while calling
// `respond`, which is associated with the active pairing, should cause the
// expected Pairing Confirm to be sent.
EXPECT_EQ(0, pairing_confirm_count());
ASSERT_TRUE(passkey_cb);
passkey_cb(kGenericPositive6DigitNumber);
RunUntilIdle();
EXPECT_EQ(1, pairing_confirm_count());
}
// The TK delegate is called with the correct pairing method and the TK is
// factored into the confirm value generation.
TEST_F(InitiatorPairingTest, LegacyPhase2ConfirmValuesExchangedWithUserTK) {
std::optional<uint32_t> tk = std::nullopt;
auto method = Delegate::DisplayMethod::kComparison;
ConfirmCallback respond;
set_display_delegate([&](uint32_t passkey,
Delegate::DisplayMethod cb_method,
ConfirmCallback cb_rsp) {
tk = passkey;
method = cb_method;
respond = std::move(cb_rsp);
});
UpgradeSecurity(SecurityLevel::kEncrypted);
RunUntilIdle();
// Pick I/O capabilities and MITM flags that will result in Passkey Entry
// pairing.
ReceivePairingFeatures(IOCapability::kKeyboardOnly, AuthReq::kMITM);
RunUntilIdle();
ASSERT_TRUE(tk.has_value());
// DisplayMethod should be kPeerEntry, as Comparison is only for Secure
// Connections, not Legacy.
ASSERT_EQ(Delegate::DisplayMethod::kPeerEntry, method);
// Notify that TK was displayed.
respond(true);
RunUntilIdle();
// Should have received Mconfirm.
EXPECT_EQ(1, pairing_confirm_count());
EXPECT_EQ(0, pairing_random_count());
EXPECT_EQ(0, security_callback_count());
// Receive Sconfirm and Srand values that match.
UInt128 confirm, random;
GenerateMatchingLegacyConfirmAndRandom(&confirm, &random, *tk);
ReceivePairingConfirm(confirm);
RunUntilIdle();
// Should have received Mrand.
EXPECT_EQ(1, pairing_confirm_count());
EXPECT_EQ(1, pairing_random_count());
EXPECT_EQ(0, security_callback_count());
// Our Mconfirm/Mrand should be correct.
UInt128 expected_confirm;
GenerateLegacyConfirmValue(
pairing_random(), &expected_confirm, /*peer_initiator=*/false, *tk);
EXPECT_EQ(expected_confirm, pairing_confirm());
// Send Srandom.
ReceivePairingRandom(random);
RunUntilIdle();
EXPECT_EQ(1, pairing_confirm_count());
EXPECT_EQ(1, pairing_random_count());
EXPECT_EQ(0, pairing_failed_count());
EXPECT_EQ(0, security_callback_count());
}
// Peer aborts during Phase 2.
TEST_F(InitiatorPairingTest, PairingFailedInPhase2) {
UpgradeSecurity(SecurityLevel::kEncrypted);
ReceivePairingFeatures();
RunUntilIdle();
UInt128 confirm, random;
GenerateMatchingLegacyConfirmAndRandom(&confirm, &random);
ReceivePairingConfirm(confirm);
RunUntilIdle();
EXPECT_EQ(1, pairing_confirm_count());
EXPECT_EQ(1, pairing_random_count());
EXPECT_EQ(0, pairing_failed_count());
EXPECT_EQ(0, security_callback_count());
ReceivePairingFailed(ErrorCode::kConfirmValueFailed);
RunUntilIdle();
EXPECT_EQ(1, pairing_confirm_count());
EXPECT_EQ(1, pairing_random_count());
EXPECT_EQ(0, pairing_failed_count());
EXPECT_EQ(1, security_callback_count());
EXPECT_EQ(ToResult(ErrorCode::kConfirmValueFailed), security_status());
}
// Encryption with STK fails.
TEST_F(InitiatorPairingTest, EncryptionWithSTKFails) {
UInt128 stk;
FastForwardToSTK(&stk);
ASSERT_TRUE(fake_link()->ltk());
EXPECT_EQ(stk, fake_link()->ltk()->value());
EXPECT_EQ(0u, fake_link()->ltk()->ediv());
EXPECT_EQ(0u, fake_link()->ltk()->rand());
// The host should have requested encryption.
EXPECT_EQ(SecurityProperties(), pairing()->security());
EXPECT_EQ(1, fake_link()->start_encryption_count());
fake_link()->TriggerEncryptionChangeCallback(
ToResult(pw::bluetooth::emboss::StatusCode::PIN_OR_KEY_MISSING)
.take_error());
RunUntilIdle();
EXPECT_EQ(1, pairing_failed_count());
EXPECT_EQ(1, security_callback_count());
EXPECT_EQ(1, auth_failure_callback_count());
EXPECT_EQ(ToResult(ErrorCode::kUnspecifiedReason), security_status());
EXPECT_EQ(ErrorCode::kUnspecifiedReason, received_error_code());
EXPECT_EQ(ToResult(pw::bluetooth::emboss::StatusCode::PIN_OR_KEY_MISSING),
auth_failure_status());
// No security property update should have been sent since the security
// properties have not changed.
EXPECT_EQ(0, new_sec_props_count());
EXPECT_EQ(SecurityProperties(), pairing()->security());
}
TEST_F(InitiatorPairingTest, EncryptionDisabledInPhase2) {
UInt128 stk;
FastForwardToSTK(&stk);
ASSERT_TRUE(fake_link()->ltk());
EXPECT_EQ(stk, fake_link()->ltk()->value());
EXPECT_EQ(0u, fake_link()->ltk()->ediv());
EXPECT_EQ(0u, fake_link()->ltk()->rand());
// The host should have requested encryption.
EXPECT_EQ(1, fake_link()->start_encryption_count());
EXPECT_EQ(SecurityProperties(), pairing()->security());
fake_link()->TriggerEncryptionChangeCallback(fit::ok(/*enabled=*/false));
RunUntilIdle();
EXPECT_EQ(1, pairing_failed_count());
EXPECT_EQ(1, security_callback_count());
EXPECT_EQ(0, auth_failure_callback_count());
EXPECT_EQ(ToResult(ErrorCode::kUnspecifiedReason), security_status());
EXPECT_EQ(ErrorCode::kUnspecifiedReason, received_error_code());
// No security property update should have been sent since the security
// properties have not changed.
EXPECT_EQ(0, new_sec_props_count());
EXPECT_EQ(SecurityProperties(), pairing()->security());
}
// Tests that the STK is generated according to the max length provided
TEST_F(InitiatorPairingTest, StkLengthGeneration) {
UInt128 stk;
uint8_t max_key_size = 10;
FastForwardToSTK(&stk, SecurityLevel::kEncrypted, 0, 0, max_key_size);
// At this stage, the stk is stored here
ASSERT_TRUE(fake_link()->ltk());
// Ensure that most significant (16 - max_key_size) bytes are zero. The key
// should be generated up to the max_key_size.
for (auto i = max_key_size; i < fake_link()->ltk()->value().size(); i++) {
EXPECT_TRUE(fake_link()->ltk()->value()[i] == 0);
}
}
// Tests that the pairing procedure ends after encryption with the STK if there
// are no keys to distribute, and that no keys are notified for Legacy pairing
// in this case.
TEST_F(InitiatorPairingTest, LegacyPhase3CompleteWithoutKeyExchange) {
UInt128 stk;
FastForwardToSTK(&stk);
ASSERT_TRUE(fake_link()->ltk());
EXPECT_EQ(stk, fake_link()->ltk()->value());
EXPECT_EQ(0u, fake_link()->ltk()->ediv());
EXPECT_EQ(0u, fake_link()->ltk()->rand());
// The host should have requested encryption.
EXPECT_EQ(1, fake_link()->start_encryption_count());
fake_link()->TriggerEncryptionChangeCallback(fit::ok(/*enabled=*/true));
RunUntilIdle();
// Pairing should succeed without any pairing data.
EXPECT_EQ(1, pairing_data_callback_count());
EXPECT_FALSE(peer_ltk());
EXPECT_FALSE(irk());
EXPECT_FALSE(identity());
EXPECT_FALSE(csrk());
// Should have been called at least once to determine local identity
// availability.
EXPECT_NE(0, local_id_info_callback_count());
EXPECT_EQ(0, pairing_failed_count());
EXPECT_EQ(1, security_callback_count());
EXPECT_EQ(1, pairing_complete_count());
EXPECT_EQ(0, id_info_count());
EXPECT_EQ(0, id_addr_info_count());
EXPECT_EQ(fit::ok(), security_status());
EXPECT_EQ(security_status(), pairing_complete_status());
EXPECT_EQ(SecurityLevel::kEncrypted, sec_props().level());
EXPECT_EQ(16u, sec_props().enc_key_size());
EXPECT_FALSE(sec_props().secure_connections());
// The security properties should have been updated to match the STK.
EXPECT_EQ(1, new_sec_props_count());
EXPECT_EQ(sec_props(), pairing()->security());
ASSERT_TRUE(fake_link()->ltk());
}
// Tests that for Secure Connections, the pairing procedure ends after
// encryption with the LTK if there are no keys to distribute, and that the LTK
// is notified.
TEST_F(InitiatorPairingTest, ScPhase3CompleteWithoutKeyExchange) {
UInt128 ltk_bytes;
const SecurityProperties kExpectedSecurity(SecurityLevel::kEncrypted,
kMaxEncryptionKeySize,
/*secure_connections=*/true);
FastForwardToPhase3(&ltk_bytes,
/*secure_connections=*/true,
kExpectedSecurity.level(),
KeyDistGenField{0},
KeyDistGenField{0});
const LTK kExpectedLtk(kExpectedSecurity, hci_spec::LinkKey(ltk_bytes, 0, 0));
ASSERT_TRUE(fake_link()->ltk());
EXPECT_EQ(kExpectedLtk.key(), fake_link()->ltk());
// Pairing should succeed with the LTK as the SC pairing is bondable, even
// though no keys need to be distributed in Phase 3.
EXPECT_EQ(1, pairing_data_callback_count());
EXPECT_TRUE(peer_ltk().has_value());
EXPECT_EQ(kExpectedLtk, peer_ltk());
EXPECT_EQ(peer_ltk(), local_ltk());
EXPECT_FALSE(irk());
EXPECT_FALSE(identity());
EXPECT_FALSE(csrk());
// Should have been called at least once to determine local identity
// availability.
EXPECT_NE(0, local_id_info_callback_count());
EXPECT_EQ(0, pairing_failed_count());
EXPECT_EQ(1, security_callback_count());
EXPECT_EQ(1, pairing_complete_count());
EXPECT_EQ(0, id_info_count());
EXPECT_EQ(0, id_addr_info_count());
EXPECT_EQ(fit::ok(), security_status());
EXPECT_EQ(security_status(), pairing_complete_status());
EXPECT_EQ(kExpectedSecurity, sec_props());
// The security properties should have been updated to match the LTK.
EXPECT_EQ(1, new_sec_props_count());
EXPECT_EQ(sec_props(), pairing()->security());
ASSERT_TRUE(fake_link()->ltk());
}
// Tests that Secure Connections ignores the EncKey bit in the key distribution
// field.
TEST_F(InitiatorPairingTest, ScPhase3EncKeyBitSetNotDistributed) {
UInt128 ltk_bytes;
const SecurityProperties kExpectedSecurity(SecurityLevel::kEncrypted,
kMaxEncryptionKeySize,
/*secure_connections=*/true);
// We will request the EncKey from the peer and the peer will respond that it
// is capable of sending it, but as this is SC pairing that should not occur.
KeyDistGenField remote_keys{KeyDistGen::kEncKey}, local_keys{0};
FastForwardToScLtk(&ltk_bytes,
kExpectedSecurity.level(),
remote_keys,
local_keys,
BondableMode::Bondable);
const LTK kExpectedLtk(kExpectedSecurity, hci_spec::LinkKey(ltk_bytes, 0, 0));
ASSERT_TRUE(fake_link()->ltk());
EXPECT_EQ(kExpectedLtk.key(), fake_link()->ltk());
// The host should have requested encryption.
EXPECT_EQ(1, fake_link()->start_encryption_count());
fake_link()->TriggerEncryptionChangeCallback(fit::ok(/*enabled=*/true));
RunUntilIdle();
// Pairing should succeed without any messages being sent in "Phase 3". The
// LTK was generated in SC Phase 2, and as the pairing is bondable, it is
// included in the callback.
EXPECT_EQ(1, pairing_data_callback_count());
EXPECT_TRUE(peer_ltk().has_value());
EXPECT_EQ(kExpectedLtk, peer_ltk());
EXPECT_FALSE(irk());
EXPECT_FALSE(identity());
EXPECT_FALSE(csrk());
// Should have been called at least once to determine local identity
// availability.
EXPECT_NE(0, local_id_info_callback_count());
EXPECT_EQ(0, pairing_failed_count());
EXPECT_EQ(1, security_callback_count());
EXPECT_EQ(1, pairing_complete_count());
EXPECT_EQ(0, id_info_count());
EXPECT_EQ(0, id_addr_info_count());
EXPECT_EQ(fit::ok(), security_status());
EXPECT_EQ(security_status(), pairing_complete_status());
EXPECT_EQ(kExpectedSecurity, sec_props());
// The security properties should have been updated to match the LTK.
EXPECT_EQ(1, new_sec_props_count());
EXPECT_EQ(sec_props(), pairing()->security());
ASSERT_TRUE(fake_link()->ltk());
}
// Tests that for Secure Connections non-bondable mode, the pairing procedure
// ends after encryption with the key generated in Phase 2, but the upper layers
// are not notified of that key as an LTK.
TEST_F(InitiatorPairingTest, ScPhase3NonBondableCompleteWithoutKeyExchange) {
// Must have DisplayYesNo IOC to generate Authenticated security per
// kExpectedSecurity
SetUpSecurityManager(IOCapability::kDisplayYesNo);
const SecurityProperties kExpectedSecurity(SecurityLevel::kAuthenticated,
kMaxEncryptionKeySize,
/*secure_connections=*/true);
UInt128 ltk_bytes;
FastForwardToScLtk(&ltk_bytes,
kExpectedSecurity.level(),
KeyDistGenField{0},
KeyDistGenField{0},
BondableMode::NonBondable);
const hci_spec::LinkKey kExpectedLinkKey(ltk_bytes, 0, 0);
ASSERT_TRUE(fake_link()->ltk());
EXPECT_EQ(kExpectedLinkKey, fake_link()->ltk());
// The host should have requested encryption.
EXPECT_EQ(1, fake_link()->start_encryption_count());
fake_link()->TriggerEncryptionChangeCallback(fit::ok(/*enabled=*/true));
RunUntilIdle();
// Pairing should succeed with the LTK as we are in SC, but as the pairing is
// non-bondable, no LTK should be relayed up to the delegate.
EXPECT_EQ(0, pairing_data_callback_count());
EXPECT_EQ(0, pairing_failed_count());
EXPECT_EQ(1, security_callback_count());
EXPECT_EQ(1, pairing_complete_count());
EXPECT_EQ(0, id_info_count());
EXPECT_EQ(0, id_addr_info_count());
EXPECT_EQ(fit::ok(), security_status());
EXPECT_EQ(security_status(), pairing_complete_status());
EXPECT_EQ(kExpectedSecurity, sec_props());
// The security properties should have been updated to match the LTK.
EXPECT_EQ(1, new_sec_props_count());
EXPECT_EQ(sec_props(), pairing()->security());
ASSERT_TRUE(fake_link()->ltk());
}
TEST_F(InitiatorPairingTest, Phase3EncryptionInformationReceivedTwice) {
UInt128 stk;
FastForwardToPhase3(&stk,
/*secure_connections=*/false,
SecurityLevel::kEncrypted,
KeyDistGen::kEncKey);
// Pairing should still be in progress.
EXPECT_EQ(0, pairing_failed_count());
EXPECT_EQ(0, security_callback_count());
EXPECT_EQ(0, pairing_data_callback_count());
ReceiveEncryptionInformation(UInt128());
RunUntilIdle();
// Waiting for EDIV and Rand
EXPECT_EQ(0, pairing_failed_count());
EXPECT_EQ(0, security_callback_count());
// Send the LTK twice. This should cause pairing to fail.
ReceiveEncryptionInformation(UInt128());
RunUntilIdle();
EXPECT_EQ(1, pairing_failed_count());
EXPECT_EQ(1, security_callback_count());
EXPECT_EQ(1, pairing_complete_count());
EXPECT_EQ(ToResult(ErrorCode::kUnspecifiedReason), security_status());
EXPECT_EQ(ErrorCode::kUnspecifiedReason, received_error_code());
EXPECT_EQ(security_status(), pairing_complete_status());
}
// The responder sends EDIV and Rand before LTK.
TEST_F(InitiatorPairingTest, Phase3CentralIdentificationReceivedInWrongOrder) {
UInt128 stk;
FastForwardToPhase3(&stk,
/*secure_connections=*/false,
SecurityLevel::kEncrypted,
KeyDistGen::kEncKey);
// Pairing should still be in progress.
EXPECT_EQ(0, pairing_failed_count());
EXPECT_EQ(0, security_callback_count());
EXPECT_EQ(0, pairing_data_callback_count());
// Send central identification before encryption information. This should
// cause pairing to fail.
ReceiveCentralIdentification(1, 2);
RunUntilIdle();
EXPECT_EQ(1, pairing_failed_count());
EXPECT_EQ(1, security_callback_count());
EXPECT_EQ(1, pairing_complete_count());
EXPECT_EQ(ToResult(ErrorCode::kUnspecifiedReason), security_status());
EXPECT_EQ(ErrorCode::kUnspecifiedReason, received_error_code());
EXPECT_EQ(security_status(), pairing_complete_status());
}
// The responder sends the sample LTK from the specification doc
TEST_F(InitiatorPairingTest, Phase3CentralIdentificationReceiveSampleLTK) {
UInt128 stk;
FastForwardToPhase3(&stk,
/*secure_connections=*/false,
SecurityLevel::kEncrypted,
KeyDistGen::kEncKey);
const UInt128 kLtkSample{{0xBF,
0x01,
0xFB,
0x9D,
0x4E,
0xF3,
0xBC,
0x36,
0xD8,
0x74,
0xF5,
0x39,
0x41,
0x38,
0x68,
0x4C}};
// Pairing should still be in progress.
EXPECT_EQ(0, pairing_failed_count());
EXPECT_EQ(0, security_callback_count());
EXPECT_EQ(0, pairing_data_callback_count());
// Send a bad LTK, this should cause pairing to fail.
ReceiveEncryptionInformation(kLtkSample);
RunUntilIdle();
EXPECT_EQ(1, pairing_failed_count());
EXPECT_EQ(1, security_callback_count());
EXPECT_EQ(1, pairing_complete_count());
EXPECT_EQ(ToResult(ErrorCode::kUnspecifiedReason), security_status());
EXPECT_EQ(ErrorCode::kUnspecifiedReason, received_error_code());
EXPECT_EQ(security_status(), pairing_complete_status());
}
// The responder sends the sample Rand from the specification doc
TEST_F(InitiatorPairingTest, Phase3CentralIdentificationReceiveExampleRand) {
UInt128 stk;
FastForwardToPhase3(&stk,
/*secure_connections=*/false,
SecurityLevel::kEncrypted,
KeyDistGen::kEncKey);
uint64_t kRandSample = 0xABCDEF1234567890;
uint16_t kEDiv = 20;
// Pairing should still be in progress.
EXPECT_EQ(0, pairing_failed_count());
EXPECT_EQ(0, security_callback_count());
EXPECT_EQ(0, pairing_data_callback_count());
// Send a bad Rand, this should cause pairing to fail.
ReceiveEncryptionInformation(UInt128());
ReceiveCentralIdentification(kRandSample, kEDiv);
RunUntilIdle();
EXPECT_EQ(1, pairing_failed_count());
EXPECT_EQ(1, security_callback_count());
EXPECT_EQ(1, pairing_complete_count());
EXPECT_EQ(ToResult(ErrorCode::kUnspecifiedReason), security_status());
EXPECT_EQ(ErrorCode::kUnspecifiedReason, received_error_code());
EXPECT_EQ(security_status(), pairing_complete_status());
}
// The responder sends an LTK that is longer than the max key size
TEST_F(InitiatorPairingTest, Phase3CentralIdentificationReceiveLongLTK) {
UInt128 stk;
auto max_key_size = 8;
FastForwardToPhase3(&stk,
/*secure_connections=*/false,
SecurityLevel::kEncrypted,
KeyDistGen::kEncKey,
0,
max_key_size);
const UInt128 kLtk{{1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8}};
// Pairing should still be in progress.
EXPECT_EQ(0, pairing_failed_count());
EXPECT_EQ(0, security_callback_count());
EXPECT_EQ(0, pairing_data_callback_count());
// Send a long LTK, this should cause pairing to fail.
ReceiveEncryptionInformation(kLtk);
RunUntilIdle();
EXPECT_EQ(1, pairing_failed_count());
EXPECT_EQ(1, security_callback_count());
EXPECT_EQ(1, pairing_complete_count());
EXPECT_EQ(ToResult(ErrorCode::kInvalidParameters), security_status());
EXPECT_EQ(ErrorCode::kInvalidParameters, received_error_code());
EXPECT_EQ(security_status(), pairing_complete_status());
}
TEST_F(InitiatorPairingTest, Phase3CentralIdentificationReceivedTwice) {
UInt128 stk;
FastForwardToPhase3(&stk,
/*secure_connections=*/false,
SecurityLevel::kEncrypted,
KeyDistGen::kEncKey);
// Pairing should still be in progress.
EXPECT_EQ(0, pairing_failed_count());
EXPECT_EQ(0, security_callback_count());
EXPECT_EQ(0, pairing_data_callback_count());
constexpr uint16_t kEdiv = 1;
constexpr uint64_t kRand = 2;
constexpr uint16_t kDupEdiv = 3;
constexpr uint64_t kDupRand = 4;
// Send duplicate central identification. Pairing should complete with the
// first set of information. The second set should get ignored.
ReceiveEncryptionInformation(UInt128());
ReceiveCentralIdentification(kRand, kEdiv);
ReceiveCentralIdentification(kDupRand, kDupEdiv);
RunUntilIdle();
EXPECT_EQ(0, pairing_failed_count());
EXPECT_EQ(1, security_callback_count());
EXPECT_EQ(1, pairing_complete_count());
EXPECT_EQ(1, pairing_data_callback_count());
EXPECT_EQ(fit::ok(), security_status());
EXPECT_EQ(security_status(), pairing_complete_status());
ASSERT_TRUE(pairing_data().peer_ltk.has_value());
EXPECT_EQ(kEdiv, pairing_data().peer_ltk->key().ediv());
EXPECT_EQ(kRand, pairing_data().peer_ltk->key().rand());
}
// Pairing completes after obtaining peer encryption information only.
TEST_F(InitiatorPairingTest, Phase3CompleteWithReceivingEncKey) {
UInt128 stk;
FastForwardToPhase3(&stk,
/*secure_connections=*/false,
SecurityLevel::kEncrypted,
KeyDistGen::kEncKey);
const UInt128 kLTK{{1, 2, 3, 4, 5, 6, 7, 8, 7, 6, 5, 4, 3, 2, 1, 0}};
uint64_t kRand = 5;
uint16_t kEDiv = 20;
ReceiveEncryptionInformation(kLTK);
ReceiveCentralIdentification(kRand, kEDiv);
RunUntilIdle();
// Pairing should have succeeded.
EXPECT_EQ(0, pairing_failed_count());
EXPECT_EQ(1, security_callback_count());
EXPECT_EQ(1, pairing_complete_count());
EXPECT_EQ(fit::ok(), security_status());
EXPECT_EQ(security_status(), pairing_complete_status());
// LTK should have been assigned to the link.
ASSERT_TRUE(fake_link()->ltk());
EXPECT_EQ(kLTK, fake_link()->ltk()->value());
EXPECT_EQ(kRand, fake_link()->ltk()->rand());
EXPECT_EQ(kEDiv, fake_link()->ltk()->ediv());
// We don't re-encrypt with the LTK while the link is already authenticated
// with the STK.
EXPECT_EQ(1, fake_link()->start_encryption_count());
EXPECT_EQ(SecurityLevel::kEncrypted, sec_props().level());
EXPECT_EQ(16u, sec_props().enc_key_size());
EXPECT_FALSE(sec_props().secure_connections());
// Should have been called at least once to determine local identity
// availability.
EXPECT_NE(0, local_id_info_callback_count());
// Local identity information should not have been distributed by us since it
// isn't available.
EXPECT_EQ(0, id_info_count());
EXPECT_EQ(0, id_addr_info_count());
// Should have notified the LTK.
EXPECT_EQ(1, pairing_data_callback_count());
ASSERT_TRUE(peer_ltk());
ASSERT_FALSE(irk());
ASSERT_FALSE(identity());
ASSERT_FALSE(csrk());
EXPECT_EQ(sec_props(), peer_ltk()->security());
EXPECT_EQ(kLTK, peer_ltk()->key().value());
EXPECT_EQ(kRand, peer_ltk()->key().rand());
EXPECT_EQ(kEDiv, peer_ltk()->key().ediv());
// No security property update should have been sent for the LTK. This is
// because the LTK and the STK are expected to have the same properties.
EXPECT_EQ(1, new_sec_props_count());
}
TEST_F(InitiatorPairingTest, Phase3CompleteWithSendingEncKey) {
UInt128 stk;
KeyDistGenField remote_keys{0u}, local_keys{KeyDistGen::kEncKey};
FastForwardToPhase3(&stk,
/*secure_connections=*/false,
SecurityLevel::kEncrypted,
remote_keys,
local_keys);
RunUntilIdle();
// Pairing should have succeeded.
EXPECT_EQ(0, pairing_failed_count());
EXPECT_EQ(1, security_callback_count());
EXPECT_EQ(1, pairing_complete_count());
EXPECT_EQ(fit::ok(), security_status());
EXPECT_EQ(security_status(), pairing_complete_status());
// Only the STK should be assigned to the link, as the distributed LTK was
// initiator-generated. This means it can only be used to encrypt future
// connections where the roles are reversed.
EXPECT_EQ(stk, fake_link()->ltk()->value());
EXPECT_EQ(1, fake_link()->start_encryption_count());
// Should have been called at least once to determine local identity
// availability.
EXPECT_NE(0, local_id_info_callback_count());
// Should have notified pairing data callback with the LTK.
EXPECT_EQ(1, pairing_data_callback_count());
ASSERT_TRUE(local_ltk());
// LTK sent OTA should match what we notified the pairing data callback with.
EXPECT_EQ(local_ltk()->key(), hci_spec::LinkKey(enc_info(), rand(), ediv()));
}
// Pairing completes after obtaining short encryption information only.
TEST_F(InitiatorPairingTest, Phase3CompleteWithShortEncKey) {
UInt128 stk;
uint8_t max_key_size = 12;
FastForwardToPhase3(&stk,
/*secure_connections=*/false,
SecurityLevel::kEncrypted,
KeyDistGen::kEncKey,
0u,
max_key_size);
// This LTK is within the max_key_size specified above.
const UInt128 kLTK{{1, 2, 3, 4, 5, 6, 7, 8, 7, 6, 5, 4, 0, 0, 0, 0}};
uint64_t kRand = 5;
uint16_t kEDiv = 20;
ReceiveEncryptionInformation(kLTK);
ReceiveCentralIdentification(kRand, kEDiv);
RunUntilIdle();
// Pairing should have succeeded.
EXPECT_EQ(0, pairing_failed_count());
EXPECT_EQ(1, security_callback_count());
EXPECT_EQ(1, pairing_complete_count());
EXPECT_EQ(fit::ok(), security_status());
EXPECT_EQ(security_status(), pairing_complete_status());
// LTK should have been assigned to the link.
ASSERT_TRUE(fake_link()->ltk());
EXPECT_EQ(kLTK, fake_link()->ltk()->value());
EXPECT_EQ(kRand, fake_link()->ltk()->rand());
EXPECT_EQ(kEDiv, fake_link()->ltk()->ediv());
// We don't re-encrypt with the LTK while the link is already authenticated
// with the STK.
EXPECT_EQ(1, fake_link()->start_encryption_count());
EXPECT_EQ(SecurityLevel::kEncrypted, sec_props().level());
EXPECT_EQ(max_key_size, sec_props().enc_key_size());
EXPECT_FALSE(sec_props().secure_connections());
// Should have been called at least once to determine local identity
// availability.
EXPECT_NE(0, local_id_info_callback_count());
// Local identity information should not have been distributed by us since it
// isn't available.
EXPECT_EQ(0, id_info_count());
EXPECT_EQ(0, id_addr_info_count());
// Should have notified the LTK.
EXPECT_EQ(1, pairing_data_callback_count());
ASSERT_TRUE(peer_ltk());
ASSERT_FALSE(irk());
ASSERT_FALSE(identity());
ASSERT_FALSE(csrk());
EXPECT_EQ(sec_props(), peer_ltk()->security());
EXPECT_EQ(kLTK, peer_ltk()->key().value());
EXPECT_EQ(kRand, peer_ltk()->key().rand());
EXPECT_EQ(kEDiv, peer_ltk()->key().ediv());
// No security property update should have been sent for the LTK. This is
// because the LTK and the STK are expected to have the same properties.
EXPECT_EQ(1, new_sec_props_count());
}
TEST_F(InitiatorPairingTest, Phase3WithLocalIdKey) {
IdentityInfo local_id_info;
local_id_info.irk = UInt128{{1, 2, 3, 4, 5, 6, 7, 8, 7, 6, 5, 4, 3, 2, 1, 0}};
local_id_info.address = kLocalAddr;
set_local_id_info(local_id_info);
UInt128 stk;
FastForwardToPhase3(&stk,
/*secure_connections=*/false,
SecurityLevel::kEncrypted,
0, // remote keys
KeyDistGen::kIdKey); // local keys
// Local identity information should have been sent.
EXPECT_EQ(1, id_info_count());
EXPECT_EQ(local_id_info.irk, id_info());
EXPECT_EQ(1, id_addr_info_count());
EXPECT_EQ(local_id_info.address, id_addr_info());
// Pairing should succeed without notifying any keys.
EXPECT_EQ(0, pairing_failed_count());
EXPECT_EQ(1, security_callback_count());
EXPECT_EQ(1, pairing_complete_count());
EXPECT_EQ(fit::ok(), security_status());
EXPECT_EQ(security_status(), pairing_complete_status());
}
// Tests that pairing results in an error if a local ID key was initially
// negotiated but gets removed before the distribution phase.
TEST_F(InitiatorPairingTest, Phase3IsAbortedIfLocalIdKeyIsRemoved) {
IdentityInfo local_id_info;
local_id_info.irk = UInt128{{1, 2, 3, 4, 5, 6, 7, 8, 7, 6, 5, 4, 3, 2, 1, 0}};
local_id_info.address = kLocalAddr;
set_local_id_info(local_id_info);
UInt128 stk;
FastForwardToSTK(&stk,
SecurityLevel::kEncrypted,
0, // remote keys
KeyDistGen::kIdKey); // local keys
// Local identity information should not have been sent yet.
EXPECT_EQ(0, id_info_count());
EXPECT_EQ(0, id_addr_info_count());
// Pairing still in progress.
EXPECT_EQ(0, pairing_failed_count());
EXPECT_EQ(0, security_callback_count());
EXPECT_EQ(0, pairing_complete_count());
// Remove the local identity information.
set_local_id_info(std::nullopt);
// Encrypt with the STK to finish phase 2.
fake_link()->TriggerEncryptionChangeCallback(fit::ok(/*enabled=*/true));
RunUntilIdle();
// Pairing should have been aborted.
EXPECT_EQ(0, id_info_count());
EXPECT_EQ(0, id_addr_info_count());
EXPECT_EQ(1, pairing_failed_count());
EXPECT_EQ(1, security_callback_count());
EXPECT_EQ(1, pairing_complete_count());
EXPECT_EQ(ToResult(ErrorCode::kUnspecifiedReason), security_status());
}
TEST_F(InitiatorPairingTest, Phase3IRKReceivedTwice) {
UInt128 stk;
FastForwardToPhase3(&stk,
/*secure_connections=*/false,
SecurityLevel::kEncrypted,
KeyDistGen::kIdKey);
// Pairing should still be in progress.
EXPECT_EQ(0, pairing_failed_count());
EXPECT_EQ(0, security_callback_count());
EXPECT_EQ(0, pairing_data_callback_count());
ReceiveIdentityResolvingKey(UInt128());
RunUntilIdle();
// Waiting for identity address.
EXPECT_EQ(0, pairing_failed_count());
EXPECT_EQ(0, security_callback_count());
EXPECT_EQ(0, pairing_complete_count());
// Send an IRK again. This should cause pairing to fail.
ReceiveIdentityResolvingKey(UInt128());
RunUntilIdle();
EXPECT_EQ(1, pairing_failed_count());
EXPECT_EQ(1, security_callback_count());
EXPECT_EQ(1, pairing_complete_count());
EXPECT_EQ(ToResult(ErrorCode::kUnspecifiedReason), security_status());
EXPECT_EQ(ErrorCode::kUnspecifiedReason, received_error_code());
EXPECT_EQ(security_status(), pairing_complete_status());
}
// The responder sends its identity address before sending its IRK.
TEST_F(InitiatorPairingTest, Phase3IdentityAddressReceivedInWrongOrder) {
UInt128 stk;
FastForwardToPhase3(&stk,
/*secure_connections=*/false,
SecurityLevel::kEncrypted,
KeyDistGen::kIdKey);
// Pairing should still be in progress.
EXPECT_EQ(0, pairing_failed_count());
EXPECT_EQ(0, security_callback_count());
EXPECT_EQ(0, pairing_data_callback_count());
EXPECT_EQ(0, pairing_complete_count());
// Send identity address before the IRK. This should cause pairing to fail.
ReceiveIdentityAddress(kPeerAddr);
RunUntilIdle();
EXPECT_EQ(1, pairing_failed_count());
EXPECT_EQ(1, security_callback_count());
EXPECT_EQ(1, pairing_complete_count());
EXPECT_EQ(ToResult(ErrorCode::kUnspecifiedReason), security_status());
EXPECT_EQ(ErrorCode::kUnspecifiedReason, received_error_code());
EXPECT_EQ(security_status(), pairing_complete_status());
}
TEST_F(InitiatorPairingTest, Phase3IdentityAddressReceivedTwice) {
UInt128 stk;
// Request enc key to prevent pairing from completing after sending the first
// identity address.
FastForwardToPhase3(&stk,
/*secure_connections=*/false,
SecurityLevel::kEncrypted,
KeyDistGen::kEncKey | KeyDistGen::kIdKey);
// Pairing should still be in progress.
EXPECT_EQ(0, pairing_failed_count());
EXPECT_EQ(0, security_callback_count());
EXPECT_EQ(0, pairing_data_callback_count());
EXPECT_EQ(0, pairing_complete_count());
ReceiveIdentityResolvingKey(UInt128());
ReceiveIdentityAddress(kPeerAddr);
ReceiveIdentityAddress(kPeerAddr);
RunUntilIdle();
EXPECT_EQ(1, pairing_failed_count());
EXPECT_EQ(1, security_callback_count());
EXPECT_EQ(1, pairing_complete_count());
EXPECT_EQ(ToResult(ErrorCode::kUnspecifiedReason), security_status());
EXPECT_EQ(ErrorCode::kUnspecifiedReason, received_error_code());
EXPECT_EQ(security_status(), pairing_complete_status());
}
// Pairing completes after obtaining identity information only.
TEST_F(InitiatorPairingTest, Phase3CompleteWithIdKey) {
UInt128 stk;
FastForwardToPhase3(&stk,
/*secure_connections=*/false,
SecurityLevel::kEncrypted,
KeyDistGen::kIdKey);
// Pairing should still be in progress.
EXPECT_EQ(0, pairing_failed_count());
EXPECT_EQ(0, security_callback_count());
EXPECT_EQ(0, pairing_data_callback_count());
EXPECT_EQ(0, pairing_complete_count());
const UInt128 kIRK{{1, 2, 3, 4, 5, 6, 7, 8, 7, 6, 5, 4, 3, 2, 1, 0}};
ReceiveIdentityResolvingKey(kIRK);
ReceiveIdentityAddress(kPeerAddr);
RunUntilIdle();
EXPECT_EQ(0, pairing_failed_count());
EXPECT_EQ(1, security_callback_count());
EXPECT_EQ(1, pairing_complete_count());
EXPECT_EQ(fit::ok(), security_status());
EXPECT_EQ(security_status(), pairing_complete_status());
// The link remains encrypted with the STK.
EXPECT_EQ(SecurityLevel::kEncrypted, sec_props().level());
EXPECT_EQ(16u, sec_props().enc_key_size());
EXPECT_FALSE(sec_props().secure_connections());
EXPECT_EQ(1, pairing_data_callback_count());
ASSERT_FALSE(peer_ltk());
ASSERT_TRUE(irk());
ASSERT_TRUE(identity());
ASSERT_FALSE(csrk());
EXPECT_EQ(sec_props(), irk()->security());
EXPECT_EQ(kIRK, irk()->value());
EXPECT_EQ(kPeerAddr, *identity());
}
TEST_F(InitiatorPairingTest, Phase3CompleteWithAllKeys) {
UInt128 stk;
FastForwardToPhase3(&stk,
/*secure_connections=*/false,
SecurityLevel::kEncrypted,
KeyDistGen::kEncKey | KeyDistGen::kIdKey);
const UInt128 kLTK{{1, 2, 3, 4, 5, 6, 7, 8, 7, 6, 5, 4, 3, 2, 1, 0}};
const UInt128 kIRK{{8, 7, 6, 5, 4, 3, 2, 1, 1, 2, 3, 4, 5, 6, 7, 8}};
uint64_t kRand = 5;
uint16_t kEDiv = 20;
// The link should be assigned the STK as its link key.
EXPECT_EQ(stk, fake_link()->ltk()->value());
// Receive EncKey
ReceiveEncryptionInformation(kLTK);
ReceiveCentralIdentification(kRand, kEDiv);
RunUntilIdle();
// Pairing still pending. SMP does not assign the LTK to the link until
// pairing completes.
EXPECT_EQ(0, pairing_failed_count());
EXPECT_EQ(0, security_callback_count());
EXPECT_EQ(0, pairing_complete_count());
// Receive IdKey
ReceiveIdentityResolvingKey(kIRK);
ReceiveIdentityAddress(kPeerAddr);
RunUntilIdle();
// Pairing should have succeeded
EXPECT_EQ(0, pairing_failed_count());
EXPECT_EQ(1, security_callback_count());
EXPECT_EQ(1, pairing_complete_count());
EXPECT_EQ(fit::ok(), security_status());
EXPECT_EQ(security_status(), pairing_complete_status());
// LTK should have been assigned to the link.
ASSERT_TRUE(fake_link()->ltk());
EXPECT_EQ(kLTK, fake_link()->ltk()->value());
EXPECT_EQ(kRand, fake_link()->ltk()->rand());
EXPECT_EQ(kEDiv, fake_link()->ltk()->ediv());
// We don't re-encrypt with the LTK while the link is already authenticated
// with the STK.
EXPECT_EQ(1, fake_link()->start_encryption_count());
EXPECT_EQ(SecurityLevel::kEncrypted, sec_props().level());
EXPECT_EQ(16u, sec_props().enc_key_size());
EXPECT_FALSE(sec_props().secure_connections());
// Should have notified the LTK.
EXPECT_EQ(1, pairing_data_callback_count());
ASSERT_TRUE(peer_ltk());
ASSERT_TRUE(irk());
ASSERT_TRUE(identity());
ASSERT_FALSE(csrk());
EXPECT_EQ(sec_props(), peer_ltk()->security());
EXPECT_EQ(kLTK, peer_ltk()->key().value());
EXPECT_EQ(kRand, peer_ltk()->key().rand());
EXPECT_EQ(kEDiv, peer_ltk()->key().ediv());
EXPECT_EQ(sec_props(), irk()->security());
EXPECT_EQ(kIRK, irk()->value());
EXPECT_EQ(kPeerAddr, *identity());
}
TEST_F(InitiatorPairingTest, GenerateCrossTransportLinkKey) {
UInt128 stk;
// Indicate support for SC and for link keys in both directions to enable
// CTKG.
FastForwardToPhase3(&stk,
/*secure_connections=*/true,
SecurityLevel::kEncrypted,
KeyDistGen::kLinkKey,
KeyDistGen::kLinkKey);
RunUntilIdle();
// Pairing should have succeeded
EXPECT_EQ(0, pairing_failed_count());
EXPECT_EQ(1, security_callback_count());
EXPECT_EQ(1, pairing_complete_count());
EXPECT_EQ(fit::ok(), security_status());
EXPECT_EQ(security_status(), pairing_complete_status());
// The PairingData should contain the CTKGenerated BR/EDR link key.
EXPECT_TRUE(pairing_data().cross_transport_key.has_value());
}
TEST_F(InitiatorPairingTest, AssignLongTermKeyFailsDuringPairing) {
UpgradeSecurity(SecurityLevel::kEncrypted); // Initiate pairing.
SecurityProperties sec_props(
SecurityLevel::kAuthenticated, 16, /*secure_connections=*/false);
EXPECT_FALSE(
pairing()->AssignLongTermKey(LTK(sec_props, hci_spec::LinkKey())));
EXPECT_EQ(0, fake_link()->start_encryption_count());
EXPECT_EQ(SecurityLevel::kNoSecurity, pairing()->security().level());
}
TEST_F(InitiatorPairingTest, AssignLongTermKey) {
SecurityProperties sec_props(
SecurityLevel::kAuthenticated, 16, /*secure_connections=*/false);
LTK ltk(sec_props, hci_spec::LinkKey());
EXPECT_TRUE(pairing()->AssignLongTermKey(ltk));
EXPECT_EQ(1, fake_link()->start_encryption_count());
ASSERT_TRUE(fake_link()->ltk());
EXPECT_EQ(ltk.key(), *fake_link()->ltk());
// The link security level is not assigned until successful encryption.
EXPECT_EQ(SecurityProperties(), pairing()->security());
fake_link()->TriggerEncryptionChangeCallback(fit::ok(/*enabled=*/true));
RunUntilIdle();
EXPECT_EQ(1, new_sec_props_count());
EXPECT_EQ(sec_props, new_sec_props());
EXPECT_EQ(sec_props, pairing()->security());
}
TEST_F(InitiatorPairingTest, ReceiveSecurityRequest) {
ReceiveSecurityRequest(AuthReq::kMITM);
RunUntilIdle();
// Should have requested pairing with MITM protection.
EXPECT_EQ(1, pairing_request_count());
const auto& params = local_pairing_cmd().view(1).To<PairingRequestParams>();
EXPECT_TRUE(params.auth_req & AuthReq::kMITM);
}
TEST_F(InitiatorPairingTest, ReceiveSecurityRequestWhenPaired) {
UInt128 stk;
FastForwardToPhase3(&stk,
/*secure_connections=*/false,
SecurityLevel::kEncrypted,
KeyDistGen::kEncKey);
EXPECT_EQ(stk, fake_link()->ltk()->value());
EXPECT_EQ(1, pairing_request_count());
// Receive EncKey and wait until the link is encrypted with the LTK.
UInt128 kLTK{{1, 2, 3, 4, 5, 6, 7, 8, 7, 6, 5, 4, 3, 2, 1, 0}};
uint64_t kRand = 5;
uint16_t kEDiv = 20;
ReceiveEncryptionInformation(kLTK);
ReceiveCentralIdentification(kRand, kEDiv);
RunUntilIdle();
fake_link()->TriggerEncryptionChangeCallback(fit::ok(/*enabled=*/true));
RunUntilIdle();
ASSERT_EQ(1, pairing_complete_count());
ASSERT_EQ(fit::ok(), security_status());
ASSERT_TRUE(peer_ltk());
ASSERT_EQ(SecurityLevel::kEncrypted, sec_props().level());
ASSERT_EQ(1, fake_link()->start_encryption_count()); // Once for the STK
ASSERT_EQ(1, pairing_request_count());
// Receive a security request with the no MITM requirement. This should
// trigger an encryption key refresh and no pairing request.
ReceiveSecurityRequest();
EXPECT_EQ(1, pairing_request_count());
// Once for the STK and once again due to the locally initiated key refresh.
ASSERT_EQ(2, fake_link()->start_encryption_count());
// Receive a security request with a higher security requirement. This should
// trigger a pairing request.
ReceiveSecurityRequest(AuthReq::kMITM);
EXPECT_EQ(2, pairing_request_count());
const auto& params = local_pairing_cmd().view(1).To<PairingRequestParams>();
EXPECT_TRUE(params.auth_req & AuthReq::kMITM);
}
TEST_F(InitiatorPairingTest,
ReceiveMITMSecurityRequestLocalIoCapNoInputNoOutput) {
SetUpSecurityManager(IOCapability::kNoInputNoOutput);
ReceiveSecurityRequest(AuthReq::kMITM);
// We should notify the peer that we cannot complete the security request due
// to authentication requirements.
EXPECT_EQ(1, pairing_failed_count());
EXPECT_EQ(ErrorCode::kAuthenticationRequirements, received_error_code());
// When we receive a Security Request, we start a timer. Run the loop to
// ensure that when we can't fulfill the Security Request, we stop the timer
// before it expires as we never started pairing.
RunFor(kPairingTimeout + std::chrono::seconds(1));
// Double check we haven't sent any more Pairing Failed messages
EXPECT_EQ(1, pairing_failed_count());
// We should not notify local clients of any pairing completion, because no
// pairing ever started.
EXPECT_EQ(0, pairing_complete_count());
}
TEST_F(InitiatorPairingTest, RejectPairingRequest) {
// Although we are the initiator, set the peer_initiator=true for this test so
// that we emulate reception of the Pairing Request command, not the Pairing
// Response command.
ReceivePairingFeatures(IOCapability::kDisplayYesNo,
AuthReqField{0},
kMaxEncryptionKeySize,
/*peer_initiator=*/true);
RunUntilIdle();
// We should reject the security request with CommandNotSupported as
// initiator.
EXPECT_EQ(1, pairing_failed_count());
EXPECT_EQ(ErrorCode::kCommandNotSupported, received_error_code());
// Run for the full pairing timeout to ensure we do not timeout due to sending
// a message.
RunFor(kPairingTimeout + std::chrono::seconds(1));
// No pairing occurred, as we rejected the security request command.
EXPECT_EQ(0, pairing_complete_count());
EXPECT_EQ(1, pairing_failed_count());
}
TEST_F(InitiatorPairingTest, PairingTimeoutWorks) {
UpgradeSecurity(SecurityLevel::kEncrypted);
RunUntilIdle();
ASSERT_EQ(1, pairing_request_count());
// Expiration of the pairing timeout should trigger the link error callback
// per v5.2 Vol. 3 Part H 3.4. Link disconnection will generally cause channel
// closure, so this simulates that behavior to validate that SM handles this
// safely.
fake_chan()->SetLinkErrorCallback([chan = fake_chan()]() { chan->Close(); });
RunFor(kPairingTimeout);
EXPECT_TRUE(fake_chan()->link_error());
ASSERT_EQ(1, security_callback_count());
EXPECT_EQ(ToResult(HostError::kTimedOut), security_status());
ASSERT_EQ(1, pairing_complete_count());
EXPECT_EQ(ToResult(HostError::kTimedOut), pairing_complete_status());
}
TEST_F(InitiatorPairingTest, NoTimeoutAfterSuccessfulPairing) {
UInt128 out_stk;
FastForwardToPhase3(&out_stk,
/*secure_connections=*/false,
SecurityLevel::kEncrypted,
KeyDistGenField{0},
KeyDistGenField{0});
ASSERT_EQ(1, pairing_complete_count());
ASSERT_EQ(1, security_callback_count());
ASSERT_EQ(fit::ok(), security_status());
ASSERT_EQ(fit::ok(), pairing_complete_status());
// Verify that no timeout occurs after a successful pairing followed by a long
// interval.
RunFor(kPairingTimeout * 2);
ASSERT_EQ(1, pairing_complete_count());
ASSERT_EQ(1, security_callback_count());
EXPECT_NE(ToResult(HostError::kTimedOut), pairing_complete_status());
EXPECT_NE(ToResult(HostError::kTimedOut), security_status());
}
TEST_F(InitiatorPairingTest, AbortStopsPairingTimer) {
UpgradeSecurity(SecurityLevel::kEncrypted);
RunUntilIdle();
ASSERT_EQ(1, pairing_request_count());
pairing()->Abort();
// Calling Abort should stop the pairing procedure and the timer.
ASSERT_EQ(1, pairing_complete_count());
ASSERT_EQ(1, security_callback_count());
// Run the loop for a time that would cause a timeout if a timer were active.
RunFor(kPairingTimeout * 2);
ASSERT_EQ(1, pairing_complete_count());
ASSERT_EQ(1, security_callback_count());
EXPECT_NE(ToResult(HostError::kTimedOut), pairing_complete_status());
EXPECT_NE(ToResult(HostError::kTimedOut), security_status());
}
TEST_F(InitiatorPairingTest, ResetStopsPairingTimer) {
UpgradeSecurity(SecurityLevel::kEncrypted);
RunUntilIdle();
ASSERT_EQ(1, pairing_request_count());
pairing()->Reset(IOCapability::kDisplayYesNo);
// Resetting the pairing aborts the current procedure.
ASSERT_EQ(1, pairing_complete_count());
ASSERT_EQ(1, security_callback_count());
// Run the loop for a time that would cause a timeout if a timer were active.
RunFor(kPairingTimeout * 2);
ASSERT_EQ(1, pairing_complete_count());
ASSERT_EQ(1, security_callback_count());
EXPECT_NE(ToResult(HostError::kTimedOut), pairing_complete_status());
EXPECT_NE(ToResult(HostError::kTimedOut), security_status());
}
TEST_F(InitiatorPairingTest, SendingMessageRestartsTimer) {
// SM will send the Pairing Request, which is special-cased to "reset and
// start" the pairing timer (v5.2 Vol. 3 Part H 3.4), and thus not under test
// here.
UpgradeSecurity(SecurityLevel::kEncrypted);
RunUntilIdle();
ASSERT_EQ(1, pairing_request_count());
// Run the loop until the pairing timeout has almost expired.
RunFor(kPairingTimeout - pw::chrono::SystemClock::duration(1));
// Receive the not special-cased Pairing Response, which should trigger SM to
// send the also not special-cased Pairing Confirm.
ReceivePairingFeatures();
// Run the loop for 1 more second, which would timeout if the timer had not
// been reset.
RunFor(pw::chrono::SystemClock::duration(1));
// The timeout should not have triggered, so there should be no notification
// of pairing failure.
ASSERT_EQ(0, pairing_complete_count());
ASSERT_EQ(0, security_callback_count());
// Verify that the timer is in fact still active; without receiving further
// messages, the timeout should trigger.
RunFor(kPairingTimeout);
ASSERT_EQ(1, pairing_complete_count());
ASSERT_EQ(1, security_callback_count());
EXPECT_EQ(ToResult(HostError::kTimedOut), pairing_complete_status());
EXPECT_EQ(ToResult(HostError::kTimedOut), security_status());
}
TEST_F(InitiatorPairingTest,
ModifyAssignedLinkLtkBeforeSecurityRequestCausesDisconnect) {
SecurityProperties sec_props(
SecurityLevel::kAuthenticated, 16, /*secure_connections=*/false);
const LTK kOriginalLtk(sec_props, hci_spec::LinkKey({1}, 2, 3));
const hci_spec::LinkKey kModifiedLtk(hci_spec::LinkKey({4}, 5, 6));
EXPECT_TRUE(pairing()->AssignLongTermKey(kOriginalLtk));
fake_link()->set_ltk(kModifiedLtk);
// When we receive the Security Request on a bonded (i.e. AssignLongTermKey
// has been called) connection, we will refresh the encryption key. This
// checks that the link LTK = the SMP LTK which is not the case.
ReceiveSecurityRequest(AuthReqField{0});
RunUntilIdle();
ASSERT_TRUE(fake_chan()->link_error());
ASSERT_EQ(1, auth_failure_callback_count());
ASSERT_EQ(ToResult(pw::bluetooth::emboss::StatusCode::PIN_OR_KEY_MISSING),
auth_failure_status());
}
TEST_F(ResponderPairingTest, SuccessfulPairAfterResetInProgressPairing) {
ReceivePairingRequest();
RunUntilIdle();
// At this point, we expect to have completed Phase 1, and pairing should
// still be in progress.
EXPECT_EQ(1, pairing_response_count());
pairing()->Abort();
RunUntilIdle();
// Pairing should have failed and ended.
EXPECT_EQ(1, pairing_failed_count());
EXPECT_EQ(1, pairing_complete_count());
// Verify that the next pairing request is properly handled
ReceivePairingRequest();
RunUntilIdle();
// At this point, we expect to have completed Phase 1, and pairing should
// still be in progress.
EXPECT_EQ(2, pairing_response_count());
}
TEST_F(ResponderPairingTest, SecurityRequestCausesPairing) {
UpgradeSecurity(SecurityLevel::kEncrypted);
RunUntilIdle();
AuthReqField expected_auth_req = AuthReq::kBondingFlag;
EXPECT_EQ(1, security_request_count());
EXPECT_EQ(expected_auth_req, security_request_payload());
UInt128 ltk_bytes;
FastForwardToPhase3(&ltk_bytes, /*secure_connections=*/true);
// Pairing should have succeeded
EXPECT_EQ(0, pairing_failed_count());
EXPECT_EQ(1, security_callback_count());
EXPECT_EQ(1, pairing_complete_count());
EXPECT_EQ(fit::ok(), security_status());
EXPECT_EQ(security_status(), pairing_complete_status());
// LTK should have been assigned to the link.
hci_spec::LinkKey kExpectedLinkKey(ltk_bytes, 0, 0);
ASSERT_TRUE(fake_link()->ltk());
EXPECT_EQ(kExpectedLinkKey, fake_link()->ltk());
EXPECT_EQ(SecurityLevel::kEncrypted, sec_props().level());
EXPECT_EQ(16u, sec_props().enc_key_size());
EXPECT_TRUE(sec_props().secure_connections());
// Should have notified the LTK.
EXPECT_EQ(1, pairing_data_callback_count());
ASSERT_TRUE(local_ltk());
EXPECT_EQ(sec_props(), local_ltk()->security());
EXPECT_EQ(kExpectedLinkKey, local_ltk()->key());
}
TEST_F(ResponderPairingTest, SecurityRequestWithExistingLtk) {
const SecurityProperties kProps(SecurityLevel::kAuthenticated,
kMaxEncryptionKeySize,
/*secure_connections=*/true);
const LTK kLtk(kProps, hci_spec::LinkKey({1, 2, 3}, 0, 0));
// This pretends that we have an already-bonded LTK.
pairing()->AssignLongTermKey(kLtk);
// LTK should have been assigned to the link.
ASSERT_TRUE(fake_link()->ltk());
EXPECT_EQ(kLtk.key(), fake_link()->ltk());
// Make the Security Upgrade request
UpgradeSecurity(SecurityLevel::kAuthenticated);
RunUntilIdle();
AuthReqField expected_auth_req = AuthReq::kBondingFlag | AuthReq::kMITM;
EXPECT_EQ(1, security_request_count());
EXPECT_EQ(expected_auth_req, security_request_payload());
fake_link()->TriggerEncryptionChangeCallback(fit::ok(/*enabled=*/true));
// Security should be upgraded.
EXPECT_EQ(1, security_callback_count());
EXPECT_EQ(fit::ok(), security_status());
EXPECT_EQ(kProps.level(), sec_props().level());
EXPECT_EQ(16u, sec_props().enc_key_size());
EXPECT_TRUE(sec_props().secure_connections());
// No pairing should have taken place - we had an already-bonded LTK.
EXPECT_EQ(0, pairing_failed_count());
EXPECT_EQ(0, pairing_complete_count());
EXPECT_EQ(0, pairing_data_callback_count());
}
TEST_F(ResponderPairingTest,
SecurityRequestInitiatorEncryptsWithInsufficientSecurityLtk) {
const SecurityProperties kProps(SecurityLevel::kEncrypted,
kMaxEncryptionKeySize,
/*secure_connections=*/true);
const LTK kLtk(kProps, hci_spec::LinkKey({1, 2, 3}, 0, 0));
// This pretends that we have an already-bonded LTK with kEncrypted security
// level.
pairing()->AssignLongTermKey(kLtk);
// LTK should have been assigned to the link.
ASSERT_TRUE(fake_link()->ltk());
EXPECT_EQ(kLtk.key(), fake_link()->ltk());
// Make a security request for authenticated security
UpgradeSecurity(SecurityLevel::kAuthenticated);
RunUntilIdle();
AuthReqField expected_auth_req = AuthReq::kBondingFlag | AuthReq::kMITM;
EXPECT_EQ(1, security_request_count());
EXPECT_EQ(expected_auth_req, security_request_payload());
// Pretend the SMP initiator started encryption with the bonded LTK of
// SecurityLevel::kEncrypted.
fake_link()->TriggerEncryptionChangeCallback(fit::ok(/*enabled=*/true));
// If the peer responds to our MITM security request by encrypting with an
// unauthenticated key, they stored the LTK/handle security request
// incorrectly - either way, disconnect the link.
ASSERT_TRUE(fake_chan()->link_error());
}
TEST_F(ResponderPairingTest,
AuthenticatedSecurityRequestWithInsufficientIoCapRejected) {
SetUpSecurityManager(IOCapability::kNoInputNoOutput);
// Make a security request for authenticated security
UpgradeSecurity(SecurityLevel::kAuthenticated);
RunUntilIdle();
// The security callback should have been rejected w/o sending any messages,
// as our IOCap cannot perform authenticated pairing.
EXPECT_EQ(0, security_request_count());
EXPECT_EQ(1, security_callback_count());
EXPECT_EQ(ToResult(ErrorCode::kAuthenticationRequirements),
security_status());
EXPECT_EQ(SecurityLevel::kNoSecurity, sec_props().level());
}
TEST_F(ResponderPairingTest, HandlesMultipleSecurityRequestsCorrectly) {
// Make a security request for encrypted security
UpgradeSecurity(SecurityLevel::kEncrypted);
RunUntilIdle();
AuthReqField expected_auth_req = AuthReq::kBondingFlag;
EXPECT_EQ(1, security_request_count());
EXPECT_EQ(expected_auth_req, security_request_payload());
// Making another security request, this time for authenticated security,
// while the first is still pending should not cause another Security Request
// message to be sent.
UpgradeSecurity(SecurityLevel::kAuthenticated);
RunUntilIdle();
EXPECT_EQ(1, security_request_count());
// Handle the first Security Request
UInt128 ltk_bytes;
FastForwardToPhase3(
&ltk_bytes, /*secure_connections=*/true, SecurityLevel::kEncrypted);
// Pairing should have succeeded
EXPECT_EQ(0, pairing_failed_count());
EXPECT_EQ(1, security_callback_count());
EXPECT_EQ(1, pairing_complete_count());
EXPECT_EQ(fit::ok(), security_status());
EXPECT_EQ(security_status(), pairing_complete_status());
EXPECT_EQ(SecurityLevel::kEncrypted, sec_props().level());
// Should have notified the LTK.
EXPECT_EQ(1, pairing_data_callback_count());
ASSERT_TRUE(local_ltk());
EXPECT_EQ(sec_props(), local_ltk()->security());
EXPECT_EQ(ltk_bytes, local_ltk()->key().value());
// After the first pairing satisfied the kEncrypted Security Request, the
// pending kAuthenticated Security Request should have been sent immediately.
EXPECT_EQ(2, security_request_count());
}
TEST_F(ResponderPairingTest, ReceiveSecondPairingRequestWhilePairing) {
ReceivePairingRequest();
RunUntilIdle();
// We should have sent a pairing response and should now be in Phase 2,
// waiting for the peer to send us Mconfirm.
EXPECT_EQ(0, pairing_request_count());
EXPECT_EQ(1, pairing_response_count());
EXPECT_EQ(0, pairing_confirm_count());
EXPECT_EQ(0, pairing_random_count());
EXPECT_EQ(0, pairing_failed_count());
EXPECT_EQ(0, security_callback_count());
EXPECT_EQ(0, pairing_complete_count());
// This should cause pairing to be aborted.
ReceivePairingRequest();
RunUntilIdle();
EXPECT_EQ(0, pairing_request_count());
// We will abort the second pairing request without responding if we're
// already in progress
EXPECT_EQ(1, pairing_response_count());
EXPECT_EQ(0, pairing_confirm_count());
EXPECT_EQ(0, pairing_random_count());
EXPECT_EQ(1, pairing_failed_count());
EXPECT_EQ(0, security_callback_count());
EXPECT_EQ(1, pairing_complete_count());
ASSERT_EQ(ErrorCode::kUnspecifiedReason, received_error_code());
EXPECT_EQ(ToResult(received_error_code().value()), pairing_complete_status());
}
TEST_F(ResponderPairingTest, ReceiveConfirmValueWhileWaitingForTK) {
bool tk_requested = false;
ConfirmCallback respond;
set_confirm_delegate([&](ConfirmCallback cb) {
tk_requested = true;
respond = std::move(cb);
});
ReceivePairingRequest();
RunUntilIdle();
ASSERT_TRUE(tk_requested);
UInt128 confirm;
ReceivePairingConfirm(confirm);
RunUntilIdle();
// Pairing should still be in progress without sending out any packets.
EXPECT_EQ(0, pairing_confirm_count());
EXPECT_EQ(0, pairing_random_count());
EXPECT_EQ(0, pairing_failed_count());
EXPECT_EQ(0, security_callback_count());
EXPECT_EQ(0, pairing_complete_count());
// Respond with the TK. This should cause us to send Sconfirm.
respond(true);
RunUntilIdle();
EXPECT_EQ(1, pairing_confirm_count());
EXPECT_EQ(0, pairing_random_count());
EXPECT_EQ(0, pairing_failed_count());
EXPECT_EQ(0, security_callback_count());
EXPECT_EQ(0, pairing_complete_count());
}
TEST_F(ResponderPairingTest, LegacyPhase2ReceivePairingRandomInWrongOrder) {
ReceivePairingRequest();
RunUntilIdle();
// We should have sent a pairing response and should now be in Phase 2,
// waiting for the peer to send us Mconfirm.
EXPECT_EQ(0, pairing_request_count());
EXPECT_EQ(1, pairing_response_count());
EXPECT_EQ(0, pairing_confirm_count());
EXPECT_EQ(0, pairing_random_count());
EXPECT_EQ(0, pairing_failed_count());
EXPECT_EQ(0, security_callback_count());
EXPECT_EQ(0, pairing_complete_count());
// Peer sends Mrand before Mconfirm.
UInt128 random;
ReceivePairingRandom(random);
RunUntilIdle();
EXPECT_EQ(0, pairing_request_count());
EXPECT_EQ(1, pairing_response_count());
EXPECT_EQ(0, pairing_confirm_count());
EXPECT_EQ(0, pairing_random_count());
EXPECT_EQ(1, pairing_failed_count());
EXPECT_EQ(0, security_callback_count());
EXPECT_EQ(1, pairing_complete_count());
EXPECT_EQ(ErrorCode::kUnspecifiedReason, received_error_code());
EXPECT_EQ(ToResult(ErrorCode::kUnspecifiedReason), pairing_complete_status());
}
TEST_F(ResponderPairingTest, LegacyPhase2MconfirmValueInvalid) {
ReceivePairingRequest();
RunUntilIdle();
// We should have sent a pairing response and should now be in Phase 2,
// waiting for the peer to send us Mconfirm.
EXPECT_EQ(0, pairing_request_count());
EXPECT_EQ(1, pairing_response_count());
EXPECT_EQ(0, pairing_confirm_count());
EXPECT_EQ(0, pairing_random_count());
EXPECT_EQ(0, pairing_failed_count());
EXPECT_EQ(0, security_callback_count());
EXPECT_EQ(0, pairing_complete_count());
// Set up values that don't match.
UInt128 confirm, random;
confirm.fill(0);
random.fill(1);
ReceivePairingConfirm(confirm);
RunUntilIdle();
// We should have sent Sconfirm.
EXPECT_EQ(0, pairing_request_count());
EXPECT_EQ(1, pairing_response_count());
EXPECT_EQ(1, pairing_confirm_count());
EXPECT_EQ(0, pairing_random_count());
EXPECT_EQ(0, pairing_failed_count());
EXPECT_EQ(0, security_callback_count());
EXPECT_EQ(0, pairing_complete_count());
// Peer sends Mrand that doesn't match. We should reject the pairing
// without sending Srand.
ReceivePairingRandom(random);
RunUntilIdle();
EXPECT_EQ(0, pairing_request_count());
EXPECT_EQ(1, pairing_response_count());
EXPECT_EQ(1, pairing_confirm_count());
EXPECT_EQ(0, pairing_random_count());
EXPECT_EQ(1, pairing_failed_count());
EXPECT_EQ(0, security_callback_count());
EXPECT_EQ(1, pairing_complete_count());
EXPECT_EQ(ErrorCode::kConfirmValueFailed, received_error_code());
EXPECT_EQ(ToResult(ErrorCode::kConfirmValueFailed),
pairing_complete_status());
}
TEST_F(ResponderPairingTest, LegacyPhase2ConfirmValuesExchanged) {
ReceivePairingRequest();
RunUntilIdle();
// We should have sent a pairing response and should now be in Phase 2,
// waiting for the peer to send us Mconfirm.
EXPECT_EQ(0, pairing_request_count());
EXPECT_EQ(1, pairing_response_count());
EXPECT_EQ(0, pairing_confirm_count());
EXPECT_EQ(0, pairing_random_count());
EXPECT_EQ(0, pairing_failed_count());
EXPECT_EQ(0, security_callback_count());
EXPECT_EQ(0, pairing_complete_count());
// Set up Sconfirm and Srand values that match.
UInt128 confirm, random;
GenerateMatchingLegacyConfirmAndRandom(&confirm, &random);
// Peer sends Mconfirm.
ReceivePairingConfirm(confirm);
RunUntilIdle();
// We should have sent Sconfirm.
EXPECT_EQ(0, pairing_request_count());
EXPECT_EQ(1, pairing_response_count());
EXPECT_EQ(1, pairing_confirm_count());
EXPECT_EQ(0, pairing_random_count());
EXPECT_EQ(0, pairing_failed_count());
EXPECT_EQ(0, security_callback_count());
EXPECT_EQ(0, pairing_complete_count());
// Peer sends Mrand.
ReceivePairingRandom(random);
RunUntilIdle();
// We should have sent Srand.
EXPECT_EQ(0, pairing_request_count());
EXPECT_EQ(1, pairing_response_count());
EXPECT_EQ(1, pairing_confirm_count());
EXPECT_EQ(1, pairing_random_count());
EXPECT_EQ(0, pairing_failed_count());
EXPECT_EQ(0, security_callback_count());
EXPECT_EQ(0, pairing_complete_count());
// Sconfirm/Srand values we sent should be correct.
UInt128 expected_confirm;
GenerateLegacyConfirmValue(
pairing_random(), &expected_confirm, /*peer_initiator=*/true);
EXPECT_EQ(expected_confirm, pairing_confirm());
}
TEST_F(ResponderPairingTest, LegacyPhase3LocalLTKDistributionNoRemoteKeys) {
EXPECT_EQ(0, enc_info_count());
EXPECT_EQ(0, central_ident_count());
UInt128 stk;
KeyDistGenField remote_keys{0}, local_keys{KeyDistGen::kEncKey};
FastForwardToPhase3(&stk,
/*secure_connections=*/false,
SecurityLevel::kEncrypted,
remote_keys,
local_keys);
// Local LTK, EDiv, and Rand should be sent to the peer.
EXPECT_EQ(1, enc_info_count());
EXPECT_EQ(1, central_ident_count());
ASSERT_TRUE(fake_link()->ltk());
EXPECT_EQ(enc_info(), fake_link()->ltk()->value());
EXPECT_EQ(ediv(), fake_link()->ltk()->ediv());
EXPECT_EQ(rand(), fake_link()->ltk()->rand());
// This LTK should be stored with the pairing data but the pairing callback
// shouldn't be called because pairing wasn't initiated by UpgradeSecurity().
EXPECT_EQ(0, pairing_failed_count());
EXPECT_EQ(0, security_callback_count());
// Pairing is considered complete when all keys have been distributed even if
// we're still encrypted with the STK. This is because the initiator may not
// always re-encrypt the link with the LTK until a reconnection.
EXPECT_EQ(1, pairing_data_callback_count());
// Nonetheless the link should have been assigned the LTK.
ASSERT_TRUE(pairing_data().local_ltk.has_value());
EXPECT_EQ(fake_link()->ltk(), pairing_data().local_ltk->key());
// Make sure that an encryption change has no effect.
fake_link()->TriggerEncryptionChangeCallback(fit::ok(/*enabled=*/true));
RunUntilIdle();
EXPECT_EQ(1, pairing_data_callback_count());
// No additional security property update should have been sent since the STK
// and LTK have the same properties.
EXPECT_EQ(1, new_sec_props_count());
}
TEST_F(ResponderPairingTest, LegacyPhase3LocalLTKDistributionWithRemoteKeys) {
EXPECT_EQ(0, enc_info_count());
EXPECT_EQ(0, central_ident_count());
UInt128 stk;
FastForwardToPhase3(&stk,
/*secure_connections=*/false,
SecurityLevel::kEncrypted,
KeyDistGen::kIdKey, // remote keys
KeyDistGen::kEncKey); // local keys
// Local LTK, EDiv, and Rand should be sent to the peer - we don't assign the
// new LTK to the link until pairing is complete.
EXPECT_EQ(1, enc_info_count());
EXPECT_EQ(1, central_ident_count());
// No local identity information should have been sent.
EXPECT_EQ(0, id_info_count());
EXPECT_EQ(0, id_addr_info_count());
// This LTK should be stored with the pairing data but the pairing callback
// shouldn't be called because pairing wasn't initiated by UpgradeSecurity().
EXPECT_EQ(0, pairing_failed_count());
EXPECT_EQ(0, security_callback_count());
// Still waiting for initiator's keys.
EXPECT_EQ(0, pairing_data_callback_count());
const auto kIrk = Random<UInt128>();
ReceiveIdentityResolvingKey(kIrk);
ReceiveIdentityAddress(kPeerAddr);
RunUntilIdle();
// Pairing is considered complete when all keys have been distributed even if
// we're still encrypted with the STK. This is because the initiator may not
// always re-encrypt the link with the LTK until a reconnection.
EXPECT_EQ(1, pairing_data_callback_count());
// The peer should have sent us its identity information.
ASSERT_TRUE(pairing_data().irk);
EXPECT_EQ(kIrk, pairing_data().irk->value());
ASSERT_TRUE(pairing_data().identity_address);
EXPECT_EQ(kPeerAddr, *pairing_data().identity_address);
// Nonetheless the link should have been assigned the LTK.
ASSERT_TRUE(pairing_data().local_ltk.has_value());
EXPECT_EQ(fake_link()->ltk(), pairing_data().local_ltk->key());
}
// Locally generated ltk length should match max key length specified
TEST_F(ResponderPairingTest, LegacyPhase3LocalLTKMaxLength) {
EXPECT_EQ(0, enc_info_count());
EXPECT_EQ(0, central_ident_count());
UInt128 stk;
uint16_t max_key_size = 7;
FastForwardToPhase3(&stk,
/*secure_connections=*/false,
SecurityLevel::kEncrypted,
0u, // remote keys
KeyDistGen::kEncKey, // local keys
max_key_size);
// Local LTK, EDiv, and Rand should be sent to the peer.
EXPECT_EQ(1, enc_info_count());
EXPECT_EQ(1, central_ident_count());
ASSERT_TRUE(fake_link()->ltk());
EXPECT_EQ(enc_info(), fake_link()->ltk()->value());
EXPECT_EQ(ediv(), fake_link()->ltk()->ediv());
EXPECT_EQ(rand(), fake_link()->ltk()->rand());
// This LTK should be stored with the pairing data but the pairing callback
// shouldn't be called because pairing wasn't initiated by UpgradeSecurity().
EXPECT_EQ(0, pairing_failed_count());
EXPECT_EQ(0, security_callback_count());
// Pairing is considered complete when all keys have been distributed even if
// we're still encrypted with the STK. This is because the initiator may not
// always re-encrypt the link with the LTK until a reconnection.
EXPECT_EQ(1, pairing_data_callback_count());
// The link should have been assigned the LTK.
ASSERT_TRUE(pairing_data().local_ltk.has_value());
EXPECT_EQ(fake_link()->ltk(), pairing_data().local_ltk->key());
// Ensure that most significant (16 - max_key_size) bytes are zero. The key
// should be generated up to the max_key_size.
auto ltk = pairing_data().local_ltk->key().value();
for (auto i = max_key_size; i < ltk.size(); i++) {
EXPECT_TRUE(ltk[i] == 0);
}
}
TEST_F(ResponderPairingTest, LegacyPhase3ReceiveInitiatorEncKey) {
UInt128 stk;
KeyDistGenField remote_keys{KeyDistGen::kEncKey}, local_keys{0u};
FastForwardToPhase3(&stk,
/*secure_connections=*/false,
SecurityLevel::kEncrypted,
remote_keys,
local_keys);
const uint64_t kRand = 5;
const uint16_t kEDiv = 20;
const hci_spec::LinkKey kLTK(
{1, 2, 3, 4, 5, 6, 7, 8, 7, 6, 5, 4, 3, 2, 1, 0}, kRand, kEDiv);
ReceiveEncryptionInformation(kLTK.value());
ReceiveCentralIdentification(kRand, kEDiv);
RunUntilIdle();
// Pairing should have succeeded.
EXPECT_EQ(0, pairing_failed_count());
EXPECT_EQ(1, pairing_complete_count());
EXPECT_EQ(fit::ok(), security_status());
EXPECT_EQ(security_status(), pairing_complete_status());
// No pairing callbacks needed as this is a peer-initiated pairing.
EXPECT_EQ(0, security_callback_count());
// Only the STK should be assigned to the link, as the distributed LTK was
// initiator-generated. This means it can only be used to encrypt future
// connections where the roles are reversed.
EXPECT_EQ(stk, fake_link()->ltk()->value());
// Should have been called at least once to determine local identity
// availability.
EXPECT_NE(0, local_id_info_callback_count());
// Should have notified pairing data callback with the LTK.
EXPECT_EQ(1, pairing_data_callback_count());
ASSERT_TRUE(peer_ltk());
// LTK received OTA should match what we notified the pairing data callback
// with.
EXPECT_EQ(kLTK, peer_ltk()->key());
}
TEST_F(ResponderPairingTest, LegacyPhase3LocalIdKeyDistributionWithRemoteKeys) {
IdentityInfo local_id_info;
local_id_info.irk = UInt128{{1, 2, 3, 4, 5, 6, 7, 8, 7, 6, 5, 4, 3, 2, 1, 0}};
local_id_info.address = kLocalAddr;
set_local_id_info(local_id_info);
EXPECT_EQ(0, enc_info_count());
EXPECT_EQ(0, central_ident_count());
UInt128 stk;
FastForwardToPhase3(&stk,
/*secure_connections=*/false,
SecurityLevel::kEncrypted,
KeyDistGen::kIdKey, // remote keys
KeyDistGen::kIdKey); // local keys
// No local LTK, EDiv, and Rand should be sent to the peer.
EXPECT_EQ(0, enc_info_count());
EXPECT_EQ(0, central_ident_count());
// Local identity information should have been sent.
EXPECT_EQ(1, id_info_count());
EXPECT_EQ(local_id_info.irk, id_info());
EXPECT_EQ(1, id_addr_info_count());
EXPECT_EQ(local_id_info.address, id_addr_info());
// Still waiting for initiator's keys.
EXPECT_EQ(0, pairing_data_callback_count());
const auto kIrk = Random<UInt128>();
ReceiveIdentityResolvingKey(kIrk);
ReceiveIdentityAddress(kPeerAddr);
RunUntilIdle();
// Pairing is considered complete when all keys have been distributed even if
// we're still encrypted with the STK. This is because the initiator may not
// always re-encrypt the link with the LTK until a reconnection.
EXPECT_EQ(1, pairing_data_callback_count());
// The peer should have sent us its identity information.
ASSERT_TRUE(pairing_data().irk);
EXPECT_EQ(kIrk, pairing_data().irk->value());
ASSERT_TRUE(pairing_data().identity_address);
EXPECT_EQ(kPeerAddr, *pairing_data().identity_address);
}
TEST_F(ResponderPairingTest, AssignLongTermKeyFailsDuringPairing) {
ReceivePairingRequest();
RunUntilIdle();
SecurityProperties sec_props(
SecurityLevel::kAuthenticated, 16, /*secure_connections=*/false);
EXPECT_FALSE(
pairing()->AssignLongTermKey(LTK(sec_props, hci_spec::LinkKey())));
EXPECT_EQ(0, fake_link()->start_encryption_count());
EXPECT_EQ(SecurityLevel::kNoSecurity, pairing()->security().level());
}
TEST_F(ResponderPairingTest, AssignLongTermKey) {
SecurityProperties sec_props(
SecurityLevel::kAuthenticated, 16, /*secure_connections=*/false);
LTK ltk(sec_props, hci_spec::LinkKey());
EXPECT_TRUE(pairing()->AssignLongTermKey(ltk));
ASSERT_TRUE(fake_link()->ltk());
EXPECT_EQ(ltk.key(), *fake_link()->ltk());
// No encryption request should have been made as the initiator is expected to
// do it.
EXPECT_EQ(0, fake_link()->start_encryption_count());
// The link security level is not assigned until successful encryption.
EXPECT_EQ(SecurityProperties(), pairing()->security());
fake_link()->TriggerEncryptionChangeCallback(fit::ok(/*enabled=*/true));
RunUntilIdle();
EXPECT_EQ(1, new_sec_props_count());
EXPECT_EQ(sec_props, new_sec_props());
EXPECT_EQ(sec_props, pairing()->security());
}
TEST_F(ResponderPairingTest, EncryptWithLinkKeyModifiedOutsideSmDisconnects) {
SecurityProperties sec_props(
SecurityLevel::kAuthenticated, 16, /*secure_connections=*/false);
const LTK kOriginalLtk(sec_props, hci_spec::LinkKey({1}, 2, 3));
const hci_spec::LinkKey kModifiedLtk(hci_spec::LinkKey({4}, 5, 6));
EXPECT_TRUE(pairing()->AssignLongTermKey(kOriginalLtk));
fake_link()->set_ltk(kModifiedLtk);
fake_link()->TriggerEncryptionChangeCallback(fit::ok(/*enabled=*/true));
RunUntilIdle();
ASSERT_TRUE(fake_chan()->link_error());
ASSERT_EQ(1, auth_failure_callback_count());
ASSERT_EQ(ToResult(pw::bluetooth::emboss::StatusCode::PIN_OR_KEY_MISSING),
auth_failure_status());
}
TEST_F(ResponderPairingTest, EncryptWithLinkKeyButNoSmLtkDisconnects) {
// The LE link LTK should always be assigned through SM, so while encryption
// could succeed with a link LTK but no SM LTK, this is a violation of bt-host
// assumptions and we will disconnect.
fake_link()->set_ltk(hci_spec::LinkKey({1}, 2, 3));
fake_link()->TriggerEncryptionChangeCallback(fit::ok(/*enabled=*/true));
RunUntilIdle();
ASSERT_TRUE(fake_chan()->link_error());
ASSERT_EQ(1, auth_failure_callback_count());
ASSERT_EQ(ToResult(pw::bluetooth::emboss::StatusCode::PIN_OR_KEY_MISSING),
auth_failure_status());
}
// As responder, we reject security requests, as the initiator should never send
// them.
TEST_F(ResponderPairingTest, RejectSecurityRequest) {
ReceiveSecurityRequest();
EXPECT_EQ(1, pairing_failed_count());
EXPECT_EQ(ErrorCode::kCommandNotSupported, received_error_code());
// Run for the full pairing timeout to ensure we do not timeout due to sending
// a message.
RunFor(kPairingTimeout + std::chrono::seconds(1));
EXPECT_EQ(0, pairing_request_count());
EXPECT_EQ(0, fake_link()->start_encryption_count());
EXPECT_EQ(1, pairing_failed_count());
}
// Test that LTK is generated and passed up to SecurityManager when both sides
// request bonding
TEST_F(ResponderPairingTest, BothSidesRequestBondingLTKCreated) {
UInt128 stk;
SetUpSecurityManager(IOCapability::kDisplayOnly);
FastForwardToPhase3(&stk,
/*secure_connections=*/false,
SecurityLevel::kEncrypted,
0u, // remote keys
KeyDistGen::kEncKey, // local keys
kMaxEncryptionKeySize,
BondableMode::Bondable);
// The link should have been assigned the LTK.
EXPECT_TRUE(pairing_data().local_ltk.has_value());
}
// Test that LTK is not passed up to SecurityManager when local side requests
// non-bondable mode and peer requests bondable mode.
TEST_F(ResponderPairingTest, LocalRequestsNonBondableNoLTKCreated) {
UInt128 stk;
SetUpSecurityManager(IOCapability::kDisplayOnly, BondableMode::NonBondable);
FastForwardToPhase3(&stk,
/*secure_connections=*/false,
SecurityLevel::kEncrypted,
0u, // remote keys
KeyDistGen::kEncKey, // local keys
kMaxEncryptionKeySize,
BondableMode::Bondable);
// The link should not have been assigned the LTK.
EXPECT_FALSE(pairing_data().local_ltk.has_value() ||
pairing_data().peer_ltk.has_value());
}
// Test that LTK is not passed up to SecurityManager when local side requests
// bondable mode and peer requests non-bondable mode.
TEST_F(ResponderPairingTest, PeerRequestsNonBondableNoLTKCreated) {
UInt128 stk;
SetUpSecurityManager(IOCapability::kDisplayOnly, BondableMode::Bondable);
FastForwardToPhase3(&stk,
/*secure_connections=*/false,
SecurityLevel::kEncrypted,
0u, // remote keys
0u, // local keys
kMaxEncryptionKeySize,
BondableMode::NonBondable);
// The link should not have been assigned the LTK.
EXPECT_FALSE(pairing_data().local_ltk.has_value() ||
pairing_data().peer_ltk.has_value());
}
// Test that LTK is not generated and passed up to SecurityManager when both
// sides request non-bondable mode.
TEST_F(ResponderPairingTest, BothSidesRequestNonBondableNoLTKCreated) {
UInt128 stk;
SetUpSecurityManager(IOCapability::kDisplayOnly, BondableMode::NonBondable);
FastForwardToPhase3(&stk,
/*secure_connections=*/false,
SecurityLevel::kEncrypted,
0u, // remote keys
0u, // local keys
kMaxEncryptionKeySize,
BondableMode::NonBondable);
// The link should not have been assigned the LTK.
EXPECT_FALSE(pairing_data().local_ltk.has_value() ||
pairing_data().peer_ltk.has_value());
}
TEST_F(ResponderPairingTest, PairingRequestStartsPairingTimer) {
ReceivePairingRequest();
RunFor(kPairingTimeout);
EXPECT_TRUE(fake_chan()->link_error());
// Pairing should fail, but no callbacks should be notified because the
// pairing was initiated remotely, not through UpgradeSecurity locally
ASSERT_EQ(1, pairing_complete_count());
EXPECT_EQ(ToResult(HostError::kTimedOut), pairing_complete_status());
EXPECT_EQ(0, security_callback_count());
}
TEST_F(ResponderPairingTest,
RejectUnauthenticatedPairingInSecureConnectionsOnlyMode) {
SetUpSecurityManager(IOCapability::kKeyboardDisplay);
pairing()->set_security_mode(gap::LESecurityMode::SecureConnectionsOnly);
// In SC Only mode, SM should translate this "encrypted" request into a MITM
// requirement.
UpgradeSecurity(SecurityLevel::kEncrypted);
RunUntilIdle();
EXPECT_EQ(1, security_request_count());
EXPECT_EQ(AuthReq::kBondingFlag | AuthReq::kMITM | AuthReq::kSC,
security_request_payload());
// The peer has NoInputNoOutput IOCapabilities, thus cannot perform
// authenticated pairing.
ReceivePairingRequest(IOCapability::kNoInputNoOutput,
AuthReq::kBondingFlag | AuthReq::kSC);
RunUntilIdle();
EXPECT_EQ(1, pairing_failed_count());
EXPECT_EQ(1, security_callback_count());
EXPECT_EQ(ToResult(ErrorCode::kAuthenticationRequirements),
security_status());
EXPECT_EQ(1, pairing_complete_count());
EXPECT_EQ(security_status(), pairing_complete_status());
}
TEST_F(ResponderPairingTest,
RejectInsufficientKeySizeRequestInSecureConnectionsOnlyMode) {
SetUpSecurityManager(IOCapability::kKeyboardDisplay);
pairing()->set_security_mode(gap::LESecurityMode::SecureConnectionsOnly);
// The peer encryption key size is not kMaxEncryptionKeySize, thus does not
// meet the Secure Connections Only requirements.
ReceivePairingRequest(IOCapability::kDisplayYesNo,
AuthReq::kBondingFlag | AuthReq::kSC,
kMaxEncryptionKeySize - 1);
RunUntilIdle();
EXPECT_EQ(1, pairing_failed_count());
EXPECT_EQ(1, pairing_complete_count());
EXPECT_EQ(ToResult(ErrorCode::kEncryptionKeySize), pairing_complete_status());
}
// Tests that Secure Connections works as responder
TEST_F(ResponderPairingTest, SecureConnectionsWorks) {
// Must have DisplayYesNo IOC to generate Authenticated security per
// kExpectedSecurity
SetUpSecurityManager(IOCapability::kDisplayYesNo);
UInt128 ltk_bytes;
const SecurityProperties kExpectedSecurity(SecurityLevel::kAuthenticated,
kMaxEncryptionKeySize,
/*secure_connections=*/true);
FastForwardToPhase3(
&ltk_bytes, /*secure_connections=*/true, kExpectedSecurity.level());
const LTK kExpectedLtk(kExpectedSecurity, hci_spec::LinkKey(ltk_bytes, 0, 0));
ASSERT_TRUE(fake_link()->ltk());
EXPECT_EQ(kExpectedLtk.key(), fake_link()->ltk());
// Pairing should succeed with the LTK as the SC pairing is bondable, even
// though no keys need to be distributed in Phase 3.
EXPECT_EQ(1, pairing_data_callback_count());
EXPECT_TRUE(local_ltk().has_value());
EXPECT_EQ(kExpectedLtk, local_ltk());
EXPECT_EQ(local_ltk(), peer_ltk());
EXPECT_FALSE(irk());
EXPECT_FALSE(identity());
EXPECT_FALSE(csrk());
// Should have been called at least once to determine local identity
// availability.
EXPECT_NE(0, local_id_info_callback_count());
// Pairing should complete successfully
EXPECT_EQ(1, pairing_complete_count());
EXPECT_EQ(0, pairing_failed_count());
EXPECT_EQ(fit::ok(), pairing_complete_status());
// No callbacks are notified as the peer started this pairing, not a call to
// UpgradeSecurity.
EXPECT_EQ(0, security_callback_count());
EXPECT_EQ(0, id_info_count());
EXPECT_EQ(0, id_addr_info_count());
EXPECT_EQ(kExpectedSecurity, pairing()->security());
// The security properties should have been updated to match the LTK.
EXPECT_EQ(1, new_sec_props_count());
EXPECT_EQ(pairing()->security(), new_sec_props());
ASSERT_TRUE(fake_link()->ltk());
}
} // namespace
} // namespace bt::sm