| // 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" |
| |
| 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 sm::PairingState::Delegate { |
| public: |
| SMP_PairingStateTest() : weak_ptr_factory_(this) {} |
| ~SMP_PairingStateTest() override = default; |
| |
| protected: |
| void TearDown() override { |
| RunLoopUntilIdle(); |
| DestroyPairingState(); |
| } |
| |
| void NewPairingState(hci::Connection::Role role, IOCapability ioc) { |
| // Setup fake SMP channel. |
| ChannelOptions options(l2cap::kLESMPChannelId); |
| fake_chan_ = CreateFakeChannel(options); |
| fake_chan_->SetSendCallback( |
| fit::bind_member(this, &SMP_PairingStateTest::OnDataReceived), |
| dispatcher()); |
| |
| // Setup a fake logical link. |
| fake_link_ = std::make_unique<hci::testing::FakeConnection>( |
| 1, hci::Connection::LinkType::kLE, role, kLocalAddr, kPeerAddr); |
| |
| pairing_ = std::make_unique<PairingState>( |
| fake_link_->WeakPtr(), fake_chan_, ioc, weak_ptr_factory_.GetWeakPtr()); |
| } |
| |
| void DestroyPairingState() { pairing_ = nullptr; } |
| |
| // Called by |pairing_| to obtain a Temporary Key during legacy pairing. |
| void OnTemporaryKeyRequest( |
| PairingMethod method, |
| PairingState::Delegate::TkResponse responder) override { |
| if (tk_delegate_) { |
| tk_delegate_(method, std::move(responder)); |
| } else { |
| responder(true /* success */, 0); |
| } |
| } |
| |
| // 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; |
| } |
| |
| void UpgradeSecurity(SecurityLevel level) { |
| ZX_DEBUG_ASSERT(pairing_); |
| pairing_->UpgradeSecurity(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) { |
| ZX_DEBUG_ASSERT(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 ReceiveIdentityResolvingKey(const UInt128& irk) { |
| Receive128BitCmd(kIdentityInformation, irk); |
| } |
| |
| 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 GenerateConfirmValue(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); |
| } |
| |
| 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 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_; |
| } |
| |
| const std::optional<LTK>& ltk() const { return pairing_data_.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 TkDelegate = |
| fit::function<void(PairingMethod, PairingState::Delegate::TkResponse)>; |
| void set_tk_delegate(TkDelegate delegate) { |
| tk_delegate_ = std::move(delegate); |
| } |
| |
| 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 UpgradeSecurity 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 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_; |
| |
| // 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_; |
| |
| // Callback used to notify when a call to OnTKRequest() is received. |
| // OnTKRequest() will reply with 0 if a callback is not set. |
| TkDelegate tk_delegate_; |
| |
| // 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::WeakPtrFactory<SMP_PairingStateTest> weak_ptr_factory_; |
| |
| 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(hci::Connection::Role::kMaster, ioc); |
| } |
| |
| void GenerateMatchingConfirmAndRandom(UInt128* out_confirm, |
| UInt128* out_random, uint32_t tk = 0) { |
| ZX_DEBUG_ASSERT(out_confirm); |
| ZX_DEBUG_ASSERT(out_random); |
| *out_random = common::RandomUInt128(); |
| GenerateConfirmValue(*out_random, out_confirm, false /* peer_initiator */, |
| tk); |
| } |
| |
| // 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|. |
| // |
| // 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 |
| // FastForwardToSTKEncrypted() to also emulate successful encryption. |
| void FastForwardToSTK(UInt128* out_stk, |
| SecurityLevel level = SecurityLevel::kEncrypted, |
| KeyDistGenField remote_keys = 0, |
| KeyDistGenField local_keys = 0) { |
| UpgradeSecurity(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()); |
| |
| ZX_DEBUG_ASSERT(out_stk); |
| |
| UInt128 tk; |
| tk.fill(0); |
| util::S1(tk, srand, pairing_random(), out_stk); |
| } |
| |
| void FastForwardToSTKEncrypted( |
| UInt128* out_stk, SecurityLevel level = SecurityLevel::kEncrypted, |
| KeyDistGenField remote_keys = 0, KeyDistGenField local_keys = 0) { |
| FastForwardToSTK(out_stk, level, remote_keys, local_keys); |
| |
| 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(); |
| } |
| |
| 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(hci::Connection::Role::kSlave, ioc); |
| } |
| |
| void GenerateMatchingConfirmAndRandom(UInt128* out_confirm, |
| UInt128* out_random, uint32_t tk = 0) { |
| ZX_DEBUG_ASSERT(out_confirm); |
| ZX_DEBUG_ASSERT(out_random); |
| zx_cprng_draw(out_random->data(), out_random->size()); |
| GenerateConfirmValue(*out_random, out_confirm, true /* peer_initiator */, |
| tk); |
| } |
| |
| 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, 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, 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) { |
| UpgradeSecurity(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()); |
| |
| EXPECT_EQ(1, pairing_complete_count()); |
| EXPECT_EQ(pairing_status(), pairing_complete_status()); |
| } |
| |
| // Local aborts during Phase 1. |
| TEST_F(SMP_MasterPairingTest, PairingAbortedInPhase1) { |
| UpgradeSecurity(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()); |
| |
| pairing()->Abort(); |
| RunLoopUntilIdle(); |
| |
| EXPECT_EQ(1, pairing_callback_count()); |
| EXPECT_EQ(1, pairing_request_count()); |
| EXPECT_EQ(ErrorCode::kUnspecifiedReason, pairing_status().protocol_error()); |
| |
| EXPECT_EQ(1, pairing_complete_count()); |
| EXPECT_EQ(pairing_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_MasterPairingTest, PairingStateResetDuringPairing) { |
| UpgradeSecurity(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()); |
| |
| pairing()->Reset(IOCapability::kNoInputNoOutput); |
| RunLoopUntilIdle(); |
| |
| EXPECT_EQ(1, pairing_callback_count()); |
| EXPECT_EQ(1, pairing_request_count()); |
| EXPECT_EQ(ErrorCode::kUnspecifiedReason, pairing_status().protocol_error()); |
| |
| EXPECT_EQ(1, pairing_complete_count()); |
| EXPECT_EQ(pairing_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_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) { |
| 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, pairing_callback_count()); |
| EXPECT_EQ(ErrorCode::kUnspecifiedReason, pairing_status().protocol_error()); |
| |
| EXPECT_EQ(1, pairing_complete_count()); |
| EXPECT_EQ(pairing_status(), pairing_complete_status()); |
| } |
| |
| // In Phase 2 but still waiting to receive TK. |
| TEST_F(SMP_MasterPairingTest, ReceiveConfirmValueWhileWaitingForTK) { |
| bool tk_requested = false; |
| set_tk_delegate([&](auto, auto) { 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, pairing_callback_count()); |
| EXPECT_EQ(ErrorCode::kUnspecifiedReason, pairing_status().protocol_error()); |
| |
| EXPECT_EQ(1, pairing_complete_count()); |
| EXPECT_EQ(pairing_status(), pairing_complete_status()); |
| } |
| |
| // PairingState destroyed when TKResponse runs. |
| TEST_F(SMP_MasterPairingTest, PairingStateDestroyedStateWhileWaitingForTK) { |
| PairingState::Delegate::TkResponse respond; |
| set_tk_delegate([&](auto, auto rsp) { respond = std::move(rsp); }); |
| |
| UpgradeSecurity(SecurityLevel::kEncrypted); |
| ReceivePairingFeatures(); |
| RunLoopUntilIdle(); |
| EXPECT_TRUE(respond); |
| |
| DestroyPairingState(); |
| |
| // This should proceed safely. |
| respond(true, 0); |
| RunLoopUntilIdle(); |
| } |
| |
| // Pairing no longer in progress when TKResponse runs. |
| TEST_F(SMP_MasterPairingTest, PairingAbortedWhileWaitingForTK) { |
| PairingState::Delegate::TkResponse respond; |
| set_tk_delegate([&](auto, auto rsp) { respond = std::move(rsp); }); |
| |
| UpgradeSecurity(SecurityLevel::kEncrypted); |
| ReceivePairingFeatures(); |
| RunLoopUntilIdle(); |
| EXPECT_TRUE(respond); |
| |
| ReceivePairingFailed(ErrorCode::kPairingNotSupported); |
| RunLoopUntilIdle(); |
| EXPECT_EQ(1, pairing_callback_count()); |
| EXPECT_EQ(ErrorCode::kPairingNotSupported, pairing_status().protocol_error()); |
| |
| EXPECT_EQ(1, pairing_complete_count()); |
| EXPECT_EQ(pairing_status(), pairing_complete_status()); |
| |
| // This should have no effect. |
| respond(true, 0); |
| 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, pairing_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_MasterPairingTest, PairingRestartedWhileWaitingForTK) { |
| PairingState::Delegate::TkResponse respond; |
| set_tk_delegate([&](auto, auto rsp) { respond = std::move(rsp); }); |
| |
| UpgradeSecurity(SecurityLevel::kEncrypted); |
| ReceivePairingFeatures(); |
| RunLoopUntilIdle(); |
| EXPECT_TRUE(respond); |
| |
| // Stop pairing. |
| ReceivePairingFailed(ErrorCode::kPairingNotSupported); |
| RunLoopUntilIdle(); |
| EXPECT_EQ(1, pairing_callback_count()); |
| EXPECT_EQ(ErrorCode::kPairingNotSupported, pairing_status().protocol_error()); |
| |
| EXPECT_EQ(1, pairing_complete_count()); |
| EXPECT_EQ(pairing_status(), pairing_complete_status()); |
| |
| // Reset the delegate so that |respond| doesn't get overwritten by the second |
| // pairing. |
| set_tk_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, pairing_callback_count()); |
| EXPECT_EQ(0, pairing_data_callback_count()); |
| |
| // This should have no effect. |
| respond(true, 0); |
| 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, pairing_callback_count()); |
| EXPECT_EQ(1, pairing_complete_count()); |
| EXPECT_EQ(0, pairing_data_callback_count()); |
| } |
| |
| 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) { |
| 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, pairing_callback_count()); |
| EXPECT_EQ(ErrorCode::kUnspecifiedReason, pairing_status().protocol_error()); |
| |
| EXPECT_EQ(1, pairing_complete_count()); |
| EXPECT_EQ(pairing_status(), pairing_complete_status()); |
| } |
| |
| // In Phase 2 but still waiting to receive TK. |
| TEST_F(SMP_MasterPairingTest, ReceiveRandomValueWhileWaitingForTK) { |
| bool tk_requested = false; |
| set_tk_delegate([&](auto, auto) { tk_requested = true; }); |
| |
| UpgradeSecurity(SecurityLevel::kEncrypted); |
| ReceivePairingFeatures(); |
| RunLoopUntilIdle(); |
| EXPECT_TRUE(tk_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, pairing_callback_count()); |
| EXPECT_EQ(ErrorCode::kUnspecifiedReason, pairing_status().protocol_error()); |
| |
| EXPECT_EQ(1, pairing_complete_count()); |
| EXPECT_EQ(pairing_status(), pairing_complete_status()); |
| } |
| |
| TEST_F(SMP_MasterPairingTest, LegacyPhase2SlaveConfirmValueReceivedTwice) { |
| 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, 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()); |
| |
| EXPECT_EQ(1, pairing_complete_count()); |
| EXPECT_EQ(pairing_status(), pairing_complete_status()); |
| } |
| |
| TEST_F(SMP_MasterPairingTest, 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, 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()); |
| |
| EXPECT_EQ(1, pairing_complete_count()); |
| EXPECT_EQ(pairing_status(), pairing_complete_status()); |
| } |
| |
| TEST_F(SMP_MasterPairingTest, LegacyPhase2SlaveConfirmValueInvalid) { |
| 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, 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()); |
| |
| EXPECT_EQ(1, pairing_complete_count()); |
| EXPECT_EQ(pairing_status(), pairing_complete_status()); |
| } |
| |
| TEST_F(SMP_MasterPairingTest, 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, 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()); |
| |
| EXPECT_EQ(1, pairing_complete_count()); |
| EXPECT_EQ(pairing_status(), pairing_complete_status()); |
| } |
| |
| TEST_F(SMP_MasterPairingTest, 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, 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()); |
| } |
| |
| // TK delegate rejects pairing. When pairing method is "PasskeyEntryInput", this |
| // should result in a "Passkey Entry Failed" error. |
| TEST_F(SMP_MasterPairingTest, LegacyPhase2TKDelegateRejectsPasskeyInput) { |
| SetUpPairingState(IOCapability::kKeyboardOnly); |
| |
| bool tk_requested = false; |
| PairingState::Delegate::TkResponse respond; |
| PairingMethod method = PairingMethod::kJustWorks; |
| set_tk_delegate([&](auto cb_method, auto cb_rsp) { |
| tk_requested = true; |
| 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::kDisplayOnly, AuthReq::kMITM); |
| RunLoopUntilIdle(); |
| ASSERT_TRUE(tk_requested); |
| EXPECT_EQ(PairingMethod::kPasskeyEntryInput, method); |
| |
| // Reject pairing. |
| respond(false, 0); |
| 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::kPasskeyEntryFailed, pairing_status().protocol_error()); |
| } |
| |
| // TK delegate rejects pairing. |
| TEST_F(SMP_MasterPairingTest, LegacyPhase2TKDelegateRejectsPairing) { |
| bool tk_requested = false; |
| PairingState::Delegate::TkResponse respond; |
| PairingMethod method = PairingMethod::kPasskeyEntryDisplay; |
| set_tk_delegate([&](auto cb_method, auto cb_rsp) { |
| tk_requested = true; |
| method = cb_method; |
| respond = std::move(cb_rsp); |
| }); |
| |
| UpgradeSecurity(SecurityLevel::kEncrypted); |
| RunLoopUntilIdle(); |
| |
| ReceivePairingFeatures(); |
| RunLoopUntilIdle(); |
| ASSERT_TRUE(tk_requested); |
| EXPECT_EQ(PairingMethod::kJustWorks, method); |
| |
| // Reject pairing. |
| respond(false, 0); |
| 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()); |
| } |
| |
| // The TK delegate is called with the correct pairing method and the TK is |
| // factored into the confirm value generation. |
| TEST_F(SMP_MasterPairingTest, LegacyPhase2ConfirmValuesExchangedWithUserTK) { |
| constexpr uint32_t kTK = 123456; |
| |
| bool tk_requested = false; |
| PairingState::Delegate::TkResponse respond; |
| PairingMethod method = PairingMethod::kJustWorks; |
| set_tk_delegate([&](auto cb_method, auto cb_rsp) { |
| tk_requested = true; |
| 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_requested); |
| |
| // Local is DisplayOnly and peer is KeyboardOnly. Local displays passkey. |
| EXPECT_EQ(PairingMethod::kPasskeyEntryDisplay, method); |
| |
| // Send TK. |
| respond(true, kTK); |
| 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, kTK); |
| |
| 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, |
| false /* peer_initiator */, kTK); |
| 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) { |
| UpgradeSecurity(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(1, auth_failure_callback_count()); |
| EXPECT_EQ(ErrorCode::kUnspecifiedReason, pairing_status().protocol_error()); |
| EXPECT_EQ(ErrorCode::kUnspecifiedReason, received_error_code()); |
| EXPECT_EQ(hci::StatusCode::kPinOrKeyMissing, |
| auth_failure_status().protocol_error()); |
| } |
| |
| 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(0, auth_failure_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 any pairing data. |
| EXPECT_EQ(1, pairing_data_callback_count()); |
| EXPECT_FALSE(ltk()); |
| EXPECT_FALSE(irk()); |
| EXPECT_FALSE(identity()); |
| EXPECT_FALSE(csrk()); |
| |
| EXPECT_EQ(0, pairing_failed_count()); |
| EXPECT_EQ(1, pairing_callback_count()); |
| EXPECT_EQ(1, pairing_complete_count()); |
| EXPECT_TRUE(pairing_status()); |
| EXPECT_EQ(pairing_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()); |
| |
| ASSERT_TRUE(fake_link()->ltk()); |
| } |
| |
| TEST_F(SMP_MasterPairingTest, Phase3EncryptionInformationReceivedTwice) { |
| UInt128 stk; |
| FastForwardToSTKEncrypted(&stk, SecurityLevel::kEncrypted, |
| KeyDistGen::kEncKey); |
| |
| // Pairing should still be in progress. |
| EXPECT_EQ(0, pairing_failed_count()); |
| EXPECT_EQ(0, pairing_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, 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(1, pairing_complete_count()); |
| EXPECT_EQ(ErrorCode::kUnspecifiedReason, pairing_status().protocol_error()); |
| EXPECT_EQ(ErrorCode::kUnspecifiedReason, received_error_code()); |
| EXPECT_EQ(pairing_status(), pairing_complete_status()); |
| } |
| |
| // The slave sends EDIV and Rand before LTK. |
| TEST_F(SMP_MasterPairingTest, Phase3MasterIdentificationReceivedInWrongOrder) { |
| UInt128 stk; |
| FastForwardToSTKEncrypted(&stk, SecurityLevel::kEncrypted, |
| KeyDistGen::kEncKey); |
| |
| // Pairing should still be in progress. |
| EXPECT_EQ(0, pairing_failed_count()); |
| EXPECT_EQ(0, pairing_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, pairing_callback_count()); |
| EXPECT_EQ(1, pairing_complete_count()); |
| EXPECT_EQ(ErrorCode::kUnspecifiedReason, pairing_status().protocol_error()); |
| EXPECT_EQ(ErrorCode::kUnspecifiedReason, received_error_code()); |
| EXPECT_EQ(pairing_status(), pairing_complete_status()); |
| } |
| |
| TEST_F(SMP_MasterPairingTest, Phase3MasterIdentificationReceivedTwice) { |
| UInt128 stk; |
| FastForwardToSTKEncrypted(&stk, SecurityLevel::kEncrypted, |
| KeyDistGen::kEncKey); |
| |
| // Pairing should still be in progress. |
| EXPECT_EQ(0, pairing_failed_count()); |
| EXPECT_EQ(0, pairing_callback_count()); |
| EXPECT_EQ(0, pairing_data_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(1, pairing_complete_count()); |
| EXPECT_EQ(ErrorCode::kUnspecifiedReason, pairing_status().protocol_error()); |
| EXPECT_EQ(ErrorCode::kUnspecifiedReason, received_error_code()); |
| EXPECT_EQ(pairing_status(), pairing_complete_status()); |
| } |
| |
| // 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; |
| FastForwardToSTKEncrypted(&stk, SecurityLevel::kEncrypted, |
| KeyDistGen::kEncKey); |
| |
| 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(1, pairing_complete_count()); |
| EXPECT_EQ(1, auth_failure_callback_count()); |
| EXPECT_EQ(ErrorCode::kUnspecifiedReason, pairing_status().protocol_error()); |
| EXPECT_EQ(ErrorCode::kUnspecifiedReason, received_error_code()); |
| EXPECT_EQ(pairing_status(), pairing_complete_status()); |
| EXPECT_EQ(hci::StatusCode::kPinOrKeyMissing, |
| auth_failure_status().protocol_error()); |
| } |
| |
| // Pairing completes after obtaining encryption information only. |
| TEST_F(SMP_MasterPairingTest, Phase3CompleteWithEncKey) { |
| UInt128 stk; |
| FastForwardToSTKEncrypted(&stk, 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(); |
| |
| 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_EQ(1, pairing_complete_count()); |
| EXPECT_TRUE(pairing_status()); |
| EXPECT_EQ(pairing_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()); |
| |
| // Should have notified the LTK. |
| EXPECT_EQ(1, pairing_data_callback_count()); |
| ASSERT_TRUE(ltk()); |
| ASSERT_FALSE(irk()); |
| ASSERT_FALSE(identity()); |
| ASSERT_FALSE(csrk()); |
| 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_MasterPairingTest, Phase3IRKReceivedTwice) { |
| UInt128 stk; |
| FastForwardToSTKEncrypted(&stk, SecurityLevel::kEncrypted, |
| KeyDistGen::kIdKey); |
| |
| // Pairing should still be in progress. |
| EXPECT_EQ(0, pairing_failed_count()); |
| EXPECT_EQ(0, pairing_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, pairing_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, pairing_callback_count()); |
| EXPECT_EQ(1, pairing_complete_count()); |
| EXPECT_EQ(ErrorCode::kUnspecifiedReason, pairing_status().protocol_error()); |
| EXPECT_EQ(ErrorCode::kUnspecifiedReason, received_error_code()); |
| EXPECT_EQ(pairing_status(), pairing_complete_status()); |
| } |
| |
| // The slave sends its identity address before sending its IRK. |
| TEST_F(SMP_MasterPairingTest, Phase3IdentityAddressReceivedInWrongOrder) { |
| UInt128 stk; |
| FastForwardToSTKEncrypted(&stk, SecurityLevel::kEncrypted, |
| KeyDistGen::kIdKey); |
| |
| // Pairing should still be in progress. |
| EXPECT_EQ(0, pairing_failed_count()); |
| EXPECT_EQ(0, pairing_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, pairing_callback_count()); |
| EXPECT_EQ(1, pairing_complete_count()); |
| EXPECT_EQ(ErrorCode::kUnspecifiedReason, pairing_status().protocol_error()); |
| EXPECT_EQ(ErrorCode::kUnspecifiedReason, received_error_code()); |
| EXPECT_EQ(pairing_status(), pairing_complete_status()); |
| } |
| |
| TEST_F(SMP_MasterPairingTest, Phase3IdentityAddressReceivedTwice) { |
| UInt128 stk; |
| // Request enc key to prevent pairing from completing after sending the first |
| // identity address. |
| FastForwardToSTKEncrypted(&stk, SecurityLevel::kEncrypted, |
| KeyDistGen::kEncKey | KeyDistGen::kIdKey); |
| |
| // Pairing should still be in progress. |
| EXPECT_EQ(0, pairing_failed_count()); |
| EXPECT_EQ(0, pairing_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, pairing_callback_count()); |
| EXPECT_EQ(1, pairing_complete_count()); |
| EXPECT_EQ(ErrorCode::kUnspecifiedReason, pairing_status().protocol_error()); |
| EXPECT_EQ(ErrorCode::kUnspecifiedReason, received_error_code()); |
| EXPECT_EQ(pairing_status(), pairing_complete_status()); |
| } |
| |
| // Pairing completes after obtaining identity information only. |
| TEST_F(SMP_MasterPairingTest, Phase3CompleteWithIdKey) { |
| UInt128 stk; |
| FastForwardToSTKEncrypted(&stk, SecurityLevel::kEncrypted, |
| KeyDistGen::kIdKey); |
| |
| // Pairing should still be in progress. |
| EXPECT_EQ(0, pairing_failed_count()); |
| EXPECT_EQ(0, pairing_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, pairing_callback_count()); |
| EXPECT_EQ(1, pairing_complete_count()); |
| EXPECT_TRUE(pairing_status()); |
| EXPECT_EQ(pairing_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(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_MasterPairingTest, Phase3CompleteWithAllKeys) { |
| UInt128 stk; |
| FastForwardToSTKEncrypted(&stk, 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; |
| |
| // Receive EncKey |
| ReceiveEncryptionInformation(kLTK); |
| ReceiveMasterIdentification(kRand, kEDiv); |
| RunLoopUntilIdle(); |
| |
| // Pairing still pending. No request to re-encrypt with the LTK should have |
| // been made (the link should be encrypted with the STK). |
| EXPECT_EQ(0, pairing_failed_count()); |
| EXPECT_EQ(0, pairing_callback_count()); |
| EXPECT_EQ(0, pairing_complete_count()); |
| EXPECT_TRUE(fake_link()->ltk()); |
| EXPECT_NE(kLTK, fake_link()->ltk()->value()); |
| EXPECT_EQ(stk, fake_link()->ltk()->value()); |
| EXPECT_EQ(1, fake_link()->start_encryption_count()); |
| |
| // Receive IdKey |
| ReceiveIdentityResolvingKey(kIRK); |
| ReceiveIdentityAddress(kPeerAddr); |
| RunLoopUntilIdle(); |
| |
| // Pairing still pending. Encryption request with LTK should have been made. |
| EXPECT_EQ(0, pairing_failed_count()); |
| EXPECT_EQ(0, pairing_callback_count()); |
| EXPECT_EQ(0, pairing_complete_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_EQ(1, pairing_complete_count()); |
| EXPECT_TRUE(pairing_status()); |
| EXPECT_EQ(pairing_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()); |
| |
| // Should have notified the LTK. |
| EXPECT_EQ(1, pairing_data_callback_count()); |
| ASSERT_TRUE(ltk()); |
| ASSERT_TRUE(irk()); |
| ASSERT_TRUE(identity()); |
| ASSERT_FALSE(csrk()); |
| EXPECT_EQ(sec_props(), ltk()->security()); |
| EXPECT_EQ(kLTK, ltk()->key().value()); |
| EXPECT_EQ(kRand, ltk()->key().rand()); |
| EXPECT_EQ(kEDiv, ltk()->key().ediv()); |
| EXPECT_EQ(sec_props(), irk()->security()); |
| EXPECT_EQ(kIRK, irk()->value()); |
| EXPECT_EQ(kPeerAddr, *identity()); |
| } |
| |
| TEST_F(SMP_MasterPairingTest, SetCurrentSecurityFailsDuringPairing) { |
| UpgradeSecurity(SecurityLevel::kEncrypted); // Initiate pairing. |
| SecurityProperties sec_props(SecurityLevel::kAuthenticated, 16, false); |
| EXPECT_FALSE(pairing()->SetCurrentSecurity(LTK(sec_props, hci::LinkKey()))); |
| EXPECT_EQ(SecurityLevel::kNoSecurity, pairing()->security().level()); |
| } |
| |
| TEST_F(SMP_MasterPairingTest, SetCurrentSecurity) { |
| SecurityProperties sec_props(SecurityLevel::kAuthenticated, 16, false); |
| LTK ltk(sec_props, hci::LinkKey()); |
| |
| EXPECT_TRUE(pairing()->SetCurrentSecurity(ltk)); |
| EXPECT_EQ(1, fake_link()->start_encryption_count()); |
| EXPECT_EQ(SecurityLevel::kAuthenticated, pairing()->security().level()); |
| ASSERT_TRUE(fake_link()->ltk()); |
| EXPECT_EQ(ltk.key(), *fake_link()->ltk()); |
| } |
| |
| 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()); |
| EXPECT_EQ(0, pairing_complete_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(1, pairing_complete_count()); |
| EXPECT_EQ(ErrorCode::kUnspecifiedReason, received_error_code()); |
| EXPECT_EQ(received_error_code(), pairing_complete_status().protocol_error()); |
| } |
| |
| TEST_F(SMP_SlavePairingTest, ReceiveConfirmValueWhileWaitingForTK) { |
| bool tk_requested = false; |
| PairingState::Delegate::TkResponse respond; |
| set_tk_delegate([&](auto, auto 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, pairing_callback_count()); |
| EXPECT_EQ(0, pairing_complete_count()); |
| |
| // Respond with the TK. This should cause us to send Sconfirm. |
| respond(true, 0); |
| RunLoopUntilIdle(); |
| EXPECT_EQ(1, pairing_confirm_count()); |
| EXPECT_EQ(0, pairing_random_count()); |
| EXPECT_EQ(0, pairing_failed_count()); |
| EXPECT_EQ(0, pairing_callback_count()); |
| EXPECT_EQ(0, pairing_complete_count()); |
| } |
| |
| 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()); |
| EXPECT_EQ(0, pairing_complete_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(1, pairing_complete_count()); |
| EXPECT_EQ(ErrorCode::kUnspecifiedReason, received_error_code()); |
| EXPECT_EQ(ErrorCode::kUnspecifiedReason, |
| pairing_complete_status().protocol_error()); |
| } |
| |
| 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()); |
| 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(); |
| |
| // 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()); |
| EXPECT_EQ(0, pairing_complete_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(1, pairing_complete_count()); |
| EXPECT_EQ(ErrorCode::kConfirmValueFailed, received_error_code()); |
| EXPECT_EQ(ErrorCode::kConfirmValueFailed, |
| pairing_complete_status().protocol_error()); |
| } |
| |
| 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()); |
| EXPECT_EQ(0, pairing_complete_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()); |
| EXPECT_EQ(0, pairing_complete_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()); |
| EXPECT_EQ(0, pairing_complete_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 |
| |
| TEST_F(SMP_SlavePairingTest, SetCurrentSecurityFailsDuringPairing) { |
| ReceivePairingRequest(); |
| RunLoopUntilIdle(); |
| SecurityProperties sec_props(SecurityLevel::kAuthenticated, 16, false); |
| EXPECT_FALSE(pairing()->SetCurrentSecurity(LTK(sec_props, hci::LinkKey()))); |
| EXPECT_EQ(SecurityLevel::kNoSecurity, pairing()->security().level()); |
| } |
| |
| TEST_F(SMP_SlavePairingTest, SetCurrentSecurity) { |
| SecurityProperties sec_props(SecurityLevel::kAuthenticated, 16, false); |
| LTK ltk(sec_props, hci::LinkKey()); |
| |
| EXPECT_TRUE(pairing()->SetCurrentSecurity(ltk)); |
| EXPECT_EQ(SecurityLevel::kAuthenticated, pairing()->security().level()); |
| ASSERT_TRUE(fake_link()->ltk()); |
| EXPECT_EQ(ltk.key(), *fake_link()->ltk()); |
| |
| // No encryption request should have been made as the master is expected to do |
| // it. |
| EXPECT_EQ(0, fake_link()->start_encryption_count()); |
| } |
| |
| } // namespace |
| } // namespace sm |
| } // namespace btlib |