blob: 4d7fbc291913af147d7536a205b2456394df2d3f [file] [log] [blame]
// Copyright 2020 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/phase_3.h"
#include <cstdint>
#include <memory>
#include <gtest/gtest.h>
#include "src/connectivity/bluetooth/core/bt-host/public/pw_bluetooth_sapphire/internal/host/common/byte_buffer.h"
#include "src/connectivity/bluetooth/core/bt-host/public/pw_bluetooth_sapphire/internal/host/common/device_address.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/common/uint128.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/l2cap/fake_channel_test.h"
#include "src/connectivity/bluetooth/core/bt-host/public/pw_bluetooth_sapphire/internal/host/sm/fake_phase_listener.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/test_helpers.h"
namespace bt::sm {
namespace {
using util::PacketSize;
const PairingFeatures kDefaultFeatures = {
.initiator = true,
.secure_connections = false,
.will_bond = true,
.generate_ct_key = std::optional<CrossTransportKeyAlgo>{std::nullopt},
.method = PairingMethod::kJustWorks,
.encryption_key_size = kMaxEncryptionKeySize,
.local_key_distribution =
KeyDistGen::kEncKey, // kEncKey because it lets Phase 3 "just work"
.remote_key_distribution = 0u};
const SecurityProperties kDefaultProperties(SecurityLevel::kEncrypted,
kMaxEncryptionKeySize,
/*secure_connections=*/false);
struct Phase3Args {
PairingFeatures features = kDefaultFeatures;
SecurityProperties le_props = kDefaultProperties;
};
const hci_spec::LinkKey kSampleLinkKey(
/*value=*/UInt128{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16},
/*rand=*/0x1234,
/*ediv=*/0x5678);
const DeviceAddress kSampleDeviceAddress(DeviceAddress::Type::kLEPublic, {1});
class Phase3Test : public l2cap::testing::FakeChannelTest {
public:
Phase3Test() = default;
~Phase3Test() override = default;
pw::async::HeapDispatcher& heap_dispatcher() { return heap_dispatcher_; }
protected:
void SetUp() override { NewPhase3(); }
void TearDown() override { phase_3_ = nullptr; }
void NewPhase3(Phase3Args phase_args = Phase3Args(),
bt::LinkType ll_type = bt::LinkType::kLE) {
l2cap::ChannelId cid = ll_type == bt::LinkType::kLE ? l2cap::kLESMPChannelId
: l2cap::kSMPChannelId;
ChannelOptions options(cid);
options.link_type = ll_type;
listener_ = std::make_unique<FakeListener>();
fake_chan_ = CreateFakeChannel(options);
sm_chan_ = std::make_unique<PairingChannel>(fake_chan_->GetWeakPtr());
auto role =
phase_args.features.initiator ? Role::kInitiator : Role::kResponder;
phase_3_ = std::make_unique<Phase3>(sm_chan_->GetWeakPtr(),
listener_->as_weak_ptr(),
role,
phase_args.features,
phase_args.le_props,
[this](PairingData pairing_results) {
phase_3_complete_count_++;
pairing_data_ = pairing_results;
});
}
auto Make128BitCmd(Code cmd_code, const UInt128& value) {
StaticByteBuffer<PacketSize<UInt128>()> buffer;
PacketWriter writer(cmd_code, &buffer);
*writer.mutable_payload<UInt128>() = value;
return buffer;
}
void Receive128BitCmd(Code cmd_code, const UInt128& value) {
fake_chan()->Receive(Make128BitCmd(cmd_code, value));
}
auto MakeCentralIdentification(uint64_t random, uint16_t ediv) {
StaticByteBuffer<PacketSize<CentralIdentificationParams>()> buffer;
PacketWriter writer(kCentralIdentification, &buffer);
auto* params = writer.mutable_payload<CentralIdentificationParams>();
params->ediv = htole16(ediv);
params->rand = htole64(random);
return buffer;
}
void ReceiveCentralIdentification(uint64_t random, uint16_t ediv) {
fake_chan()->Receive(MakeCentralIdentification(random, ediv));
}
auto MakeIdentityAddress(const DeviceAddress& address) {
StaticByteBuffer<PacketSize<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();
return buffer;
}
void ReceiveIdentityAddress(const DeviceAddress& address) {
fake_chan()->Receive(MakeIdentityAddress(address));
}
static std::pair<Code, UInt128> ExtractCodeAnd128BitCmd(ByteBufferPtr sdu) {
BT_ASSERT_MSG(sdu, "Tried to ExtractCodeAnd128BitCmd from nullptr in test");
auto maybe_reader = ValidPacketReader::ParseSdu(sdu);
BT_ASSERT_MSG(maybe_reader.is_ok(),
"Tried to ExtractCodeAnd128BitCmd from invalid SMP packet");
return {maybe_reader.value().code(),
maybe_reader.value().payload<UInt128>()};
}
static void ExpectEncryptionInfo(
ByteBufferPtr sdu,
std::optional<EncryptionInformationParams>* out_ltk_bytes,
std::optional<CentralIdentificationParams>* out_central_id) {
fit::result<ErrorCode, ValidPacketReader> reader =
ValidPacketReader::ParseSdu(sdu);
ASSERT_TRUE(reader.is_ok());
if (reader.value().code() == kEncryptionInformation) {
*out_ltk_bytes = reader.value().payload<EncryptionInformationParams>();
} else if (reader.value().code() == kCentralIdentification) {
*out_central_id = reader.value().payload<CentralIdentificationParams>();
} else {
ADD_FAILURE() << "Only expected LTK packets";
}
}
static void ExpectIdentity(
ByteBufferPtr sdu,
std::optional<IRK>* out_irk,
std::optional<IdentityAddressInformationParams>* out_id_address) {
fit::result<ErrorCode, ValidPacketReader> reader =
ValidPacketReader::ParseSdu(sdu);
ASSERT_TRUE(reader.is_ok());
if (reader.value().code() == kIdentityInformation) {
*out_irk = reader.value().payload<IRK>();
} else if (reader.value().code() == kIdentityAddressInformation) {
*out_id_address =
reader.value().payload<IdentityAddressInformationParams>();
} else {
ADD_FAILURE() << "Only expected identity information packets";
}
}
void DestroyPhase3() { phase_3_.reset(nullptr); }
l2cap::testing::FakeChannel* fake_chan() const { return fake_chan_.get(); }
Phase3* phase_3() { return phase_3_.get(); }
FakeListener* listener() { return listener_.get(); }
int phase_3_complete_count() const { return phase_3_complete_count_; }
const PairingData& pairing_data() const { return pairing_data_; }
private:
std::unique_ptr<FakeListener> listener_;
std::unique_ptr<l2cap::testing::FakeChannel> fake_chan_;
std::unique_ptr<PairingChannel> sm_chan_;
std::unique_ptr<Phase3> phase_3_;
int phase_3_complete_count_ = 0;
PairingData pairing_data_;
pw::async::HeapDispatcher heap_dispatcher_{dispatcher()};
BT_DISALLOW_COPY_AND_ASSIGN_ALLOW_MOVE(Phase3Test);
};
using Phase3DeathTest = Phase3Test;
TEST_F(Phase3DeathTest, NoLocalLtkDistributionDuringSecureConnections) {
Phase3Args args;
args.features.secure_connections = true;
args.features.local_key_distribution = KeyDistGen::kEncKey;
ASSERT_DEATH_IF_SUPPORTED(NewPhase3(args), ".*Secure Connections.*");
}
TEST_F(Phase3DeathTest, NoRemoteLtkDistributionDuringSecureConnections) {
Phase3Args args;
args.features.secure_connections = true;
args.features.remote_key_distribution = KeyDistGen::kEncKey;
ASSERT_DEATH_IF_SUPPORTED(NewPhase3(args), ".*Secure Connections.*");
}
TEST_F(Phase3DeathTest, CannotDistributeKeysOnUnencryptedChannel) {
Phase3Args args;
args.le_props = SecurityProperties(SecurityLevel::kNoSecurity,
kMaxEncryptionKeySize,
/*secure_connections=*/false);
ASSERT_DEATH_IF_SUPPORTED(NewPhase3(args), ".*NoSecurity.*");
}
TEST_F(Phase3DeathTest, Phase3MustDistributeKeys) {
Phase3Args args;
args.features.remote_key_distribution = args.features.local_key_distribution =
0;
// Phase 3 should only be instantiated if there are keys to distribute
ASSERT_DEATH_IF_SUPPORTED(NewPhase3(args), ".*HasKeysToDistribute.*");
}
// The peer sends EDIV and Rand before LTK.
TEST_F(Phase3Test, EncryptionInformationReceivedTwice) {
Phase3Args args;
args.features.initiator = true;
args.features.remote_key_distribution = KeyDistGen::kEncKey;
NewPhase3(args);
ByteBufferPtr sent = nullptr;
fake_chan()->SetSendCallback(
[&](ByteBufferPtr sdu) { sent = std::move(sdu); }, dispatcher());
phase_3()->Start();
Receive128BitCmd(kEncryptionInformation, UInt128());
RunUntilIdle();
ASSERT_FALSE(sent);
// When we receive the second Encryption Info packet, we should respond with
// pairing failed, as a device should only ever send one Encryption Info
// packet in Phase 3.
const auto kEncryptionInformationCmd =
Make128BitCmd(kEncryptionInformation, UInt128());
const StaticByteBuffer<PacketSize<ErrorCode>()> kExpectedFailure{
kPairingFailed, ErrorCode::kUnspecifiedReason};
ASSERT_TRUE(ReceiveAndExpect(kEncryptionInformationCmd, kExpectedFailure));
EXPECT_EQ(1, listener()->pairing_error_count());
EXPECT_EQ(Error(ErrorCode::kUnspecifiedReason), listener()->last_error());
}
// The peer sends EDIV and Rand before LTK.
TEST_F(Phase3Test, CentralIdentificationReceivedInWrongOrder) {
Phase3Args args;
args.features.initiator = true;
args.features.remote_key_distribution = KeyDistGen::kEncKey;
NewPhase3(args);
phase_3()->Start();
// When we receive the second Encryption Info packet, we should respond with
// pairing failed, as a device should only ever send one Encryption Info
// packet in Phase 3.
StaticByteBuffer<PacketSize<CentralIdentificationParams>()> central_id_packet;
PacketWriter p(kCentralIdentification, &central_id_packet);
*p.mutable_payload<CentralIdentificationParams>() =
Random<CentralIdentificationParams>();
const StaticByteBuffer<PacketSize<ErrorCode>()> kExpectedFailure{
kPairingFailed, ErrorCode::kUnspecifiedReason};
ASSERT_TRUE(ReceiveAndExpect(central_id_packet, kExpectedFailure));
EXPECT_EQ(1, listener()->pairing_error_count());
EXPECT_EQ(Error(ErrorCode::kUnspecifiedReason), listener()->last_error());
}
// The peer sends the sample Rand from the specification doc
TEST_F(Phase3Test, ReceiveExampleLtkAborts) {
Phase3Args args;
args.features.initiator = true;
args.features.remote_key_distribution = KeyDistGen::kEncKey;
NewPhase3(args);
// Sample data from spec V5.0 Vol. 6 Part C Section 1
const UInt128 kLtkSample = {0xBF,
0x01,
0xFB,
0x9D,
0x4E,
0xF3,
0xBC,
0x36,
0xD8,
0x74,
0xF5,
0x39,
0x41,
0x38,
0x68,
0x4C};
phase_3()->Start();
// Pairing should abort when receiving sample LTK data
const auto kEncryptionInformationCmd =
Make128BitCmd(kEncryptionInformation, kLtkSample);
const StaticByteBuffer<PacketSize<ErrorCode>()> kExpectedFailure{
kPairingFailed, ErrorCode::kUnspecifiedReason};
ASSERT_TRUE(ReceiveAndExpect(kEncryptionInformationCmd, kExpectedFailure));
EXPECT_EQ(1, listener()->pairing_error_count());
EXPECT_EQ(Error(ErrorCode::kUnspecifiedReason), listener()->last_error());
}
// The peer sends the sample LTK from the specification doc
TEST_F(Phase3Test, ReceiveExampleRandAborts) {
Phase3Args args;
args.features.initiator = true;
args.features.remote_key_distribution = KeyDistGen::kEncKey;
NewPhase3(args);
// Sample data from spec V5.0 Vol. 6 Part C Section 1
const uint64_t kRandSample = 0xABCDEF1234567890;
const uint16_t kEDiv = 20;
phase_3()->Start();
// Pairing should still proceed after accepting the LTK
Receive128BitCmd(kEncryptionInformation, UInt128());
RunUntilIdle();
ASSERT_EQ(0, listener()->pairing_error_count());
ASSERT_EQ(0, phase_3_complete_count());
// We disallow pairing with spec sample values as using known values for
// encryption parameters is inherently unsafe.
const auto kCentralIdentificationCmd =
MakeCentralIdentification(kRandSample, kEDiv);
const StaticByteBuffer<PacketSize<ErrorCode>()> kExpectedFailure{
kPairingFailed, ErrorCode::kUnspecifiedReason};
ASSERT_TRUE(ReceiveAndExpect(kCentralIdentificationCmd, kExpectedFailure));
EXPECT_EQ(1, listener()->pairing_error_count());
EXPECT_EQ(Error(ErrorCode::kUnspecifiedReason), listener()->last_error());
}
// The peer sends us an LTK that is longer than the negotiated maximum key size
TEST_F(Phase3Test, ReceiveTooLongLTK) {
Phase3Args args;
args.features.initiator = true;
args.features.remote_key_distribution = KeyDistGen::kEncKey;
args.features.encryption_key_size = 8;
NewPhase3(args);
// Ltk with 9 bytes set is longer than the negotiated max of 8 bytes.
const UInt128 kTooLongLtk{1, 2, 3, 4, 5, 6, 7, 8, 9};
// Pairing should abort when receiving sample LTK data
const auto kEncryptionInformationCmd =
Make128BitCmd(kEncryptionInformation, kTooLongLtk);
const StaticByteBuffer<PacketSize<ErrorCode>()> kExpectedFailure{
kPairingFailed, ErrorCode::kInvalidParameters};
ASSERT_TRUE(ReceiveAndExpect(kEncryptionInformationCmd, kExpectedFailure));
EXPECT_EQ(Error(ErrorCode::kInvalidParameters), listener()->last_error());
}
TEST_F(Phase3Test, CentralIdentificationReceivedTwice) {
Phase3Args args;
args.features.initiator = true;
// The local device must expect both an Encryption and ID key from the peer,
// or it would start sending messages after the first Central ID, which is not
// the behavior checked in this test.
args.features.remote_key_distribution =
KeyDistGen::kEncKey | KeyDistGen::kIdKey;
NewPhase3(args);
constexpr uint16_t kEdiv = 1;
constexpr uint64_t kRand = 2;
phase_3()->Start();
// Send duplicate central identification. If Phase 3 receives multiple Central
// Identification commands before completing, it should abort the pairing.
Receive128BitCmd(kEncryptionInformation, UInt128());
const auto kCentralIdentificationCmd =
MakeCentralIdentification(kRand, kEdiv);
fake_chan()->Receive(kCentralIdentificationCmd);
const StaticByteBuffer<PacketSize<ErrorCode>()> kExpectedFailure{
kPairingFailed, ErrorCode::kUnspecifiedReason};
ASSERT_TRUE(ReceiveAndExpect(kCentralIdentificationCmd, kExpectedFailure));
EXPECT_EQ(1, listener()->pairing_error_count());
}
// Pairing completes after obtaining encryption information only.
TEST_F(Phase3Test, InitiatorReceivesEncKey) {
const LTK kExpectedLtk = LTK(kDefaultProperties, kSampleLinkKey);
Phase3Args args;
args.features.initiator = true;
args.features.secure_connections = false;
args.features.local_key_distribution = 0u;
args.features.remote_key_distribution = KeyDistGen::kEncKey;
args.le_props = kExpectedLtk.security();
NewPhase3(args);
size_t sent_msg_count = 0;
fake_chan()->SetSendCallback(
[&](ByteBufferPtr /*ignore*/) { sent_msg_count++; }, dispatcher());
phase_3()->Start();
Receive128BitCmd(kEncryptionInformation, kExpectedLtk.key().value());
ReceiveCentralIdentification(kExpectedLtk.key().rand(),
kExpectedLtk.key().ediv());
RunUntilIdle();
// We were not supposed to distribute any keys in Phase 3
EXPECT_EQ(0u, sent_msg_count);
// Pairing should have succeeded
EXPECT_EQ(0, listener()->pairing_error_count());
EXPECT_EQ(1, phase_3_complete_count());
ASSERT_TRUE(pairing_data().peer_ltk.has_value());
EXPECT_EQ(kExpectedLtk, *pairing_data().peer_ltk);
}
TEST_F(Phase3Test, InitiatorSendsLocalIdKey) {
Phase3Args args;
args.features.initiator = true;
args.features.local_key_distribution = KeyDistGen::kIdKey;
args.features.remote_key_distribution = 0u;
args.le_props = kDefaultProperties;
NewPhase3(args);
std::optional<IRK> irk = std::nullopt;
std::optional<IdentityAddressInformationParams> identity_addr = std::nullopt;
fake_chan()->SetSendCallback(
[&](ByteBufferPtr sdu) {
ExpectIdentity(std::move(sdu), &irk, &identity_addr);
},
dispatcher());
IdentityInfo kLocalIdentity{.irk = Random<IRK>(),
.address = kSampleDeviceAddress};
listener()->set_identity_info(kLocalIdentity);
phase_3()->Start();
RunUntilIdle();
// Local ID Info should be sent to the peer & pairing should be complete
ASSERT_TRUE(irk.has_value());
ASSERT_EQ(kLocalIdentity.irk, *irk);
ASSERT_TRUE(identity_addr.has_value());
ASSERT_EQ(kLocalIdentity.address.value(), identity_addr->bd_addr);
EXPECT_EQ(1, phase_3_complete_count());
// We should have stored no PairingData, as the peer did not send us any
ASSERT_FALSE(pairing_data().identity_address.has_value());
ASSERT_FALSE(pairing_data().irk.has_value());
ASSERT_FALSE(pairing_data().peer_ltk.has_value());
ASSERT_FALSE(pairing_data().local_ltk.has_value());
}
TEST_F(Phase3Test, InitiatorSendsEncKey) {
Phase3Args args;
args.features.initiator = true;
args.features.local_key_distribution = KeyDistGen::kEncKey;
args.features.remote_key_distribution = 0u;
args.le_props = kDefaultProperties;
NewPhase3(args);
std::optional<EncryptionInformationParams> ltk_bytes = std::nullopt;
std::optional<CentralIdentificationParams> central_id = std::nullopt;
fake_chan()->SetSendCallback(
[&](ByteBufferPtr sdu) {
ExpectEncryptionInfo(std::move(sdu), &ltk_bytes, &central_id);
},
dispatcher());
phase_3()->Start();
RunUntilIdle();
// Local LTK should be sent to the peer & pairing should be complete
EXPECT_EQ(1, phase_3_complete_count());
ASSERT_TRUE(ltk_bytes.has_value());
ASSERT_TRUE(central_id.has_value());
ASSERT_TRUE(pairing_data().local_ltk.has_value());
EXPECT_EQ(pairing_data().local_ltk->key(),
hci_spec::LinkKey(*ltk_bytes, central_id->rand, central_id->ediv));
}
TEST_F(Phase3Test, InitiatorReceivesThenSendsEncKey) {
const LTK kExpectedLtk = LTK(kDefaultProperties, kSampleLinkKey);
Phase3Args args;
args.features.initiator = true;
args.features.local_key_distribution = KeyDistGen::kEncKey;
args.features.remote_key_distribution = KeyDistGen::kEncKey;
args.le_props = kExpectedLtk.security();
NewPhase3(args);
std::optional<EncryptionInformationParams> ltk_bytes = std::nullopt;
std::optional<CentralIdentificationParams> central_id = std::nullopt;
fake_chan()->SetSendCallback(
[&](ByteBufferPtr sdu) {
ExpectEncryptionInfo(std::move(sdu), &ltk_bytes, &central_id);
},
dispatcher());
phase_3()->Start();
Receive128BitCmd(kEncryptionInformation, kExpectedLtk.key().value());
ReceiveCentralIdentification(kExpectedLtk.key().rand(),
kExpectedLtk.key().ediv());
RunUntilIdle();
// Local LTK should be sent to the peer & pairing should be complete
EXPECT_EQ(0, listener()->pairing_error_count());
EXPECT_EQ(1, phase_3_complete_count());
ASSERT_TRUE(ltk_bytes.has_value());
ASSERT_TRUE(central_id.has_value());
ASSERT_TRUE(pairing_data().local_ltk.has_value());
EXPECT_EQ(pairing_data().local_ltk->key(),
hci_spec::LinkKey(*ltk_bytes, central_id->rand, central_id->ediv));
ASSERT_TRUE(pairing_data().peer_ltk.has_value());
EXPECT_EQ(kExpectedLtk, *pairing_data().peer_ltk);
}
// Tests that pairing aborts if the local ID key doesn't exist but we'd already
// agreed to send it.
TEST_F(Phase3Test, AbortsIfLocalIdKeyIsRemoved) {
Phase3Args args;
args.features.local_key_distribution = KeyDistGen::kIdKey;
NewPhase3(args);
listener()->set_identity_info(std::nullopt);
(void)heap_dispatcher().Post(
[this](pw::async::Context /*ctx*/, pw::Status status) {
if (status.ok()) {
phase_3()->Start();
}
});
const StaticByteBuffer<PacketSize<ErrorCode>()> kExpectedFailure{
kPairingFailed, ErrorCode::kUnspecifiedReason};
ASSERT_TRUE(Expect(kExpectedFailure));
EXPECT_EQ(1, listener()->pairing_error_count());
EXPECT_EQ(Error(ErrorCode::kUnspecifiedReason), listener()->last_error());
}
TEST_F(Phase3Test, IRKReceivedTwice) {
Phase3Args args;
args.features.remote_key_distribution = KeyDistGen::kIdKey;
NewPhase3(args);
Receive128BitCmd(kIdentityInformation, UInt128());
RunUntilIdle();
// Should be waiting for identity address.
EXPECT_EQ(0, listener()->pairing_error_count());
EXPECT_EQ(0, phase_3_complete_count());
// Send an IRK again. This should cause pairing to fail.
const auto kIdentityInformationCmd =
Make128BitCmd(kIdentityInformation, UInt128());
const StaticByteBuffer<PacketSize<ErrorCode>()> kExpectedFailure{
kPairingFailed, ErrorCode::kUnspecifiedReason};
ASSERT_TRUE(ReceiveAndExpect(kIdentityInformationCmd, kExpectedFailure));
EXPECT_EQ(1, listener()->pairing_error_count());
}
// The responder sends its identity address before sending its IRK.
TEST_F(Phase3Test, IdentityAddressReceivedInWrongOrder) {
Phase3Args args;
args.features.remote_key_distribution = KeyDistGen::kIdKey;
NewPhase3(args);
const auto kIdentityAddressCmd = MakeIdentityAddress(kSampleDeviceAddress);
const StaticByteBuffer<PacketSize<ErrorCode>()> kExpectedFailure{
kPairingFailed, ErrorCode::kUnspecifiedReason};
ASSERT_TRUE(ReceiveAndExpect(kIdentityAddressCmd, kExpectedFailure));
EXPECT_EQ(1, listener()->pairing_error_count());
}
TEST_F(Phase3Test, IdentityAddressReceivedTwice) {
Phase3Args args;
// We tell Phase 3 to expect the sign key even though we don't yet support it
// so that pairing does not complete after receiving the first IdentityAddress
args.features.remote_key_distribution =
KeyDistGen::kIdKey | KeyDistGen::kSignKey;
NewPhase3(args);
phase_3()->Start();
Receive128BitCmd(kIdentityInformation, UInt128());
ReceiveIdentityAddress(kSampleDeviceAddress);
RunUntilIdle();
// Should not complete as we still have not obtained all the requested keys.
EXPECT_EQ(0, listener()->pairing_error_count());
EXPECT_EQ(0, phase_3_complete_count());
// Send the IdentityAddress again. This should cause pairing to fail.
const auto kIdentityAddressCmd = MakeIdentityAddress(kSampleDeviceAddress);
const StaticByteBuffer<PacketSize<ErrorCode>()> kExpectedFailure{
kPairingFailed, ErrorCode::kUnspecifiedReason};
ASSERT_TRUE(ReceiveAndExpect(kIdentityAddressCmd, kExpectedFailure));
EXPECT_EQ(1, listener()->pairing_error_count());
}
TEST_F(Phase3Test, BadIdentityAddressType) {
Phase3Args args;
args.features.remote_key_distribution = KeyDistGen::kIdKey;
NewPhase3(args);
phase_3()->Start();
// Receive a generic IdentityInfo packet so we are prepared for the Identity
// Addr pacekt
Receive128BitCmd(kIdentityInformation, UInt128());
StaticByteBuffer<PacketSize<IdentityAddressInformationParams>()> addr;
PacketWriter writer(kIdentityAddressInformation, &addr);
auto* params = writer.mutable_payload<IdentityAddressInformationParams>();
// The only valid address type values are 0 or 1 (V5.0 Vol. 3 Part H 3.6.5)
const uint8_t kInvalidAddrType = 0xFF;
params->type = *reinterpret_cast<const AddressType*>(&kInvalidAddrType);
params->bd_addr = DeviceAddressBytes({1, 2, 3, 4, 5, 6});
const StaticByteBuffer<PacketSize<ErrorCode>()> kExpectedFailure{
kPairingFailed, ErrorCode::kInvalidParameters};
ASSERT_TRUE(ReceiveAndExpect(addr, kExpectedFailure));
EXPECT_EQ(1, listener()->pairing_error_count());
}
// Pairing completes after obtaining identity information only.
TEST_F(Phase3Test, InitiatorCompleteWithIdKey) {
const Key kIrk =
Key(kDefaultProperties, {1, 2, 3, 4, 5, 6, 7, 8, 7, 6, 5, 4, 3, 2, 1, 0});
Phase3Args args;
args.features.local_key_distribution = 0u;
args.features.remote_key_distribution = KeyDistGen::kIdKey;
args.le_props = kIrk.security();
NewPhase3(args);
size_t sent_msg_count = 0;
fake_chan()->SetSendCallback(
[&](ByteBufferPtr /*ignore*/) { sent_msg_count++; }, dispatcher());
phase_3()->Start();
Receive128BitCmd(kIdentityInformation, kIrk.value());
ReceiveIdentityAddress(kSampleDeviceAddress);
RunUntilIdle();
// We were not supposed to distribute any keys in Phase 3
EXPECT_EQ(0u, sent_msg_count);
// Pairing should have succeeded
EXPECT_EQ(0, listener()->pairing_error_count());
EXPECT_EQ(1, phase_3_complete_count());
ASSERT_TRUE(pairing_data().irk.has_value());
EXPECT_EQ(kIrk, *pairing_data().irk);
}
// Pairing completes after obtaining identity information only.
TEST_F(Phase3Test, InitiatorCompleteWithEncAndIdKey) {
const LTK kExpectedLtk = LTK(kDefaultProperties, kSampleLinkKey);
const Key kIrk =
Key(kDefaultProperties, {1, 2, 3, 4, 5, 6, 7, 8, 7, 6, 5, 4, 3, 2, 1, 0});
Phase3Args args;
args.features.initiator = true;
args.features.secure_connections = false;
args.features.local_key_distribution = 0u;
args.features.remote_key_distribution =
KeyDistGen::kEncKey | KeyDistGen::kIdKey;
args.le_props = kExpectedLtk.security();
NewPhase3(args);
size_t sent_msg_count = 0;
fake_chan()->SetSendCallback(
[&](ByteBufferPtr /*ignore*/) { sent_msg_count++; }, dispatcher());
phase_3()->Start();
Receive128BitCmd(kEncryptionInformation, kExpectedLtk.key().value());
ReceiveCentralIdentification(kExpectedLtk.key().rand(),
kExpectedLtk.key().ediv());
Receive128BitCmd(kIdentityInformation, kIrk.value());
ReceiveIdentityAddress(kSampleDeviceAddress);
RunUntilIdle();
// We were not supposed to distribute any keys in Phase 3
EXPECT_EQ(0u, sent_msg_count);
// Pairing should have succeeded
EXPECT_EQ(0, listener()->pairing_error_count());
EXPECT_EQ(1, phase_3_complete_count());
ASSERT_TRUE(pairing_data().peer_ltk.has_value());
EXPECT_EQ(kExpectedLtk, *pairing_data().peer_ltk);
ASSERT_TRUE(pairing_data().irk.has_value());
EXPECT_EQ(kIrk, *pairing_data().irk);
}
TEST_F(Phase3Test, ResponderLTKDistributionNoRemoteKeys) {
Phase3Args args;
args.features.initiator = false;
args.features.secure_connections = false;
args.features.local_key_distribution = KeyDistGen::kEncKey;
args.features.remote_key_distribution = 0u;
args.le_props = kDefaultProperties;
NewPhase3(args);
std::optional<EncryptionInformationParams> ltk_bytes = std::nullopt;
std::optional<CentralIdentificationParams> central_id = std::nullopt;
fake_chan()->SetSendCallback(
[&](ByteBufferPtr sdu) {
ExpectEncryptionInfo(std::move(sdu), &ltk_bytes, &central_id);
},
dispatcher());
phase_3()->Start();
RunUntilIdle();
// We should have sent both the Encryption Info and Central ID to the peer
ASSERT_TRUE(ltk_bytes.has_value());
ASSERT_TRUE(central_id.has_value());
// We should have notified the callback with the LTK
ASSERT_TRUE(pairing_data().local_ltk.has_value());
// The LTK we sent to the peer should match the one we notified callbacks with
ASSERT_EQ(hci_spec::LinkKey(*ltk_bytes, central_id->rand, central_id->ediv),
pairing_data().local_ltk->key());
}
TEST_F(Phase3Test, ResponderAcceptsInitiatorEncKey) {
const LTK kExpectedLtk = LTK(kDefaultProperties, kSampleLinkKey);
Phase3Args args;
args.features.initiator = false;
args.features.secure_connections = false;
args.features.local_key_distribution = 0u;
args.features.remote_key_distribution = KeyDistGen::kEncKey;
args.le_props = kExpectedLtk.security();
NewPhase3(args);
size_t sent_msg_count = 0;
fake_chan()->SetSendCallback(
[&](ByteBufferPtr /*ignore*/) { sent_msg_count++; }, dispatcher());
phase_3()->Start();
Receive128BitCmd(kEncryptionInformation, kExpectedLtk.key().value());
ReceiveCentralIdentification(kExpectedLtk.key().rand(),
kExpectedLtk.key().ediv());
RunUntilIdle();
// We were not supposed to distribute any keys in Phase 3
EXPECT_EQ(0u, sent_msg_count);
// Pairing should have succeeded
EXPECT_EQ(0, listener()->pairing_error_count());
EXPECT_EQ(1, phase_3_complete_count());
ASSERT_TRUE(pairing_data().peer_ltk.has_value());
EXPECT_EQ(kExpectedLtk, *pairing_data().peer_ltk);
}
TEST_F(Phase3Test, ResponderLTKDistributionWithRemoteKeys) {
const Key kIrk =
Key(kDefaultProperties, {1, 2, 3, 4, 5, 6, 7, 8, 7, 6, 5, 4, 3, 2, 1, 0});
Phase3Args args;
args.features.initiator = false;
args.features.secure_connections = false;
args.features.local_key_distribution = KeyDistGen::kEncKey;
args.features.remote_key_distribution = KeyDistGen::kIdKey;
args.le_props = kDefaultProperties;
NewPhase3(args);
std::optional<EncryptionInformationParams> ltk_bytes = std::nullopt;
std::optional<CentralIdentificationParams> central_id = std::nullopt;
fake_chan()->SetSendCallback(
[&](ByteBufferPtr sdu) {
ExpectEncryptionInfo(std::move(sdu), &ltk_bytes, &central_id);
},
dispatcher());
phase_3()->Start();
RunUntilIdle();
// We should have sent the Encryption Info and Central ID & be waiting for the
// peer's IRK
ASSERT_TRUE(ltk_bytes.has_value());
ASSERT_TRUE(central_id.has_value());
ASSERT_EQ(0, phase_3_complete_count());
const hci_spec::LinkKey kExpectedKey =
hci_spec::LinkKey(*ltk_bytes, central_id->rand, central_id->ediv);
// Reset ltk_bytes & central_id to verify that we don't send any further
// messages
ltk_bytes.reset();
central_id.reset();
Receive128BitCmd(kIdentityInformation, kIrk.value());
ReceiveIdentityAddress(kSampleDeviceAddress);
RunUntilIdle();
ASSERT_FALSE(ltk_bytes.has_value());
ASSERT_FALSE(central_id.has_value());
// We should have notified the callback with the LTK & IRK
ASSERT_TRUE(pairing_data().local_ltk.has_value());
ASSERT_TRUE(pairing_data().irk.has_value());
// The LTK we sent to the peer should be equal to the one provided to the
// callback.
ASSERT_EQ(kExpectedKey, pairing_data().local_ltk->key());
// The IRK we notified the callback with should match the one we sent.
ASSERT_EQ(kIrk, *pairing_data().irk);
}
// Locally generated ltk length should match max key length specified
TEST_F(Phase3Test, ResponderLocalLTKMaxLength) {
const uint16_t kNegotiatedMaxKeySize = 7;
Phase3Args args;
args.features.initiator = false;
args.features.encryption_key_size = kNegotiatedMaxKeySize;
args.features.local_key_distribution = KeyDistGen::kEncKey;
args.features.remote_key_distribution = 0u;
NewPhase3(args);
std::optional<EncryptionInformationParams> ltk_bytes = std::nullopt;
std::optional<CentralIdentificationParams> central_id = std::nullopt;
fake_chan()->SetSendCallback(
[&](ByteBufferPtr sdu) {
ExpectEncryptionInfo(std::move(sdu), &ltk_bytes, &central_id);
},
dispatcher());
phase_3()->Start();
RunUntilIdle();
// Local LTK, EDiv, and Rand should be sent to the peer & listener should be
// notified.
ASSERT_TRUE(ltk_bytes.has_value());
ASSERT_TRUE(central_id.has_value());
EXPECT_EQ(1, phase_3_complete_count());
EXPECT_EQ(hci_spec::LinkKey(*ltk_bytes, central_id->rand, central_id->ediv),
pairing_data().local_ltk->key());
// Ensure that most significant (16 - kNegotiatedMaxKeySize) bytes are zero.
auto ltk = pairing_data().local_ltk->key().value();
for (auto i = kNegotiatedMaxKeySize; i < ltk.size(); i++) {
EXPECT_TRUE(ltk[i] == 0);
}
}
TEST_F(Phase3Test, ResponderLocalIdKeyDistributionWithRemoteKeys) {
Phase3Args args;
args.features.initiator = false;
args.features.local_key_distribution = KeyDistGen::kIdKey;
args.features.remote_key_distribution = KeyDistGen::kIdKey;
args.le_props = kDefaultProperties;
NewPhase3(args);
std::optional<IRK> irk = std::nullopt;
std::optional<IdentityAddressInformationParams> identity_addr = std::nullopt;
fake_chan()->SetSendCallback(
[&](ByteBufferPtr sdu) {
ExpectIdentity(std::move(sdu), &irk, &identity_addr);
},
dispatcher());
IdentityInfo kLocalIdentity{.irk = Random<IRK>(),
.address = kSampleDeviceAddress};
listener()->set_identity_info(kLocalIdentity);
phase_3()->Start();
RunUntilIdle();
// Local ID Info should be sent to the peer & we should be waiting for the
// peer's ID info
ASSERT_TRUE(irk.has_value());
ASSERT_TRUE(identity_addr.has_value());
EXPECT_EQ(0, phase_3_complete_count());
EXPECT_EQ(kLocalIdentity.irk, *irk);
EXPECT_EQ(kLocalIdentity.address.value(), identity_addr->bd_addr);
// Ensure that most significant (16 - kNegotiatedMaxKeySize) bytes are zero.
const Key kIrk(kDefaultProperties, Random<UInt128>());
const DeviceAddress kPeerAddr(DeviceAddress::Type::kLEPublic, {2});
Receive128BitCmd(kIdentityInformation, kIrk.value());
ReceiveIdentityAddress(kPeerAddr);
RunUntilIdle();
// Pairing should be complete with the peer's identity information.
ASSERT_EQ(1, phase_3_complete_count());
ASSERT_TRUE(pairing_data().irk.has_value());
EXPECT_EQ(kIrk, *pairing_data().irk);
ASSERT_TRUE(pairing_data().identity_address.has_value());
EXPECT_EQ(kPeerAddr, *pairing_data().identity_address);
}
TEST_F(Phase3Test, ReceivePairingFailed) {
Phase3Args args;
args.features.remote_key_distribution = KeyDistGen::kEncKey;
NewPhase3(args);
phase_3()->Start();
fake_chan()->Receive(
StaticByteBuffer{kPairingFailed, ErrorCode::kPairingNotSupported});
RunUntilIdle();
ASSERT_EQ(1, listener()->pairing_error_count());
EXPECT_EQ(Error(ErrorCode::kPairingNotSupported), listener()->last_error());
}
TEST_F(Phase3Test, MalformedCommand) {
Phase3Args args;
args.features.remote_key_distribution = KeyDistGen::kEncKey;
NewPhase3(args);
phase_3()->Start();
// The kEncryptionInformation packet is expected to have a 16 byte payload,
// not 1 byte.
const StaticByteBuffer<PacketSize<ErrorCode>()> kExpectedFailure{
kPairingFailed, ErrorCode::kInvalidParameters};
ReceiveAndExpect(StaticByteBuffer{kEncryptionInformation, 0x01},
kExpectedFailure);
ASSERT_EQ(1, listener()->pairing_error_count());
EXPECT_EQ(Error(ErrorCode::kInvalidParameters), listener()->last_error());
}
TEST_F(Phase3Test, UnexpectedOpCode) {
phase_3()->Start();
// The Security Request is not expected during Phase 3.
const StaticByteBuffer<PacketSize<ErrorCode>()> kExpectedFailure{
kPairingFailed, ErrorCode::kUnspecifiedReason};
ReceiveAndExpect(StaticByteBuffer{kSecurityRequest, AuthReq::kBondingFlag},
kExpectedFailure);
ASSERT_EQ(1, listener()->pairing_error_count());
EXPECT_EQ(Error(ErrorCode::kUnspecifiedReason), listener()->last_error());
}
} // namespace
} // namespace bt::sm