blob: ba1c453e5730a261fa6a2395dc9beb49287a3615 [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 "security_manager.h"
#include <cstdlib>
#include <fbl/macros.h>
#include "src/connectivity/bluetooth/core/bt-host/common/random.h"
#include "src/connectivity/bluetooth/core/bt-host/common/status.h"
#include "src/connectivity/bluetooth/core/bt-host/common/test_helpers.h"
#include "src/connectivity/bluetooth/core/bt-host/gap/gap.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/hci/fake_connection.h"
#include "src/connectivity/bluetooth/core/bt-host/hci/status.h"
#include "src/connectivity/bluetooth/core/bt-host/l2cap/fake_channel_test.h"
#include "src/connectivity/bluetooth/core/bt-host/sm/ecdh_key.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/status.h"
#include "src/connectivity/bluetooth/core/bt-host/sm/types.h"
#include "util.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};
class SMP_SecurityManagerTest : public l2cap::testing::FakeChannelTest, public sm::Delegate {
public:
SMP_SecurityManagerTest() : weak_ptr_factory_(this) {}
~SMP_SecurityManagerTest() override = default;
protected:
void TearDown() override {
RunLoopUntilIdle();
DestroySecurityManager();
}
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(this, &SMP_SecurityManagerTest::OnDataReceived),
dispatcher());
// Setup a fake logical link.
auto link_role =
role == Role::kInitiator ? hci::Connection::Role::kMaster : hci::Connection::Role::kSlave;
fake_link_ = std::make_unique<hci::testing::FakeConnection>(1, hci::Connection::LinkType::kLE,
link_role, kLocalAddr, kPeerAddr);
pairing_ = SecurityManager::Create(fake_link_->WeakPtr(), fake_chan_, ioc,
weak_ptr_factory_.GetWeakPtr(), bondable_mode,
gap::LeSecurityMode::Mode1);
}
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(Status 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::Status 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) {
ZX_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) {
ZX_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 kMasterIdentification: {
const auto& params = reader.payload<MasterIdentificationParams>();
master_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 ReceiveMasterIdentification(uint64_t random, uint16_t ediv) {
StaticByteBuffer<sizeof(Header) + sizeof(MasterIdentificationParams)> buffer;
PacketWriter writer(kMasterIdentification, &buffer);
auto* params = writer.mutable_payload<MasterIdentificationParams>();
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 auto kResponse = CreateStaticByteBuffer(
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);
RunLoopUntilIdle();
}
void GenerateLegacyConfirmValue(const UInt128& random, UInt128* out_value,
bool peer_initiator = false, uint32_t tk = 0) {
ZX_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) {
ZX_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::FakeConnection* fake_link() const { return fake_link_.get(); }
int security_callback_count() const { return security_callback_count_; }
ErrorCode received_error_code() const { return received_error_code_; }
const Status& security_status() const { return security_status_; }
const SecurityProperties& sec_props() const { return sec_props_; }
int pairing_complete_count() const { return pairing_complete_count_; }
const Status& 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::Status& 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 master_ident_count() const { return master_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);
}
// 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;
Status security_status_;
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;
Status pairing_complete_status_;
// State tracking the OnAuthenticationFailure event.
int auth_failure_callback_count_ = 0;
hci::Status auth_failure_status_;
// 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 master_ident_count_ = 0;
// Values that have we have sent to the peer.
AuthReqField security_auth_req_;
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_;
uint64_t rand_;
ErrorCode received_error_code_ = ErrorCode::kNoError;
fbl::RefPtr<l2cap::testing::FakeChannel> fake_chan_;
std::unique_ptr<hci::testing::FakeConnection> fake_link_;
std::unique_ptr<SecurityManager> pairing_;
fxl::WeakPtrFactory<SMP_SecurityManagerTest> weak_ptr_factory_;
DISALLOW_COPY_AND_ASSIGN_ALLOW_MOVE(SMP_SecurityManagerTest);
};
class SMP_InitiatorPairingTest : public SMP_SecurityManagerTest {
public:
SMP_InitiatorPairingTest() = default;
~SMP_InitiatorPairingTest() override = default;
void SetUp() override { 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) {
ZX_DEBUG_ASSERT(out_confirm);
ZX_DEBUG_ASSERT(out_random);
*out_random = kHardCodedPairingRandom;
GenerateLegacyConfirmValue(*out_random, out_confirm, false /* peer_initiator */, 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, 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.
RunLoopUntilIdle();
UInt128 sconfirm, srand;
GenerateMatchingLegacyConfirmAndRandom(&sconfirm, &srand);
ReceivePairingConfirm(sconfirm);
ReceivePairingRandom(srand);
RunLoopUntilIdle();
EXPECT_EQ(1, pairing_confirm_count());
EXPECT_EQ(1, pairing_random_count());
EXPECT_EQ(0, pairing_failed_count());
EXPECT_EQ(0, security_callback_count());
ZX_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(hci::Status(), true /* enabled */);
RunLoopUntilIdle();
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);
RunLoopUntilIdle();
ASSERT_EQ(1, pairing_request_count());
PairingRequestParams pres;
pres.io_capability = IOCapability::kDisplayYesNo;
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);
RunLoopUntilIdle();
ASSERT_TRUE(public_ecdh_key().has_value());
LocalEcdhKey peer_key = *LocalEcdhKey::Create();
ReceivePairingPublicKey(peer_key.GetSerializedPublicKey());
RunLoopUntilIdle();
// 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);
RunLoopUntilIdle();
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);
RunLoopUntilIdle();
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);
RunLoopUntilIdle();
EXPECT_EQ(1, pairing_dhkey_check_count());
ASSERT_EQ(dhkey_check_a, pairing_dhkey_check());
ReceivePairingDHKeyCheck(dhkey_check_b);
RunLoopUntilIdle();
EXPECT_EQ(0, pairing_failed_count());
EXPECT_EQ(0, security_callback_count());
ASSERT_TRUE(out_ltk);
*out_ltk = f5.ltk;
}
private:
DISALLOW_COPY_AND_ASSIGN_ALLOW_MOVE(SMP_InitiatorPairingTest);
};
class SMP_ResponderPairingTest : public SMP_SecurityManagerTest {
public:
SMP_ResponderPairingTest() = default;
~SMP_ResponderPairingTest() override = default;
void SetUp() override { 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) {
ZX_DEBUG_ASSERT(out_confirm);
ZX_DEBUG_ASSERT(out_random);
*out_random = kHardCodedPairingRandom;
GenerateLegacyConfirmValue(*out_random, out_confirm, true /* peer_initiator */, 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, 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, true /* peer_initiator */);
}
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, true /* peer_initiator */);
// Run the loop until the harness caches the feature exchange PDUs (preq &
// pres) so that we can generate a valid confirm value.
RunLoopUntilIdle();
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);
RunLoopUntilIdle();
EXPECT_EQ(1, pairing_confirm_count());
EXPECT_EQ(0, pairing_random_count());
ReceivePairingRandom(mrand);
RunLoopUntilIdle();
EXPECT_EQ(1, pairing_confirm_count());
EXPECT_EQ(1, pairing_random_count());
EXPECT_EQ(0, pairing_failed_count());
EXPECT_EQ(0, security_callback_count());
ZX_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(hci::Status(), true /* enabled */);
RunLoopUntilIdle();
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;
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, true /* peer_initiator */);
RunLoopUntilIdle();
ASSERT_EQ(1, pairing_response_count());
LocalEcdhKey peer_key = *LocalEcdhKey::Create();
ReceivePairingPublicKey(peer_key.GetSerializedPublicKey());
RunLoopUntilIdle();
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);
RunLoopUntilIdle();
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);
RunLoopUntilIdle();
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:
DISALLOW_COPY_AND_ASSIGN_ALLOW_MOVE(SMP_ResponderPairingTest);
};
// Calling `Abort` with no in-progress security upgrade should not cause a PairingComplete event.
TEST_F(SMP_InitiatorPairingTest, AbortNoSecurityUpgradeInProgress) {
pairing()->Abort();
RunLoopUntilIdle();
EXPECT_EQ(0, pairing_complete_count());
}
// Disconnecting with no in-progress security upgrade should not cause a PairingComplete event.
TEST_F(SMP_InitiatorPairingTest, DisconnectNoSecurityUpgradeInProgress) {
fake_chan()->Close();
RunLoopUntilIdle();
EXPECT_EQ(0, pairing_complete_count());
}
// Requesting pairing at the current security level should succeed immediately.
TEST_F(SMP_InitiatorPairingTest, UpgradeSecurityCurrentLevel) {
UpgradeSecurity(SecurityLevel::kNoSecurity);
RunLoopUntilIdle();
// 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_TRUE(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(SMP_InitiatorPairingTest, PairingFailedInPhase1) {
UpgradeSecurity(SecurityLevel::kEncrypted);
RunLoopUntilIdle();
// 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);
RunLoopUntilIdle();
EXPECT_EQ(1, security_callback_count());
EXPECT_EQ(1, pairing_request_count());
EXPECT_EQ(ErrorCode::kPairingNotSupported, security_status().protocol_error());
EXPECT_EQ(1, pairing_complete_count());
EXPECT_EQ(security_status(), pairing_complete_status());
}
// Local aborts during Phase 1.
TEST_F(SMP_InitiatorPairingTest, PairingAbortedInPhase1) {
UpgradeSecurity(SecurityLevel::kEncrypted);
RunLoopUntilIdle();
// 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();
RunLoopUntilIdle();
EXPECT_EQ(1, security_callback_count());
EXPECT_EQ(1, pairing_request_count());
EXPECT_EQ(ErrorCode::kUnspecifiedReason, security_status().protocol_error());
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(SMP_InitiatorPairingTest, SecurityManagerResetDuringPairing) {
UpgradeSecurity(SecurityLevel::kEncrypted);
RunLoopUntilIdle();
// 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);
RunLoopUntilIdle();
EXPECT_EQ(1, security_callback_count());
EXPECT_EQ(1, pairing_request_count());
EXPECT_EQ(ErrorCode::kUnspecifiedReason, security_status().protocol_error());
EXPECT_EQ(1, pairing_complete_count());
EXPECT_EQ(security_status(), pairing_complete_status());
UpgradeSecurity(SecurityLevel::kEncrypted);
RunLoopUntilIdle();
// 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).As<PairingRequestParams>();
EXPECT_EQ(IOCapability::kNoInputNoOutput, params.io_capability);
}
TEST_F(SMP_InitiatorPairingTest, ReceiveConfirmValueWhileNotPairing) {
UInt128 confirm;
ReceivePairingConfirm(confirm);
RunLoopUntilIdle();
// 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(SMP_InitiatorPairingTest, ReceiveConfirmValueInPhase1) {
UpgradeSecurity(SecurityLevel::kEncrypted);
RunLoopUntilIdle();
UInt128 confirm;
ReceivePairingConfirm(confirm);
RunLoopUntilIdle();
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(ErrorCode::kUnspecifiedReason, security_status().protocol_error());
EXPECT_EQ(1, pairing_complete_count());
EXPECT_EQ(security_status(), pairing_complete_status());
}
TEST_F(SMP_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);
RunLoopUntilIdle();
EXPECT_EQ(1, pairing_failed_count());
EXPECT_EQ(1, security_callback_count());
EXPECT_EQ(ErrorCode::kAuthenticationRequirements, security_status().protocol_error());
EXPECT_EQ(1, pairing_complete_count());
EXPECT_EQ(security_status(), pairing_complete_status());
}
TEST_F(SMP_InitiatorPairingTest, RejectUnauthenticatedEncryptionInSecureConnectionsOnlyMode) {
pairing()->set_security_mode(gap::LeSecurityMode::SecureConnectionsOnly);
const LTK kUnauthenticatedLtk(SecurityProperties(true /*encrypted*/, false /*authenticated*/,
true /*SC*/, kMaxEncryptionKeySize),
hci::LinkKey());
pairing()->AssignLongTermKey(kUnauthenticatedLtk);
RunLoopUntilIdle();
// 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(hci::Status(), true);
RunLoopUntilIdle();
EXPECT_EQ(1, auth_failure_callback_count());
EXPECT_EQ(HostError::kInsufficientSecurity, auth_failure_status().error());
EXPECT_TRUE(fake_chan()->link_error());
}
TEST_F(SMP_InitiatorPairingTest, AllowSecureAuthenticatedPairingInSecureConnectionsOnlyMode) {
SetUpSecurityManager(IOCapability::kDisplayYesNo);
pairing()->set_security_mode(gap::LeSecurityMode::SecureConnectionsOnly);
UInt128 enc_key;
FastForwardToPhase3(&enc_key, true, SecurityLevel::kSecureAuthenticated);
RunLoopUntilIdle();
// 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_TRUE(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(SMP_InitiatorPairingTest, ReceiveConfirmValueWhileWaitingForUserInput) {
bool tk_requested = false;
set_confirm_delegate([&](ConfirmCallback) { tk_requested = true; });
UpgradeSecurity(SecurityLevel::kEncrypted);
ReceivePairingFeatures();
RunLoopUntilIdle();
EXPECT_TRUE(tk_requested);
UInt128 confirm;
ReceivePairingConfirm(confirm);
RunLoopUntilIdle();
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(ErrorCode::kUnspecifiedReason, security_status().protocol_error());
EXPECT_EQ(1, pairing_complete_count());
EXPECT_EQ(security_status(), pairing_complete_status());
}
// SecurityManager destroyed when waiting for Just Works user confirmation.
TEST_F(SMP_InitiatorPairingTest, SecurityManagerDestroyedStateWhileWaitingForUserInput) {
ConfirmCallback respond;
set_confirm_delegate([&](ConfirmCallback rsp) { respond = std::move(rsp); });
UpgradeSecurity(SecurityLevel::kEncrypted);
ReceivePairingFeatures();
RunLoopUntilIdle();
EXPECT_TRUE(respond);
DestroySecurityManager();
// This should proceed safely.
respond(true);
RunLoopUntilIdle();
}
// Pairing no longer in progress when waiting for Just Works user confirmation.
TEST_F(SMP_InitiatorPairingTest, PairingAbortedWhileWaitingForUserInput) {
ConfirmCallback respond;
set_confirm_delegate([&](ConfirmCallback rsp) { respond = std::move(rsp); });
UpgradeSecurity(SecurityLevel::kEncrypted);
ReceivePairingFeatures();
RunLoopUntilIdle();
EXPECT_TRUE(respond);
ReceivePairingFailed(ErrorCode::kPairingNotSupported);
RunLoopUntilIdle();
EXPECT_EQ(1, security_callback_count());
EXPECT_EQ(ErrorCode::kPairingNotSupported, security_status().protocol_error());
EXPECT_EQ(1, pairing_complete_count());
EXPECT_EQ(security_status(), pairing_complete_status());
// This should have no effect.
respond(true);
RunLoopUntilIdle();
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(SMP_InitiatorPairingTest, PairingRestartedWhileWaitingForTK) {
ConfirmCallback respond;
set_confirm_delegate([&](ConfirmCallback rsp) { respond = std::move(rsp); });
UpgradeSecurity(SecurityLevel::kEncrypted);
ReceivePairingFeatures();
RunLoopUntilIdle();
EXPECT_TRUE(respond);
// Stop pairing.
ReceivePairingFailed(ErrorCode::kPairingNotSupported);
RunLoopUntilIdle();
EXPECT_EQ(1, security_callback_count());
EXPECT_EQ(ErrorCode::kPairingNotSupported, security_status().protocol_error());
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();
RunLoopUntilIdle();
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);
RunLoopUntilIdle();
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(SMP_InitiatorPairingTest, ReceiveRandomValueWhileNotPairing) {
UInt128 random;
ReceivePairingRandom(random);
RunLoopUntilIdle();
// 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(SMP_InitiatorPairingTest, ReceiveRandomValueInPhase1) {
UpgradeSecurity(SecurityLevel::kEncrypted);
RunLoopUntilIdle();
UInt128 random;
ReceivePairingRandom(random);
RunLoopUntilIdle();
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(ErrorCode::kUnspecifiedReason, security_status().protocol_error());
EXPECT_EQ(1, pairing_complete_count());
EXPECT_EQ(security_status(), pairing_complete_status());
}
// In Phase 2 but still waiting to receive TK.
TEST_F(SMP_InitiatorPairingTest, ReceiveRandomValueWhileWaitingForTK) {
bool confirmation_requested = false;
set_confirm_delegate([&](ConfirmCallback) { confirmation_requested = true; });
UpgradeSecurity(SecurityLevel::kEncrypted);
ReceivePairingFeatures();
RunLoopUntilIdle();
EXPECT_TRUE(confirmation_requested);
UInt128 random;
ReceivePairingRandom(random);
RunLoopUntilIdle();
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(ErrorCode::kUnspecifiedReason, security_status().protocol_error());
EXPECT_EQ(1, pairing_complete_count());
EXPECT_EQ(security_status(), pairing_complete_status());
}
TEST_F(SMP_InitiatorPairingTest, LegacyPhase2SconfirmValueReceivedTwice) {
UpgradeSecurity(SecurityLevel::kEncrypted);
RunLoopUntilIdle();
ReceivePairingFeatures();
RunLoopUntilIdle();
// 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);
RunLoopUntilIdle();
// 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);
RunLoopUntilIdle();
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(ErrorCode::kUnspecifiedReason, security_status().protocol_error());
EXPECT_EQ(1, pairing_complete_count());
EXPECT_EQ(security_status(), pairing_complete_status());
}
TEST_F(SMP_InitiatorPairingTest, LegacyPhase2ReceiveRandomValueInWrongOrder) {
UpgradeSecurity(SecurityLevel::kEncrypted);
RunLoopUntilIdle();
ReceivePairingFeatures();
RunLoopUntilIdle();
// 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);
RunLoopUntilIdle();
// 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(ErrorCode::kUnspecifiedReason, security_status().protocol_error());
EXPECT_EQ(1, pairing_complete_count());
EXPECT_EQ(security_status(), pairing_complete_status());
}
TEST_F(SMP_InitiatorPairingTest, LegacyPhase2SconfirmValueInvalid) {
UpgradeSecurity(SecurityLevel::kEncrypted);
RunLoopUntilIdle();
// Pick I/O capabilities and MITM flags that will result in Just Works
// pairing.
ReceivePairingFeatures();
RunLoopUntilIdle();
// 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);
RunLoopUntilIdle();
// 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);
RunLoopUntilIdle();
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(ErrorCode::kConfirmValueFailed, security_status().protocol_error());
EXPECT_EQ(1, pairing_complete_count());
EXPECT_EQ(security_status(), pairing_complete_status());
}
TEST_F(SMP_InitiatorPairingTest, LegacyPhase2RandomValueReceivedTwice) {
UpgradeSecurity(SecurityLevel::kEncrypted);
RunLoopUntilIdle();
// Pick I/O capabilities and MITM flags that will result in Just Works
// pairing.
ReceivePairingFeatures();
RunLoopUntilIdle();
// 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);
RunLoopUntilIdle();
// 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);
RunLoopUntilIdle();
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);
RunLoopUntilIdle();
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(ErrorCode::kUnspecifiedReason, security_status().protocol_error());
EXPECT_EQ(1, pairing_complete_count());
EXPECT_EQ(security_status(), pairing_complete_status());
}
TEST_F(SMP_InitiatorPairingTest, LegacyPhase2ConfirmValuesExchanged) {
UpgradeSecurity(SecurityLevel::kEncrypted);
RunLoopUntilIdle();
// Pick I/O capabilities and MITM flags that will result in Just Works
// pairing.
ReceivePairingFeatures();
RunLoopUntilIdle();
// 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);
RunLoopUntilIdle();
// 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);
RunLoopUntilIdle();
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(SMP_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);
RunLoopUntilIdle();
// Pick I/O capabilities and MITM flags that will result in Passkey Entry
// pairing.
ReceivePairingFeatures(IOCapability::kDisplayOnly, AuthReq::kMITM);
RunLoopUntilIdle();
ASSERT_TRUE(tk_requested);
// Reject pairing.
respond(-1);
RunLoopUntilIdle();
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(ErrorCode::kPasskeyEntryFailed, security_status().protocol_error());
}
// TK delegate rejects pairing.
TEST_F(SMP_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);
RunLoopUntilIdle();
ReceivePairingFeatures();
RunLoopUntilIdle();
ASSERT_TRUE(tk_requested);
// Reject pairing.
respond(false);
RunLoopUntilIdle();
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(ErrorCode::kUnspecifiedReason, security_status().protocol_error());
}
TEST_F(SMP_InitiatorPairingTest, IgnoresExpiredConfirmRequestCallback) {
ConfirmCallback respond = nullptr;
set_confirm_delegate([&](ConfirmCallback rsp) { respond = std::move(rsp); });
UpgradeSecurity(SecurityLevel::kEncrypted);
RunLoopUntilIdle();
ReceivePairingFeatures();
RunLoopUntilIdle();
ASSERT_TRUE(respond);
ConfirmCallback first_pairing_cb = std::move(respond);
pairing()->Abort();
RunLoopUntilIdle();
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);
RunLoopUntilIdle();
ReceivePairingFeatures();
RunLoopUntilIdle();
first_pairing_cb(true);
RunLoopUntilIdle();
// 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);
RunLoopUntilIdle();
EXPECT_EQ(1, pairing_confirm_count());
}
TEST_F(SMP_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);
RunLoopUntilIdle();
ReceivePairingFeatures(IOCapability::kKeyboardOnly);
RunLoopUntilIdle();
ASSERT_TRUE(respond);
ConfirmCallback first_pairing_cb = std::move(respond);
pairing()->Abort();
RunLoopUntilIdle();
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);
RunLoopUntilIdle();
ReceivePairingFeatures(IOCapability::kKeyboardOnly);
RunLoopUntilIdle();
first_pairing_cb(true);
RunLoopUntilIdle();
// 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);
RunLoopUntilIdle();
EXPECT_EQ(1, pairing_confirm_count());
}
TEST_F(SMP_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);
RunLoopUntilIdle();
ReceivePairingFeatures(IOCapability::kDisplayOnly);
RunLoopUntilIdle();
ASSERT_TRUE(passkey_cb);
PasskeyResponseCallback first_pairing_cb = std::move(passkey_cb);
pairing()->Abort();
RunLoopUntilIdle();
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);
RunLoopUntilIdle();
ReceivePairingFeatures(IOCapability::kDisplayOnly);
RunLoopUntilIdle();
const int32_t kGenericPositive6DigitNumber = 123456;
first_pairing_cb(kGenericPositive6DigitNumber);
RunLoopUntilIdle();
// 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);
RunLoopUntilIdle();
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(SMP_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);
RunLoopUntilIdle();
// Pick I/O capabilities and MITM flags that will result in Passkey Entry
// pairing.
ReceivePairingFeatures(IOCapability::kKeyboardOnly, AuthReq::kMITM);
RunLoopUntilIdle();
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);
RunLoopUntilIdle();
// 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);
RunLoopUntilIdle();
// 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, false /* peer_initiator */, *tk);
EXPECT_EQ(expected_confirm, pairing_confirm());
// Send Srandom.
ReceivePairingRandom(random);
RunLoopUntilIdle();
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(SMP_InitiatorPairingTest, PairingFailedInPhase2) {
UpgradeSecurity(SecurityLevel::kEncrypted);
ReceivePairingFeatures();
RunLoopUntilIdle();
UInt128 confirm, random;
GenerateMatchingLegacyConfirmAndRandom(&confirm, &random);
ReceivePairingConfirm(confirm);
RunLoopUntilIdle();
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);
RunLoopUntilIdle();
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(ErrorCode::kConfirmValueFailed, security_status().protocol_error());
}
// Encryption with STK fails.
TEST_F(SMP_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(hci::Status(hci::StatusCode::kPinOrKeyMissing),
false /* enabled */);
RunLoopUntilIdle();
EXPECT_EQ(1, pairing_failed_count());
EXPECT_EQ(1, security_callback_count());
EXPECT_EQ(1, auth_failure_callback_count());
EXPECT_EQ(ErrorCode::kUnspecifiedReason, security_status().protocol_error());
EXPECT_EQ(ErrorCode::kUnspecifiedReason, received_error_code());
EXPECT_EQ(hci::StatusCode::kPinOrKeyMissing, auth_failure_status().protocol_error());
// 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(SMP_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(hci::Status(), false /* enabled */);
RunLoopUntilIdle();
EXPECT_EQ(1, pairing_failed_count());
EXPECT_EQ(1, security_callback_count());
EXPECT_EQ(0, auth_failure_callback_count());
EXPECT_EQ(ErrorCode::kUnspecifiedReason, security_status().protocol_error());
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(SMP_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(SMP_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(hci::Status(), true /* enabled */);
RunLoopUntilIdle();
// 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_TRUE(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(SMP_InitiatorPairingTest, ScPhase3CompleteWithoutKeyExchange) {
UInt128 ltk_bytes;
const SecurityProperties kExpectedSecurity(SecurityLevel::kEncrypted, kMaxEncryptionKeySize,
true /* secure connections */);
FastForwardToPhase3(&ltk_bytes, true /*secure_connections*/, kExpectedSecurity.level(),
KeyDistGenField{0}, KeyDistGenField{0});
const LTK kExpectedLtk(kExpectedSecurity, hci::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_TRUE(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(SMP_InitiatorPairingTest, ScPhase3EncKeyBitSetNotDistributed) {
UInt128 ltk_bytes;
const SecurityProperties kExpectedSecurity(SecurityLevel::kEncrypted, kMaxEncryptionKeySize,
true /* secure connections */);
// 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::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(hci::Status(), true /* enabled */);
RunLoopUntilIdle();
// 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_TRUE(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(SMP_InitiatorPairingTest, ScPhase3NonBondableCompleteWithoutKeyExchange) {
// Must have DisplayYesNo IOC to generate Authenticated security per kExpectedSecurity
SetUpSecurityManager(IOCapability::kDisplayYesNo);
const SecurityProperties kExpectedSecurity(SecurityLevel::kAuthenticated, kMaxEncryptionKeySize,
true /* secure connections */);
UInt128 ltk_bytes;
FastForwardToScLtk(&ltk_bytes, kExpectedSecurity.level(), KeyDistGenField{0}, KeyDistGenField{0},
BondableMode::NonBondable);
const hci::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(hci::Status(), true /* enabled */);
RunLoopUntilIdle();
// 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_TRUE(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(SMP_InitiatorPairingTest, Phase3EncryptionInformationReceivedTwice) {
UInt128 stk;
FastForwardToPhase3(&stk, false /*secure_connections*/, 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());
RunLoopUntilIdle();
// 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());
RunLoopUntilIdle();
EXPECT_EQ(1, pairing_failed_count());
EXPECT_EQ(1, security_callback_count());
EXPECT_EQ(1, pairing_complete_count());
EXPECT_EQ(ErrorCode::kUnspecifiedReason, security_status().protocol_error());
EXPECT_EQ(ErrorCode::kUnspecifiedReason, received_error_code());
EXPECT_EQ(security_status(), pairing_complete_status());
}
// The responder sends EDIV and Rand before LTK.
TEST_F(SMP_InitiatorPairingTest, Phase3MasterIdentificationReceivedInWrongOrder) {
UInt128 stk;
FastForwardToPhase3(&stk, false /*secure_connections*/, 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 master identification before encryption information. This should cause
// pairing to fail.
ReceiveMasterIdentification(1, 2);
RunLoopUntilIdle();
EXPECT_EQ(1, pairing_failed_count());
EXPECT_EQ(1, security_callback_count());
EXPECT_EQ(1, pairing_complete_count());
EXPECT_EQ(ErrorCode::kUnspecifiedReason, security_status().protocol_error());
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(SMP_InitiatorPairingTest, Phase3MasterIdentificationReceiveSampleLTK) {
UInt128 stk;
FastForwardToPhase3(&stk, false /*secure_connections*/, 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);
RunLoopUntilIdle();
EXPECT_EQ(1, pairing_failed_count());
EXPECT_EQ(1, security_callback_count());
EXPECT_EQ(1, pairing_complete_count());
EXPECT_EQ(ErrorCode::kUnspecifiedReason, security_status().protocol_error());
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(SMP_InitiatorPairingTest, Phase3MasterIdentificationReceiveExampleRand) {
UInt128 stk;
FastForwardToPhase3(&stk, false /*secure_connections*/, 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());
ReceiveMasterIdentification(kRandSample, kEDiv);
RunLoopUntilIdle();
EXPECT_EQ(1, pairing_failed_count());
EXPECT_EQ(1, security_callback_count());
EXPECT_EQ(1, pairing_complete_count());
EXPECT_EQ(ErrorCode::kUnspecifiedReason, security_status().protocol_error());
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(SMP_InitiatorPairingTest, Phase3MasterIdentificationReceiveLongLTK) {
UInt128 stk;
auto max_key_size = 8;
FastForwardToPhase3(&stk, false /*secure_connections*/, 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);
RunLoopUntilIdle();
EXPECT_EQ(1, pairing_failed_count());
EXPECT_EQ(1, security_callback_count());
EXPECT_EQ(1, pairing_complete_count());
EXPECT_EQ(ErrorCode::kInvalidParameters, security_status().protocol_error());
EXPECT_EQ(ErrorCode::kInvalidParameters, received_error_code());
EXPECT_EQ(security_status(), pairing_complete_status());
}
TEST_F(SMP_InitiatorPairingTest, Phase3MasterIdentificationReceivedTwice) {
UInt128 stk;
FastForwardToPhase3(&stk, false /*secure_connections*/, 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 master identification. Pairing should complete with the
// first set of information. The second set should get ignored.
ReceiveEncryptionInformation(UInt128());
ReceiveMasterIdentification(kRand, kEdiv);
ReceiveMasterIdentification(kDupRand, kDupEdiv);
RunLoopUntilIdle();
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_TRUE(security_status().is_success());
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(SMP_InitiatorPairingTest, Phase3CompleteWithReceivingEncKey) {
UInt128 stk;
FastForwardToPhase3(&stk, false /*secure_connections*/, 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);
ReceiveMasterIdentification(kRand, kEDiv);
RunLoopUntilIdle();
// Pairing should have succeeded.
EXPECT_EQ(0, pairing_failed_count());
EXPECT_EQ(1, security_callback_count());
EXPECT_EQ(1, pairing_complete_count());
EXPECT_TRUE(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(SMP_InitiatorPairingTest, Phase3CompleteWithSendingEncKey) {
UInt128 stk;
KeyDistGenField remote_keys{0u}, local_keys{KeyDistGen::kEncKey};
FastForwardToPhase3(&stk, false, SecurityLevel::kEncrypted, remote_keys, local_keys);
RunLoopUntilIdle();
// Pairing should have succeeded.
EXPECT_EQ(0, pairing_failed_count());
EXPECT_EQ(1, security_callback_count());
EXPECT_EQ(1, pairing_complete_count());
EXPECT_TRUE(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::LinkKey(enc_info(), rand(), ediv()));
}
// Pairing completes after obtaining short encryption information only.
TEST_F(SMP_InitiatorPairingTest, Phase3CompleteWithShortEncKey) {
UInt128 stk;
uint8_t max_key_size = 12;
FastForwardToPhase3(&stk, false /*secure_connections*/, 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);
ReceiveMasterIdentification(kRand, kEDiv);
RunLoopUntilIdle();
// Pairing should have succeeded.
EXPECT_EQ(0, pairing_failed_count());
EXPECT_EQ(1, security_callback_count());
EXPECT_EQ(1, pairing_complete_count());
EXPECT_TRUE(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(SMP_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, false /*secure_connections*/, 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_TRUE(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(SMP_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(hci::Status(), true /* enabled */);
RunLoopUntilIdle();
// 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_FALSE(security_status());
EXPECT_EQ(ErrorCode::kUnspecifiedReason, security_status().protocol_error());
}
TEST_F(SMP_InitiatorPairingTest, Phase3IRKReceivedTwice) {
UInt128 stk;
FastForwardToPhase3(&stk, false /*secure_connections*/, 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());
RunLoopUntilIdle();
// 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());
RunLoopUntilIdle();
EXPECT_EQ(1, pairing_failed_count());
EXPECT_EQ(1, security_callback_count());
EXPECT_EQ(1, pairing_complete_count());
EXPECT_EQ(ErrorCode::kUnspecifiedReason, security_status().protocol_error());
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(SMP_InitiatorPairingTest, Phase3IdentityAddressReceivedInWrongOrder) {
UInt128 stk;
FastForwardToPhase3(&stk, false /*secure_connections*/, 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);
RunLoopUntilIdle();
EXPECT_EQ(1, pairing_failed_count());
EXPECT_EQ(1, security_callback_count());
EXPECT_EQ(1, pairing_complete_count());
EXPECT_EQ(ErrorCode::kUnspecifiedReason, security_status().protocol_error());
EXPECT_EQ(ErrorCode::kUnspecifiedReason, received_error_code());
EXPECT_EQ(security_status(), pairing_complete_status());
}
TEST_F(SMP_InitiatorPairingTest, Phase3IdentityAddressReceivedTwice) {
UInt128 stk;
// Request enc key to prevent pairing from completing after sending the first
// identity address.
FastForwardToPhase3(&stk, false /*secure_connections*/, 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);
RunLoopUntilIdle();
EXPECT_EQ(1, pairing_failed_count());
EXPECT_EQ(1, security_callback_count());
EXPECT_EQ(1, pairing_complete_count());
EXPECT_EQ(ErrorCode::kUnspecifiedReason, security_status().protocol_error());
EXPECT_EQ(ErrorCode::kUnspecifiedReason, received_error_code());
EXPECT_EQ(security_status(), pairing_complete_status());
}
// Pairing completes after obtaining identity information only.
TEST_F(SMP_InitiatorPairingTest, Phase3CompleteWithIdKey) {
UInt128 stk;
FastForwardToPhase3(&stk, false /*secure_connections*/, 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);
RunLoopUntilIdle();
EXPECT_EQ(0, pairing_failed_count());
EXPECT_EQ(1, security_callback_count());
EXPECT_EQ(1, pairing_complete_count());
EXPECT_TRUE(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(SMP_InitiatorPairingTest, Phase3CompleteWithAllKeys) {
UInt128 stk;
FastForwardToPhase3(&stk, false /*secure_connections*/, 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);
ReceiveMasterIdentification(kRand, kEDiv);
RunLoopUntilIdle();
// 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);
RunLoopUntilIdle();
// Pairing should have succeeded
EXPECT_EQ(0, pairing_failed_count());
EXPECT_EQ(1, security_callback_count());
EXPECT_EQ(1, pairing_complete_count());
EXPECT_TRUE(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(SMP_InitiatorPairingTest, GenerateCrossTransportLinkKey) {
UInt128 stk;
// Indicate support for SC and for link keys in both directions to enable CTKG.
FastForwardToPhase3(&stk, true /*secure connections*/, SecurityLevel::kEncrypted,
KeyDistGen::kLinkKey, KeyDistGen::kLinkKey);
RunLoopUntilIdle();
// Pairing should have succeeded
EXPECT_EQ(0, pairing_failed_count());
EXPECT_EQ(1, security_callback_count());
EXPECT_EQ(1, pairing_complete_count());
EXPECT_TRUE(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(SMP_InitiatorPairingTest, AssignLongTermKeyFailsDuringPairing) {
UpgradeSecurity(SecurityLevel::kEncrypted); // Initiate pairing.
SecurityProperties sec_props(SecurityLevel::kAuthenticated, 16, false);
EXPECT_FALSE(pairing()->AssignLongTermKey(LTK(sec_props, hci::LinkKey())));
EXPECT_EQ(0, fake_link()->start_encryption_count());
EXPECT_EQ(SecurityLevel::kNoSecurity, pairing()->security().level());
}
TEST_F(SMP_InitiatorPairingTest, AssignLongTermKey) {
SecurityProperties sec_props(SecurityLevel::kAuthenticated, 16, false);
LTK ltk(sec_props, hci::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(hci::Status(), true /* enabled */);
RunLoopUntilIdle();
EXPECT_EQ(1, new_sec_props_count());
EXPECT_EQ(sec_props, new_sec_props());
EXPECT_EQ(sec_props, pairing()->security());
}
TEST_F(SMP_InitiatorPairingTest, ReceiveSecurityRequest) {
ReceiveSecurityRequest(AuthReq::kMITM);
RunLoopUntilIdle();
// Should have requested pairing with MITM protection.
EXPECT_EQ(1, pairing_request_count());
const auto& params = local_pairing_cmd().view(1).As<PairingRequestParams>();
EXPECT_TRUE(params.auth_req & AuthReq::kMITM);
}
TEST_F(SMP_InitiatorPairingTest, ReceiveSecurityRequestWhenPaired) {
UInt128 stk;
FastForwardToPhase3(&stk, false /*secure_connections*/, SecurityLevel::kEncrypted,
KeyDistGen::kEncKey);
EXPECT_EQ(stk, fake_link()->ltk()->value());
EXPECT_EQ(1, pairing_request_count());
// Receiving a security request now should have no effect since pairing is
// still in progress.
ReceiveSecurityRequest();
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);
ReceiveMasterIdentification(kRand, kEDiv);
RunLoopUntilIdle();
fake_link()->TriggerEncryptionChangeCallback(hci::Status(), true /* enabled */);
RunLoopUntilIdle();
ASSERT_EQ(1, pairing_complete_count());
ASSERT_TRUE(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).As<PairingRequestParams>();
EXPECT_TRUE(params.auth_req & AuthReq::kMITM);
}
TEST_F(SMP_InitiatorPairingTest, PairingTimeoutWorks) {
UpgradeSecurity(SecurityLevel::kEncrypted);
RunLoopUntilIdle();
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(); });
RunLoopFor(kPairingTimeout);
EXPECT_TRUE(fake_chan()->link_error());
ASSERT_EQ(1, security_callback_count());
EXPECT_EQ(HostError::kTimedOut, security_status().error());
ASSERT_EQ(1, pairing_complete_count());
EXPECT_EQ(HostError::kTimedOut, pairing_complete_status().error());
}
TEST_F(SMP_InitiatorPairingTest, NoTimeoutAfterSuccessfulPairing) {
UInt128 out_stk;
FastForwardToPhase3(&out_stk, false /*secure_connections*/, SecurityLevel::kEncrypted,
KeyDistGenField{0}, KeyDistGenField{0});
ASSERT_EQ(1, pairing_complete_count());
ASSERT_EQ(1, security_callback_count());
ASSERT_TRUE(security_status().is_success());
ASSERT_TRUE(pairing_complete_status().is_success());
// Verify that no timeout occurs after a successful pairing followed by a long interval.
RunLoopFor(kPairingTimeout * 2);
ASSERT_EQ(1, pairing_complete_count());
ASSERT_EQ(1, security_callback_count());
ASSERT_NE(HostError::kTimedOut, pairing_complete_status().error());
ASSERT_NE(HostError::kTimedOut, security_status().error());
}
TEST_F(SMP_InitiatorPairingTest, AbortStopsPairingTimer) {
UpgradeSecurity(SecurityLevel::kEncrypted);
RunLoopUntilIdle();
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.
RunLoopFor(kPairingTimeout * 2);
ASSERT_EQ(1, pairing_complete_count());
ASSERT_EQ(1, security_callback_count());
ASSERT_NE(HostError::kTimedOut, pairing_complete_status().error());
ASSERT_NE(HostError::kTimedOut, security_status().error());
}
TEST_F(SMP_InitiatorPairingTest, ResetStopsPairingTimer) {
UpgradeSecurity(SecurityLevel::kEncrypted);
RunLoopUntilIdle();
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.
RunLoopFor(kPairingTimeout * 2);
ASSERT_EQ(1, pairing_complete_count());
ASSERT_EQ(1, security_callback_count());
ASSERT_NE(HostError::kTimedOut, pairing_complete_status().error());
ASSERT_NE(HostError::kTimedOut, security_status().error());
}
TEST_F(SMP_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);
RunLoopUntilIdle();
ASSERT_EQ(1, pairing_request_count());
// Run the loop until the pairing timeout has almost expired.
RunLoopFor(kPairingTimeout - zx::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.
RunLoopFor(zx::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.
RunLoopFor(kPairingTimeout);
ASSERT_EQ(1, pairing_complete_count());
ASSERT_EQ(1, security_callback_count());
ASSERT_EQ(HostError::kTimedOut, pairing_complete_status().error());
ASSERT_EQ(HostError::kTimedOut, security_status().error());
}
TEST_F(SMP_InitiatorPairingTest, ModifyAssignedLinkLtkBeforeSecurityRequestCausesDisconnect) {
SecurityProperties sec_props(SecurityLevel::kAuthenticated, 16, false);
const LTK kOriginalLtk(sec_props, hci::LinkKey({1}, 2, 3));
const hci::LinkKey kModifiedLtk(hci::LinkKey({4}, 5, 6));
EXPECT_TRUE(pairing()->AssignLongTermKey(kOriginalLtk));
fake_link()->set_le_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});
RunLoopUntilIdle();
ASSERT_TRUE(fake_chan()->link_error());
ASSERT_EQ(1, auth_failure_callback_count());
ASSERT_EQ(hci::StatusCode::kPinOrKeyMissing, auth_failure_status().protocol_error());
}
TEST_F(SMP_ResponderPairingTest, SuccessfulPairAfterResetInProgressPairing) {
ReceivePairingRequest();
RunLoopUntilIdle();
// 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();
RunLoopUntilIdle();
// 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();
RunLoopUntilIdle();
// 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(SMP_ResponderPairingTest, SecurityRequestCausesPairing) {
UpgradeSecurity(SecurityLevel::kEncrypted);
RunLoopUntilIdle();
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, true /*secure_connections*/);
// Pairing should have succeeded
EXPECT_EQ(0, pairing_failed_count());
EXPECT_EQ(1, security_callback_count());
EXPECT_EQ(1, pairing_complete_count());
EXPECT_TRUE(security_status());
EXPECT_EQ(security_status(), pairing_complete_status());
// LTK should have been assigned to the link.
hci::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(SMP_ResponderPairingTest, SecurityRequestWithExistingLtk) {
const SecurityProperties kProps(SecurityLevel::kAuthenticated, kMaxEncryptionKeySize, true);
const LTK kLtk(kProps, hci::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);
RunLoopUntilIdle();
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(hci::Status(), true /*enabled*/);
// Security should be upgraded.
EXPECT_EQ(1, security_callback_count());
EXPECT_TRUE(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(SMP_ResponderPairingTest, SecurityRequestInitiatorEncryptsWithInsufficientSecurityLtk) {
const SecurityProperties kProps(SecurityLevel::kEncrypted, kMaxEncryptionKeySize, true);
const LTK kLtk(kProps, hci::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);
RunLoopUntilIdle();
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(hci::Status(), true /*enabled*/);
// 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(SMP_ResponderPairingTest, AuthenticatedSecurityRequestWithInsufficientIoCapRejected) {
SetUpSecurityManager(IOCapability::kNoInputNoOutput);
// Make a security request for authenticated security
UpgradeSecurity(SecurityLevel::kAuthenticated);
RunLoopUntilIdle();
// 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());
ASSERT_TRUE(security_status().is_protocol_error());
EXPECT_EQ(ErrorCode::kAuthenticationRequirements, security_status().protocol_error());
EXPECT_EQ(SecurityLevel::kNoSecurity, sec_props().level());
}
TEST_F(SMP_ResponderPairingTest, HandlesMultipleSecurityRequestsCorrectly) {
// Make a security request for encrypted security
UpgradeSecurity(SecurityLevel::kEncrypted);
RunLoopUntilIdle();
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);
RunLoopUntilIdle();
EXPECT_EQ(1, security_request_count());
// Handle the first Security Request
UInt128 ltk_bytes;
FastForwardToPhase3(&ltk_bytes, true /*secure_connections*/, 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_TRUE(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(SMP_ResponderPairingTest, ReceiveSecondPairingRequestWhilePairing) {
ReceivePairingRequest();
RunLoopUntilIdle();
// 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();
RunLoopUntilIdle();
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());
EXPECT_EQ(ErrorCode::kUnspecifiedReason, received_error_code());
EXPECT_EQ(received_error_code(), pairing_complete_status().protocol_error());
}
TEST_F(SMP_ResponderPairingTest, ReceiveConfirmValueWhileWaitingForTK) {
bool tk_requested = false;
ConfirmCallback respond;
set_confirm_delegate([&](ConfirmCallback cb) {
tk_requested = true;
respond = std::move(cb);
});
ReceivePairingRequest();
RunLoopUntilIdle();
ASSERT_TRUE(tk_requested);
UInt128 confirm;
ReceivePairingConfirm(confirm);
RunLoopUntilIdle();
// 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);
RunLoopUntilIdle();
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(SMP_ResponderPairingTest, LegacyPhase2ReceivePairingRandomInWrongOrder) {
ReceivePairingRequest();
RunLoopUntilIdle();
// 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);
RunLoopUntilIdle();
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(ErrorCode::kUnspecifiedReason, pairing_complete_status().protocol_error());
}
TEST_F(SMP_ResponderPairingTest, LegacyPhase2MconfirmValueInvalid) {
ReceivePairingRequest();
RunLoopUntilIdle();
// 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);
RunLoopUntilIdle();
// 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);
RunLoopUntilIdle();
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(ErrorCode::kConfirmValueFailed, pairing_complete_status().protocol_error());
}
TEST_F(SMP_ResponderPairingTest, LegacyPhase2ConfirmValuesExchanged) {
ReceivePairingRequest();
RunLoopUntilIdle();
// 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);
RunLoopUntilIdle();
// 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);
RunLoopUntilIdle();
// 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, true /* peer_initiator */);
EXPECT_EQ(expected_confirm, pairing_confirm());
}
TEST_F(SMP_ResponderPairingTest, LegacyPhase3LocalLTKDistributionNoRemoteKeys) {
EXPECT_EQ(0, enc_info_count());
EXPECT_EQ(0, master_ident_count());
UInt128 stk;
KeyDistGenField remote_keys{0}, local_keys{KeyDistGen::kEncKey};
FastForwardToPhase3(&stk, false /*secure_connections*/, 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, master_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(hci::Status(), true /* enabled */);
RunLoopUntilIdle();
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(SMP_ResponderPairingTest, LegacyPhase3LocalLTKDistributionWithRemoteKeys) {
EXPECT_EQ(0, enc_info_count());
EXPECT_EQ(0, master_ident_count());
UInt128 stk;
FastForwardToPhase3(&stk, false /*secure_connections*/, 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, master_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);
RunLoopUntilIdle();
// 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(SMP_ResponderPairingTest, LegacyPhase3LocalLTKMaxLength) {
EXPECT_EQ(0, enc_info_count());
EXPECT_EQ(0, master_ident_count());
UInt128 stk;
uint16_t max_key_size = 7;
FastForwardToPhase3(&stk, false /*secure_connections*/, 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, master_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(SMP_ResponderPairingTest, LegacyPhase3ReceiveInitiatorEncKey) {
UInt128 stk;
KeyDistGenField remote_keys{KeyDistGen::kEncKey}, local_keys{0u};
FastForwardToPhase3(&stk, false, SecurityLevel::kEncrypted, remote_keys, local_keys);
const uint64_t kRand = 5;
const uint16_t kEDiv = 20;
const hci::LinkKey kLTK({1, 2, 3, 4, 5, 6, 7, 8, 7, 6, 5, 4, 3, 2, 1, 0}, kRand, kEDiv);
ReceiveEncryptionInformation(kLTK.value());
ReceiveMasterIdentification(kRand, kEDiv);
RunLoopUntilIdle();
// Pairing should have succeeded.
EXPECT_EQ(0, pairing_failed_count());
EXPECT_EQ(1, pairing_complete_count());
EXPECT_TRUE(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(SMP_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, master_ident_count());
UInt128 stk;
FastForwardToPhase3(&stk, false /*secure_connections*/, 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, master_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);
RunLoopUntilIdle();
// 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(SMP_ResponderPairingTest, AssignLongTermKeyFailsDuringPairing) {
ReceivePairingRequest();
RunLoopUntilIdle();
SecurityProperties sec_props(SecurityLevel::kAuthenticated, 16, false);
EXPECT_FALSE(pairing()->AssignLongTermKey(LTK(sec_props, hci::LinkKey())));
EXPECT_EQ(0, fake_link()->start_encryption_count());
EXPECT_EQ(SecurityLevel::kNoSecurity, pairing()->security().level());
}
TEST_F(SMP_ResponderPairingTest, AssignLongTermKey) {
SecurityProperties sec_props(SecurityLevel::kAuthenticated, 16, false);
LTK ltk(sec_props, hci::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(hci::Status(), true /* enabled */);
RunLoopUntilIdle();
EXPECT_EQ(1, new_sec_props_count());
EXPECT_EQ(sec_props, new_sec_props());
EXPECT_EQ(sec_props, pairing()->security());
}
TEST_F(SMP_ResponderPairingTest, EncryptWithLinkKeyModifiedOutsideSmDisconnects) {
SecurityProperties sec_props(SecurityLevel::kAuthenticated, 16, false);
const LTK kOriginalLtk(sec_props, hci::LinkKey({1}, 2, 3));
const hci::LinkKey kModifiedLtk(hci::LinkKey({4}, 5, 6));
EXPECT_TRUE(pairing()->AssignLongTermKey(kOriginalLtk));
fake_link()->set_le_ltk(kModifiedLtk);
fake_link()->TriggerEncryptionChangeCallback(hci::Status(), true /*enabled*/);
RunLoopUntilIdle();
ASSERT_TRUE(fake_chan()->link_error());
ASSERT_EQ(1, auth_failure_callback_count());
ASSERT_EQ(hci::StatusCode::kPinOrKeyMissing, auth_failure_status().protocol_error());
}
TEST_F(SMP_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_le_ltk(hci::LinkKey({1}, 2, 3));
fake_link()->TriggerEncryptionChangeCallback(hci::Status(), true /*enabled*/);
RunLoopUntilIdle();
ASSERT_TRUE(fake_chan()->link_error());
ASSERT_EQ(1, auth_failure_callback_count());
ASSERT_EQ(hci::StatusCode::kPinOrKeyMissing, auth_failure_status().protocol_error());
}
// As responder, we ignore security requests and don't send a Pairing Request or encrypt the link
// in response.
TEST_F(SMP_ResponderPairingTest, ReceiveSecurityRequest) {
ReceiveSecurityRequest();
EXPECT_EQ(0, pairing_request_count());
EXPECT_EQ(0, fake_link()->start_encryption_count());
}
// Test that LTK is generated and passed up to SecurityManager when both sides request bonding
TEST_F(SMP_ResponderPairingTest, BothSidesRequestBondingLTKCreated) {
UInt128 stk;
SetUpSecurityManager(IOCapability::kDisplayOnly);
FastForwardToPhase3(&stk, false /*secure_connections*/, 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(SMP_ResponderPairingTest, LocalRequestsNonBondableNoLTKCreated) {
UInt128 stk;
SetUpSecurityManager(IOCapability::kDisplayOnly, BondableMode::NonBondable);
FastForwardToPhase3(&stk, false /*secure_connections*/, 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(SMP_ResponderPairingTest, PeerRequestsNonBondableNoLTKCreated) {
UInt128 stk;
SetUpSecurityManager(IOCapability::kDisplayOnly, BondableMode::Bondable);
FastForwardToPhase3(&stk, false /*secure_connections*/, 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(SMP_ResponderPairingTest, BothSidesRequestNonBondableNoLTKCreated) {
UInt128 stk;
SetUpSecurityManager(IOCapability::kDisplayOnly, BondableMode::NonBondable);
FastForwardToPhase3(&stk, false /*secure_connections*/, 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(SMP_ResponderPairingTest, PairingRequestStartsPairingTimer) {
ReceivePairingRequest();
RunLoopFor(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(HostError::kTimedOut, pairing_complete_status().error());
EXPECT_EQ(0, security_callback_count());
}
TEST_F(SMP_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);
RunLoopUntilIdle();
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);
RunLoopUntilIdle();
EXPECT_EQ(1, pairing_failed_count());
EXPECT_EQ(1, security_callback_count());
EXPECT_EQ(ErrorCode::kAuthenticationRequirements, security_status().protocol_error());
EXPECT_EQ(1, pairing_complete_count());
EXPECT_EQ(security_status(), pairing_complete_status());
}
TEST_F(SMP_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);
RunLoopUntilIdle();
EXPECT_EQ(1, pairing_failed_count());
EXPECT_EQ(1, pairing_complete_count());
EXPECT_EQ(ErrorCode::kEncryptionKeySize, pairing_complete_status().protocol_error());
}
// Tests that Secure Connections works as responder
TEST_F(SMP_ResponderPairingTest, SecureConnectionsWorks) {
// Must have DisplayYesNo IOC to generate Authenticated security per kExpectedSecurity
SetUpSecurityManager(IOCapability::kDisplayYesNo);
UInt128 ltk_bytes;
const SecurityProperties kExpectedSecurity(SecurityLevel::kAuthenticated, kMaxEncryptionKeySize,
true /* secure connections */);
FastForwardToPhase3(&ltk_bytes, true /*secure_connections*/, kExpectedSecurity.level());
const LTK kExpectedLtk(kExpectedSecurity, hci::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_TRUE(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