blob: 9de88ef72ebc5a1629b5e3dfc40aec4670bf263d [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 "phase_3.h"
#include <cstdint>
#include <memory>
#include <gtest/gtest.h>
#include "src/connectivity/bluetooth/core/bt-host/common/byte_buffer.h"
#include "src/connectivity/bluetooth/core/bt-host/common/device_address.h"
#include "src/connectivity/bluetooth/core/bt-host/common/random.h"
#include "src/connectivity/bluetooth/core/bt-host/common/test_helpers.h"
#include "src/connectivity/bluetooth/core/bt-host/common/uint128.h"
#include "src/connectivity/bluetooth/core/bt-host/hci-spec/link_key.h"
#include "src/connectivity/bluetooth/core/bt-host/hci/connection.h"
#include "src/connectivity/bluetooth/core/bt-host/l2cap/fake_channel_test.h"
#include "src/connectivity/bluetooth/core/bt-host/sm/fake_phase_listener.h"
#include "src/connectivity/bluetooth/core/bt-host/sm/packet.h"
#include "src/connectivity/bluetooth/core/bt-host/sm/smp.h"
#include "src/connectivity/bluetooth/core/bt-host/sm/types.h"
#include "src/connectivity/bluetooth/core/bt-host/sm/util.h"
#include "src/lib/fxl/memory/weak_ptr.h"
namespace bt::sm {
namespace {
using util::PacketSize;
// clang-format off
const PairingFeatures kDefaultFeatures(
true, // initiator
false, // secure_connections
true, // will_bond
std::optional<CrossTransportKeyAlgo>{std::nullopt},
PairingMethod::kJustWorks,
kMaxEncryptionKeySize, // encryption_key_size
KeyDistGen::kIdKey, // local_key_distribution
0u // remote_key_distribution
);
const SecurityProperties kDefaultProperties(
SecurityLevel::kEncrypted,
kMaxEncryptionKeySize,
false // Secure Connections
);
struct Phase3Args {
PairingFeatures features = kDefaultFeatures;
SecurityProperties le_props = kDefaultProperties;
};
const hci::LinkKey kSampleLinkKey(
UInt128{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}, // value
/* rand= */ 0x1234, /* ediv= */ 0x5678
);
// clang-format on
const DeviceAddress kSampleDeviceAddress(DeviceAddress::Type::kLEPublic, {1});
class SMP_Phase3Test : public l2cap::testing::FakeChannelTest {
public:
SMP_Phase3Test() = default;
~SMP_Phase3Test() override = default;
protected:
void SetUp() override { NewPhase3(); }
void TearDown() override { phase_3_ = nullptr; }
void NewPhase3(Phase3Args phase_args = Phase3Args(),
hci::Connection::LinkType ll_type = hci::Connection::LinkType::kLE) {
l2cap::ChannelId cid =
ll_type == hci::Connection::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_);
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 MakeMasterIdentification(uint64_t random, uint16_t ediv) {
StaticByteBuffer<PacketSize<MasterIdentificationParams>()> buffer;
PacketWriter writer(kMasterIdentification, &buffer);
auto* params = writer.mutable_payload<MasterIdentificationParams>();
params->ediv = htole16(ediv);
params->rand = htole64(random);
return buffer;
}
void ReceiveMasterIdentification(uint64_t random, uint16_t ediv) {
fake_chan()->Receive(MakeMasterIdentification(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) {
ZX_ASSERT_MSG(sdu, "Tried to ExtractCodeAnd128BitCmd from nullptr in test");
auto maybe_reader = ValidPacketReader::ParseSdu(sdu);
ZX_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<MasterIdentificationParams>* out_master_id) {
fit::result<ValidPacketReader, ErrorCode> 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() == kMasterIdentification) {
*out_master_id = reader.value().payload<MasterIdentificationParams>();
} 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<ValidPacketReader, ErrorCode> 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_;
fbl::RefPtr<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_;
DISALLOW_COPY_AND_ASSIGN_ALLOW_MOVE(SMP_Phase3Test);
};
using SMP_Phase3DeathTest = SMP_Phase3Test;
TEST_F(SMP_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(SMP_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(SMP_Phase3DeathTest, CannotDistributeKeysOnUnencryptedChannel) {
Phase3Args args;
args.le_props = SecurityProperties(SecurityLevel::kNoSecurity, kMaxEncryptionKeySize,
false /* secure connections */);
ASSERT_DEATH_IF_SUPPORTED(NewPhase3(args), ".*NoSecurity.*");
}
TEST_F(SMP_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(SMP_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());
RunLoopUntilIdle();
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());
ASSERT_TRUE(listener()->last_error().is_protocol_error());
EXPECT_EQ(ErrorCode::kUnspecifiedReason, listener()->last_error().protocol_error());
}
// The peer sends EDIV and Rand before LTK.
TEST_F(SMP_Phase3Test, MasterIdentificationReceivedInWrongOrder) {
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<MasterIdentificationParams>()> master_id_packet;
PacketWriter p(kMasterIdentification, &master_id_packet);
*p.mutable_payload<MasterIdentificationParams>() = Random<MasterIdentificationParams>();
const StaticByteBuffer<PacketSize<ErrorCode>()> kExpectedFailure{kPairingFailed,
ErrorCode::kUnspecifiedReason};
ASSERT_TRUE(ReceiveAndExpect(master_id_packet, kExpectedFailure));
EXPECT_EQ(1, listener()->pairing_error_count());
ASSERT_TRUE(listener()->last_error().is_protocol_error());
EXPECT_EQ(ErrorCode::kUnspecifiedReason, listener()->last_error().protocol_error());
}
// The peer sends the sample Rand from the specification doc
TEST_F(SMP_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());
ASSERT_TRUE(listener()->last_error().is_protocol_error());
EXPECT_EQ(ErrorCode::kUnspecifiedReason, listener()->last_error().protocol_error());
}
// The peer sends the sample LTK from the specification doc
TEST_F(SMP_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());
RunLoopUntilIdle();
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 kMasterIdentificationCmd = MakeMasterIdentification(kRandSample, kEDiv);
const StaticByteBuffer<PacketSize<ErrorCode>()> kExpectedFailure{kPairingFailed,
ErrorCode::kUnspecifiedReason};
ASSERT_TRUE(ReceiveAndExpect(kMasterIdentificationCmd, kExpectedFailure));
EXPECT_EQ(1, listener()->pairing_error_count());
ASSERT_TRUE(listener()->last_error().is_protocol_error());
EXPECT_EQ(ErrorCode::kUnspecifiedReason, listener()->last_error().protocol_error());
}
// The peer sends us an LTK that is longer than the negotiated maximum key size
TEST_F(SMP_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));
ASSERT_TRUE(listener()->last_error().is_protocol_error());
EXPECT_EQ(ErrorCode::kInvalidParameters, listener()->last_error().protocol_error());
}
TEST_F(SMP_Phase3Test, MasterIdentificationReceivedTwice) {
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 Master 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 master identification. If Phase 3 receives multiple Master Identification
// commands before completing, it should abort the pairing.
Receive128BitCmd(kEncryptionInformation, UInt128());
const auto kMasterIdentificationCmd = MakeMasterIdentification(kRand, kEdiv);
fake_chan()->Receive(kMasterIdentificationCmd);
const StaticByteBuffer<PacketSize<ErrorCode>()> kExpectedFailure{kPairingFailed,
ErrorCode::kUnspecifiedReason};
ASSERT_TRUE(ReceiveAndExpect(kMasterIdentificationCmd, kExpectedFailure));
EXPECT_EQ(1, listener()->pairing_error_count());
}
// Pairing completes after obtaining encryption information only.
TEST_F(SMP_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());
ReceiveMasterIdentification(kExpectedLtk.key().rand(), kExpectedLtk.key().ediv());
RunLoopUntilIdle();
// 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(SMP_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();
RunLoopUntilIdle();
// 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(SMP_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<MasterIdentificationParams> master_id = std::nullopt;
fake_chan()->SetSendCallback(
[&](ByteBufferPtr sdu) { ExpectEncryptionInfo(std::move(sdu), &ltk_bytes, &master_id); },
dispatcher());
phase_3()->Start();
RunLoopUntilIdle();
// 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(master_id.has_value());
ASSERT_TRUE(pairing_data().local_ltk.has_value());
EXPECT_EQ(pairing_data().local_ltk->key(),
hci::LinkKey(*ltk_bytes, master_id->rand, master_id->ediv));
}
TEST_F(SMP_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<MasterIdentificationParams> master_id = std::nullopt;
fake_chan()->SetSendCallback(
[&](ByteBufferPtr sdu) { ExpectEncryptionInfo(std::move(sdu), &ltk_bytes, &master_id); },
dispatcher());
phase_3()->Start();
Receive128BitCmd(kEncryptionInformation, kExpectedLtk.key().value());
ReceiveMasterIdentification(kExpectedLtk.key().rand(), kExpectedLtk.key().ediv());
RunLoopUntilIdle();
// 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(master_id.has_value());
ASSERT_TRUE(pairing_data().local_ltk.has_value());
EXPECT_EQ(pairing_data().local_ltk->key(),
hci::LinkKey(*ltk_bytes, master_id->rand, master_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(SMP_Phase3Test, AbortsIfLocalIdKeyIsRemoved) {
Phase3Args args;
args.features.local_key_distribution = KeyDistGen::kIdKey;
NewPhase3(args);
listener()->set_identity_info(std::nullopt);
async::PostTask(dispatcher(), [this] { phase_3()->Start(); });
const StaticByteBuffer<PacketSize<ErrorCode>()> kExpectedFailure{kPairingFailed,
ErrorCode::kUnspecifiedReason};
ASSERT_TRUE(Expect(kExpectedFailure));
EXPECT_EQ(1, listener()->pairing_error_count());
ASSERT_TRUE(listener()->last_error().is_protocol_error());
EXPECT_EQ(ErrorCode::kUnspecifiedReason, listener()->last_error().protocol_error());
}
TEST_F(SMP_Phase3Test, IRKReceivedTwice) {
Phase3Args args;
args.features.remote_key_distribution = KeyDistGen::kIdKey;
NewPhase3(args);
Receive128BitCmd(kIdentityInformation, UInt128());
RunLoopUntilIdle();
// 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(SMP_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(SMP_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);
RunLoopUntilIdle();
// 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(SMP_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(SMP_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);
RunLoopUntilIdle();
// 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(SMP_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());
ReceiveMasterIdentification(kExpectedLtk.key().rand(), kExpectedLtk.key().ediv());
Receive128BitCmd(kIdentityInformation, kIrk.value());
ReceiveIdentityAddress(kSampleDeviceAddress);
RunLoopUntilIdle();
// 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(SMP_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<MasterIdentificationParams> master_id = std::nullopt;
fake_chan()->SetSendCallback(
[&](ByteBufferPtr sdu) { ExpectEncryptionInfo(std::move(sdu), &ltk_bytes, &master_id); },
dispatcher());
phase_3()->Start();
RunLoopUntilIdle();
// We should have sent both the Encryption Info and Master ID to the peer
ASSERT_TRUE(ltk_bytes.has_value());
ASSERT_TRUE(master_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::LinkKey(*ltk_bytes, master_id->rand, master_id->ediv),
pairing_data().local_ltk->key());
}
TEST_F(SMP_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());
ReceiveMasterIdentification(kExpectedLtk.key().rand(), kExpectedLtk.key().ediv());
RunLoopUntilIdle();
// 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(SMP_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<MasterIdentificationParams> master_id = std::nullopt;
fake_chan()->SetSendCallback(
[&](ByteBufferPtr sdu) { ExpectEncryptionInfo(std::move(sdu), &ltk_bytes, &master_id); },
dispatcher());
phase_3()->Start();
RunLoopUntilIdle();
// We should have sent the Encryption Info and Master ID & be waiting for the peer's IRK
ASSERT_TRUE(ltk_bytes.has_value());
ASSERT_TRUE(master_id.has_value());
ASSERT_EQ(0, phase_3_complete_count());
const hci::LinkKey kExpectedKey = hci::LinkKey(*ltk_bytes, master_id->rand, master_id->ediv);
// Reset ltk_bytes & master_id to verify that we don't send any further messages
ltk_bytes.reset();
master_id.reset();
Receive128BitCmd(kIdentityInformation, kIrk.value());
ReceiveIdentityAddress(kSampleDeviceAddress);
RunLoopUntilIdle();
ASSERT_FALSE(ltk_bytes.has_value());
ASSERT_FALSE(master_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(SMP_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<MasterIdentificationParams> master_id = std::nullopt;
fake_chan()->SetSendCallback(
[&](ByteBufferPtr sdu) { ExpectEncryptionInfo(std::move(sdu), &ltk_bytes, &master_id); },
dispatcher());
phase_3()->Start();
RunLoopUntilIdle();
// Local LTK, EDiv, and Rand should be sent to the peer & listener should be notified.
ASSERT_TRUE(ltk_bytes.has_value());
ASSERT_TRUE(master_id.has_value());
EXPECT_EQ(1, phase_3_complete_count());
EXPECT_EQ(hci::LinkKey(*ltk_bytes, master_id->rand, master_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(SMP_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();
RunLoopUntilIdle();
// 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);
RunLoopUntilIdle();
// 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(SMP_Phase3Test, ReceivePairingFailed) {
Phase3Args args;
args.features.remote_key_distribution = KeyDistGen::kEncKey;
NewPhase3(args);
phase_3()->Start();
fake_chan()->Receive(StaticByteBuffer{kPairingFailed, ErrorCode::kPairingNotSupported});
RunLoopUntilIdle();
ASSERT_TRUE(listener()->last_error().is_protocol_error());
ASSERT_EQ(ErrorCode::kPairingNotSupported, listener()->last_error().protocol_error());
ASSERT_EQ(1, listener()->pairing_error_count());
}
TEST_F(SMP_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());
ASSERT_TRUE(listener()->last_error().is_protocol_error());
ASSERT_EQ(ErrorCode::kInvalidParameters, listener()->last_error().protocol_error());
}
} // namespace
} // namespace bt::sm