blob: a9f82fe182b1d1d76c25bfe8f6143346e014258b [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 "pairing_state.h"
#include "garnet/drivers/bluetooth/lib/common/test_helpers.h"
#include "garnet/drivers/bluetooth/lib/hci/fake_connection.h"
#include "garnet/drivers/bluetooth/lib/l2cap/fake_channel_test.h"
#include "garnet/drivers/bluetooth/lib/sm/packet.h"
#include "util.h"
#include "lib/fxl/macros.h"
#include "lib/fxl/random/rand.h"
namespace btlib {
using common::ByteBuffer;
using common::DeviceAddress;
using common::StaticByteBuffer;
using common::UInt128;
namespace sm {
namespace {
const DeviceAddress kLocalAddr(DeviceAddress::Type::kLEPublic,
"A1:A2:A3:A4:A5:A6");
const DeviceAddress kPeerAddr(DeviceAddress::Type::kLERandom,
"B1:B2:B3:B4:B5:B6");
class SMP_PairingStateTest : public l2cap::testing::FakeChannelTest {
public:
SMP_PairingStateTest() = default;
~SMP_PairingStateTest() override = default;
protected:
void TearDown() override {
RunLoopUntilIdle();
pairing_ = nullptr;
}
void NewPairingState(IOCapability ioc) {
pairing_ = std::make_unique<PairingState>(ioc);
pairing_->set_le_ltk_callback(
fit::bind_member(this, &SMP_PairingStateTest::OnNewLTK));
}
void RegisterLE(hci::Connection::Role role) {
FXL_DCHECK(pairing_);
ChannelOptions options(l2cap::kLESMPChannelId);
fake_chan_ = CreateFakeChannel(options);
fake_chan_->SetSendCallback(
fit::bind_member(this, &SMP_PairingStateTest::OnDataReceived),
dispatcher());
fake_link_ = std::make_unique<hci::testing::FakeConnection>(
1, hci::Connection::LinkType::kLE, role, kLocalAddr, kPeerAddr);
pairing_->RegisterLE(fake_link_->WeakPtr(), fake_chan_);
}
// Called by |pairing_| when a new LTK is obtained.
void OnNewLTK(const LTK& ltk) {
ltk_callback_count_++;
ltk_ = ltk;
}
void UpdateSecurity(SecurityLevel level) {
FXL_DCHECK(pairing_);
pairing_->UpdateSecurity(level, [this](auto status, const auto& props) {
pairing_callback_count_++;
pairing_status_ = status;
sec_props_ = props;
});
}
// Called when SMP sends a packet over the fake channel.
void OnDataReceived(std::unique_ptr<const ByteBuffer> packet) {
FXL_DCHECK(packet);
PacketReader reader(packet.get());
switch (reader.code()) {
case kPairingFailed:
pairing_failed_count_++;
received_error_code_ = reader.payload<PairingFailedParams>();
break;
case kPairingRequest:
pairing_request_count_++;
packet->Copy(&local_pairing_cmd_);
break;
case kPairingResponse:
pairing_response_count_++;
packet->Copy(&local_pairing_cmd_);
break;
case kPairingConfirm:
pairing_confirm_count_++;
pairing_confirm_ = reader.payload<PairingConfirmValue>();
break;
case kPairingRandom:
pairing_random_count_++;
pairing_random_ = reader.payload<PairingRandomValue>();
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 ReceivePairingConfirm(const UInt128& confirm) {
Receive128BitCmd(kPairingConfirm, confirm);
}
void ReceivePairingRandom(const UInt128& random) {
Receive128BitCmd(kPairingRandom, random);
}
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 GenerateConfirmValue(const UInt128& random, UInt128* out_value,
bool peer_initiator = false) {
FXL_DCHECK(out_value);
UInt128 tk;
tk.fill(0);
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(tk, random, *preq, *pres, *init_addr, *rsp_addr, out_value);
}
PairingState* 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 pairing_callback_count() const { return pairing_callback_count_; }
ErrorCode received_error_code() const { return received_error_code_; }
const Status& pairing_status() const { return pairing_status_; }
const SecurityProperties& sec_props() const { return sec_props_; }
int ltk_callback_count() const { return ltk_callback_count_; }
const LTK& ltk() const { return ltk_; }
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_confirm_count() const { return pairing_confirm_count_; }
int pairing_random_count() const { return pairing_random_count_; }
const UInt128& pairing_confirm() const { return pairing_confirm_; }
const UInt128& pairing_random() const { return pairing_random_; }
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 UpdateSecurity has been
// called and the most recent parameters that it was called with.
int pairing_callback_count_ = 0;
Status pairing_status_;
SecurityProperties sec_props_;
// Number of times the LTK callback has been called and the most recent LTK
// that it was called with.
int ltk_callback_count_ = 0;
LTK ltk_;
// Counts of commands that we have sent out to the peer.
int pairing_failed_count_ = 0;
int pairing_request_count_ = 0;
int pairing_response_count_ = 0;
int pairing_confirm_count_ = 0;
int pairing_random_count_ = 0;
// Values that have been sent by the peer.
UInt128 pairing_confirm_;
UInt128 pairing_random_;
ErrorCode received_error_code_ = ErrorCode::kNoError;
fbl::RefPtr<l2cap::testing::FakeChannel> fake_chan_;
std::unique_ptr<hci::testing::FakeConnection> fake_link_;
std::unique_ptr<PairingState> pairing_;
FXL_DISALLOW_COPY_AND_ASSIGN(SMP_PairingStateTest);
};
class SMP_MasterPairingTest : public SMP_PairingStateTest {
public:
SMP_MasterPairingTest() = default;
~SMP_MasterPairingTest() override = default;
void SetUp() override { SetUpPairingState(); }
void SetUpPairingState(IOCapability ioc = IOCapability::kDisplayOnly) {
NewPairingState(ioc);
RegisterLE(hci::Connection::Role::kMaster);
}
void GenerateMatchingConfirmAndRandom(UInt128* out_confirm,
UInt128* out_random) {
FXL_DCHECK(out_confirm);
FXL_DCHECK(out_random);
fxl::RandBytes(out_random->data(), out_random->size());
GenerateConfirmValue(*out_random, out_confirm);
}
// Emulate legacy pairing up until before encryption with STK. Returns the STK
// that the master is expected to encrypt the link with in |out_stk|.
void FastForwardToSTK(UInt128* out_stk,
SecurityLevel level = SecurityLevel::kEncrypted,
KeyDistGenField remote_keys = 0,
KeyDistGenField local_keys = 0) {
UpdateSecurity(level);
PairingRequestParams pairing_params;
pairing_params.io_capability = IOCapability::kNoInputNoOutput;
pairing_params.auth_req = 0;
pairing_params.max_encryption_key_size = kMaxEncryptionKeySize;
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;
GenerateMatchingConfirmAndRandom(&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, pairing_callback_count());
FXL_DCHECK(out_stk);
UInt128 tk;
tk.fill(0);
util::S1(tk, srand, pairing_random(), out_stk);
}
private:
FXL_DISALLOW_COPY_AND_ASSIGN(SMP_MasterPairingTest);
};
class SMP_SlavePairingTest : public SMP_PairingStateTest {
public:
SMP_SlavePairingTest() = default;
~SMP_SlavePairingTest() override = default;
void SetUp() override { SetUpPairingState(); }
void SetUpPairingState(IOCapability ioc = IOCapability::kDisplayOnly) {
NewPairingState(ioc);
RegisterLE(hci::Connection::Role::kSlave);
}
void GenerateMatchingConfirmAndRandom(UInt128* out_confirm,
UInt128* out_random) {
FXL_DCHECK(out_confirm);
FXL_DCHECK(out_random);
fxl::RandBytes(out_random->data(), out_random->size());
GenerateConfirmValue(*out_random, out_confirm, true /* peer_initiator */);
}
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 */);
}
private:
FXL_DISALLOW_COPY_AND_ASSIGN(SMP_SlavePairingTest);
};
// Requesting pairing at the current security level should succeed immediately.
TEST_F(SMP_MasterPairingTest, UpdateSecurityCurrentLevel) {
UpdateSecurity(SecurityLevel::kNoSecurity);
RunLoopUntilIdle();
// No pairing requests should have been made.
EXPECT_EQ(0, pairing_request_count());
// Pairing should succeed.
EXPECT_EQ(1, pairing_callback_count());
EXPECT_TRUE(pairing_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_MasterPairingTest, PairingFailedInPhase1) {
UpdateSecurity(SecurityLevel::kEncrypted);
RunLoopUntilIdle();
// Pairing not complete yet but we should be in Phase 1.
EXPECT_EQ(0, pairing_callback_count());
EXPECT_EQ(1, pairing_request_count());
ReceivePairingFailed(ErrorCode::kPairingNotSupported);
RunLoopUntilIdle();
EXPECT_EQ(1, pairing_callback_count());
EXPECT_EQ(1, pairing_request_count());
EXPECT_EQ(ErrorCode::kPairingNotSupported, pairing_status().protocol_error());
}
// Reject pairing if not using JustWorks.
// TODO(armansito): This is temporary but the test here to document the interim
// behavior until the TK gets obtained asynchronously.
TEST_F(SMP_MasterPairingTest, RejectIfNotJustWorks) {
UpdateSecurity(SecurityLevel::kEncrypted);
RunLoopUntilIdle();
// Pick I/O capabilities and MITM flags that will result in authenticated
// pairing.
ReceivePairingFeatures(IOCapability::kKeyboardOnly, AuthReq::kMITM);
RunLoopUntilIdle();
EXPECT_EQ(1, pairing_callback_count());
EXPECT_EQ(1, pairing_request_count());
EXPECT_EQ(ErrorCode::kUnspecifiedReason, pairing_status().protocol_error());
}
TEST_F(SMP_MasterPairingTest, 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, pairing_callback_count());
}
TEST_F(SMP_MasterPairingTest, ReceiveConfirmValueInPhase1) {
UpdateSecurity(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, pairing_callback_count());
EXPECT_EQ(ErrorCode::kUnspecifiedReason, pairing_status().protocol_error());
}
TEST_F(SMP_MasterPairingTest, 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, pairing_callback_count());
}
TEST_F(SMP_MasterPairingTest, ReceiveRandomValueInPhase1) {
UpdateSecurity(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, pairing_callback_count());
EXPECT_EQ(ErrorCode::kUnspecifiedReason, pairing_status().protocol_error());
}
TEST_F(SMP_MasterPairingTest, LegacyPhase2SlaveConfirmValueReceivedTwice) {
UpdateSecurity(SecurityLevel::kEncrypted);
RunLoopUntilIdle();
ReceivePairingFeatures();
RunLoopUntilIdle();
// Should have received Mconfirm.
EXPECT_EQ(1, pairing_confirm_count());
EXPECT_EQ(0, pairing_random_count());
EXPECT_EQ(0, pairing_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, pairing_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, pairing_callback_count());
EXPECT_EQ(ErrorCode::kUnspecifiedReason, pairing_status().protocol_error());
}
TEST_F(SMP_MasterPairingTest, LegacyPhase2ReceiveRandomValueInWrongOrder) {
UpdateSecurity(SecurityLevel::kEncrypted);
RunLoopUntilIdle();
ReceivePairingFeatures();
RunLoopUntilIdle();
// Should have received Mconfirm.
EXPECT_EQ(1, pairing_confirm_count());
EXPECT_EQ(0, pairing_random_count());
EXPECT_EQ(0, pairing_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, pairing_callback_count());
EXPECT_EQ(ErrorCode::kUnspecifiedReason, pairing_status().protocol_error());
}
TEST_F(SMP_MasterPairingTest, LegacyPhase2SlaveConfirmValueInvalid) {
UpdateSecurity(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, pairing_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, pairing_callback_count());
// Master's Mconfirm/Mrand should be correct.
UInt128 expected_confirm;
GenerateConfirmValue(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, pairing_callback_count());
EXPECT_EQ(ErrorCode::kConfirmValueFailed, pairing_status().protocol_error());
}
TEST_F(SMP_MasterPairingTest, LegacyPhase2RandomValueReceivedTwice) {
UpdateSecurity(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, pairing_callback_count());
// Receive Sconfirm and Srand values that match.
UInt128 confirm, random;
GenerateMatchingConfirmAndRandom(&confirm, &random);
ReceivePairingConfirm(confirm);
RunLoopUntilIdle();
// Should have received Mrand.
EXPECT_EQ(1, pairing_confirm_count());
EXPECT_EQ(1, pairing_random_count());
EXPECT_EQ(0, pairing_callback_count());
// Master's Mconfirm/Mrand should be correct.
UInt128 expected_confirm;
GenerateConfirmValue(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, pairing_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, pairing_callback_count());
EXPECT_EQ(ErrorCode::kUnspecifiedReason, pairing_status().protocol_error());
}
TEST_F(SMP_MasterPairingTest, LegacyPhase2ConfirmValuesExchanged) {
UpdateSecurity(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, pairing_callback_count());
// Receive Sconfirm and Srand values that match.
UInt128 confirm, random;
GenerateMatchingConfirmAndRandom(&confirm, &random);
ReceivePairingConfirm(confirm);
RunLoopUntilIdle();
// Should have received Mrand.
EXPECT_EQ(1, pairing_confirm_count());
EXPECT_EQ(1, pairing_random_count());
EXPECT_EQ(0, pairing_callback_count());
// Master's Mconfirm/Mrand should be correct.
UInt128 expected_confirm;
GenerateConfirmValue(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, pairing_callback_count());
}
// Peer aborts during Phase 2.
TEST_F(SMP_MasterPairingTest, PairingFailedInPhase2) {
UpdateSecurity(SecurityLevel::kEncrypted);
ReceivePairingFeatures();
RunLoopUntilIdle();
UInt128 confirm, random;
GenerateMatchingConfirmAndRandom(&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, pairing_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, pairing_callback_count());
EXPECT_EQ(ErrorCode::kConfirmValueFailed, pairing_status().protocol_error());
}
// Encryption with STK fails.
TEST_F(SMP_MasterPairingTest, 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(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, pairing_callback_count());
EXPECT_EQ(ErrorCode::kUnspecifiedReason, pairing_status().protocol_error());
EXPECT_EQ(ErrorCode::kUnspecifiedReason, received_error_code());
}
TEST_F(SMP_MasterPairingTest, 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());
fake_link()->TriggerEncryptionChangeCallback(hci::Status(),
false /* enabled */);
RunLoopUntilIdle();
EXPECT_EQ(1, pairing_failed_count());
EXPECT_EQ(1, pairing_callback_count());
EXPECT_EQ(ErrorCode::kUnspecifiedReason, pairing_status().protocol_error());
EXPECT_EQ(ErrorCode::kUnspecifiedReason, received_error_code());
}
// Tests that the pairing procedure ends after encryption with the STK if there
// are no keys to distribute.
TEST_F(SMP_MasterPairingTest, Phase3CompleteWithoutKeyExchange) {
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 notifying any keys. The pairing is
// temporary.
EXPECT_EQ(0, pairing_failed_count());
EXPECT_EQ(1, pairing_callback_count());
EXPECT_EQ(0, ltk_callback_count());
EXPECT_TRUE(pairing_status());
EXPECT_EQ(SecurityLevel::kEncrypted, sec_props().level());
EXPECT_EQ(16u, sec_props().enc_key_size());
EXPECT_FALSE(sec_props().secure_connections());
ASSERT_TRUE(fake_link()->ltk());
}
TEST_F(SMP_MasterPairingTest, Phase3EncryptionInformationReceivedTwice) {
UInt128 stk;
FastForwardToSTK(&stk, SecurityLevel::kEncrypted, KeyDistGen::kEncKey);
ASSERT_TRUE(fake_link()->ltk());
EXPECT_EQ(1, fake_link()->start_encryption_count());
fake_link()->TriggerEncryptionChangeCallback(hci::Status(),
true /* enabled */);
RunLoopUntilIdle();
// Pairing should still be in progress.
EXPECT_EQ(0, pairing_failed_count());
EXPECT_EQ(0, pairing_callback_count());
EXPECT_EQ(0, ltk_callback_count());
ReceiveEncryptionInformation(UInt128());
RunLoopUntilIdle();
// Waiting for EDIV and Rand
EXPECT_EQ(0, pairing_failed_count());
EXPECT_EQ(0, pairing_callback_count());
// Send the LTK twice. This should cause pairing to fail.
ReceiveEncryptionInformation(UInt128());
RunLoopUntilIdle();
EXPECT_EQ(1, pairing_failed_count());
EXPECT_EQ(1, pairing_callback_count());
EXPECT_EQ(ErrorCode::kUnspecifiedReason, pairing_status().protocol_error());
EXPECT_EQ(ErrorCode::kUnspecifiedReason, received_error_code());
}
// The slave sends EDIV and Rand before LTK.
TEST_F(SMP_MasterPairingTest, Phase3MasterIdentificationReceivedInWrongOrder) {
UInt128 stk;
FastForwardToSTK(&stk, SecurityLevel::kEncrypted, KeyDistGen::kEncKey);
ASSERT_TRUE(fake_link()->ltk());
EXPECT_EQ(1, fake_link()->start_encryption_count());
fake_link()->TriggerEncryptionChangeCallback(hci::Status(),
true /* enabled */);
RunLoopUntilIdle();
// Pairing should still be in progress.
EXPECT_EQ(0, pairing_failed_count());
EXPECT_EQ(0, pairing_callback_count());
EXPECT_EQ(0, ltk_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, pairing_callback_count());
EXPECT_EQ(ErrorCode::kUnspecifiedReason, pairing_status().protocol_error());
EXPECT_EQ(ErrorCode::kUnspecifiedReason, received_error_code());
}
TEST_F(SMP_MasterPairingTest, Phase3MasterIdentificationReceivedTwice) {
UInt128 stk;
FastForwardToSTK(&stk, SecurityLevel::kEncrypted, KeyDistGen::kEncKey);
ASSERT_TRUE(fake_link()->ltk());
EXPECT_EQ(1, fake_link()->start_encryption_count());
fake_link()->TriggerEncryptionChangeCallback(hci::Status(),
true /* enabled */);
RunLoopUntilIdle();
// Pairing should still be in progress.
EXPECT_EQ(0, pairing_failed_count());
EXPECT_EQ(0, pairing_callback_count());
EXPECT_EQ(0, ltk_callback_count());
ReceiveEncryptionInformation(UInt128());
ReceiveMasterIdentification(1, 2);
ReceiveMasterIdentification(1, 2);
RunLoopUntilIdle();
EXPECT_EQ(1, pairing_failed_count());
EXPECT_EQ(1, pairing_callback_count());
EXPECT_EQ(ErrorCode::kUnspecifiedReason, pairing_status().protocol_error());
EXPECT_EQ(ErrorCode::kUnspecifiedReason, received_error_code());
}
// Master starts encryption with LTK after receiving LTK, ediv, and rand.
// TODO(armansito): Test that the link isn't encrypted with the LTK until all
// keys are received if the remote key distribution has more than just "enc key"
// set.
TEST_F(SMP_MasterPairingTest, Phase3EncryptionWithLTKFails) {
UInt128 stk;
FastForwardToSTK(&stk, SecurityLevel::kEncrypted, KeyDistGen::kEncKey);
ASSERT_TRUE(fake_link()->ltk());
EXPECT_EQ(1, fake_link()->start_encryption_count());
fake_link()->TriggerEncryptionChangeCallback(hci::Status(),
true /* enabled */);
RunLoopUntilIdle();
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();
EXPECT_EQ(0, pairing_failed_count());
EXPECT_EQ(0, pairing_callback_count());
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());
EXPECT_EQ(2, fake_link()->start_encryption_count());
// Encryption fails.
fake_link()->TriggerEncryptionChangeCallback(
hci::Status(hci::StatusCode::kPinOrKeyMissing), false /* enabled */);
RunLoopUntilIdle();
EXPECT_EQ(ErrorCode::kUnspecifiedReason, pairing_status().protocol_error());
EXPECT_EQ(ErrorCode::kUnspecifiedReason, received_error_code());
}
// Master starts encryption with LTK after receiving LTK, ediv, and rand but it
// fails.
TEST_F(SMP_MasterPairingTest, Phase3EncryptionWithLTKSucceeds) {
UInt128 stk;
FastForwardToSTK(&stk, SecurityLevel::kEncrypted, KeyDistGen::kEncKey);
ASSERT_TRUE(fake_link()->ltk());
EXPECT_EQ(1, fake_link()->start_encryption_count());
fake_link()->TriggerEncryptionChangeCallback(hci::Status(),
true /* enabled */);
RunLoopUntilIdle();
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();
EXPECT_EQ(0, pairing_failed_count());
EXPECT_EQ(0, pairing_callback_count());
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());
EXPECT_EQ(2, fake_link()->start_encryption_count());
// Encryption succeeds.
fake_link()->TriggerEncryptionChangeCallback(hci::Status(),
true /* enabled */);
RunLoopUntilIdle();
// Pairing should succeed without notifying any keys.
EXPECT_EQ(0, pairing_failed_count());
EXPECT_EQ(1, pairing_callback_count());
EXPECT_TRUE(pairing_status());
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, ltk_callback_count());
EXPECT_EQ(sec_props(), ltk().security());
EXPECT_EQ(kLTK, ltk().key().value());
EXPECT_EQ(kRand, ltk().key().rand());
EXPECT_EQ(kEDiv, ltk().key().ediv());
}
TEST_F(SMP_SlavePairingTest, 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, pairing_callback_count());
// This should cause pairing to be aborted.
ReceivePairingRequest();
RunLoopUntilIdle();
EXPECT_EQ(0, pairing_request_count());
EXPECT_EQ(2, pairing_response_count());
EXPECT_EQ(0, pairing_confirm_count());
EXPECT_EQ(0, pairing_random_count());
EXPECT_EQ(1, pairing_failed_count());
EXPECT_EQ(0, pairing_callback_count());
EXPECT_EQ(ErrorCode::kUnspecifiedReason, received_error_code());
}
TEST_F(SMP_SlavePairingTest, 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, pairing_callback_count());
// Master 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, pairing_callback_count());
EXPECT_EQ(ErrorCode::kUnspecifiedReason, received_error_code());
}
TEST_F(SMP_SlavePairingTest, LegacyPhase2MasterConfirmValueInvalid) {
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, pairing_callback_count());
// Set up values that don't match.
UInt128 confirm, random;
confirm.fill(0);
random.fill(1);
ReceivePairingConfirm(confirm);
RunLoopUntilIdle();
// Slave 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, pairing_callback_count());
// Master sends Mrand that doesn't match. Slave 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, pairing_callback_count());
EXPECT_EQ(ErrorCode::kConfirmValueFailed, received_error_code());
}
TEST_F(SMP_SlavePairingTest, 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, pairing_callback_count());
// Set up Sconfirm and Srand values that match.
UInt128 confirm, random;
GenerateMatchingConfirmAndRandom(&confirm, &random);
// Master sends Mconfirm.
ReceivePairingConfirm(confirm);
RunLoopUntilIdle();
// Slave 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, pairing_callback_count());
// Master sends Mrand.
ReceivePairingRandom(random);
RunLoopUntilIdle();
// Slave 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, pairing_callback_count());
// Slave's Sconfirm/Srand should be correct.
UInt128 expected_confirm;
GenerateConfirmValue(pairing_random(), &expected_confirm,
true /* peer_initiator */);
EXPECT_EQ(expected_confirm, pairing_confirm());
}
// TODO(armansito): Add tests for Phase 3 in slave role
} // namespace
} // namespace sm
} // namespace btlib