diff options
Diffstat (limited to 'gd/security/pairing_handler_le_unittest.cc')
-rw-r--r-- | gd/security/pairing_handler_le_unittest.cc | 122 |
1 files changed, 78 insertions, 44 deletions
diff --git a/gd/security/pairing_handler_le_unittest.cc b/gd/security/pairing_handler_le_unittest.cc index 1f585fe9c..690c080c0 100644 --- a/gd/security/pairing_handler_le_unittest.cc +++ b/gd/security/pairing_handler_le_unittest.cc @@ -21,6 +21,7 @@ #include <memory> #include "os/log.h" +#include "os/rand.h" #include "security/pairing_handler_le.h" #include "security/test/mocks.h" @@ -29,6 +30,7 @@ using ::testing::Eq; using ::testing::Field; using ::testing::VariantWith; +using bluetooth::os::GenerateRandom; using bluetooth::security::CommandView; namespace bluetooth { @@ -45,18 +47,6 @@ CommandView BuilderToView(std::unique_ptr<BasePacketBuilder> builder) { return CommandView::Create(temp_cmd_view); } -std::condition_variable outgoing_l2cap_blocker_; -std::optional<bluetooth::security::CommandView> outgoing_l2cap_packet_; - -bool WaitForOutgoingL2capPacket() { - std::mutex mutex; - std::unique_lock<std::mutex> lock(mutex); - if (outgoing_l2cap_blocker_.wait_for(lock, std::chrono::seconds(5)) == std::cv_status::timeout) { - return false; - } - return true; -} - class PairingResultHandlerMock { public: MOCK_CONST_METHOD1(OnPairingFinished, void(PairingResultOrFailure)); @@ -111,16 +101,42 @@ class PairingHandlerUnitTest : public testing::Test { outgoing_l2cap_blocker_.notify_one(); } + std::optional<bluetooth::security::CommandView> WaitForOutgoingL2capPacket() { + std::mutex mutex; + std::unique_lock<std::mutex> lock(mutex); + + // It is possible that we lost wakeup from condition_variable, check if data is already waiting to be processed + if (outgoing_l2cap_packet_ != std::nullopt) { + std::optional<bluetooth::security::CommandView> tmp = std::nullopt; + outgoing_l2cap_packet_.swap(tmp); + return tmp; + } + + // Data not ready yet, wait for it. + if (outgoing_l2cap_blocker_.wait_for(lock, std::chrono::seconds(5)) == std::cv_status::timeout) { + return std::nullopt; + } + + std::optional<bluetooth::security::CommandView> tmp = std::nullopt; + outgoing_l2cap_packet_.swap(tmp); + return tmp; + } + public: os::Thread* thread_; os::Handler* handler_; std::unique_ptr<common::BidiQueue<packet::PacketView<packet::kLittleEndian>, packet::BasePacketBuilder>> bidi_queue_; std::unique_ptr<os::EnqueueBuffer<packet::BasePacketBuilder>> up_buffer_; + std::condition_variable outgoing_l2cap_blocker_; + std::optional<bluetooth::security::CommandView> outgoing_l2cap_packet_ = std::nullopt; }; InitialInformations initial_informations{ - .my_role = hci::Role::MASTER, + .my_role = hci::Role::CENTRAL, .my_connection_address = {{}, hci::AddressType::PUBLIC_DEVICE_ADDRESS}, + .my_identity_address = {{}, hci::AddressType::PUBLIC_DEVICE_ADDRESS}, + .my_identity_resolving_key = + {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f}, .myPairingCapabilities = {.io_capability = IoCapability::NO_INPUT_NO_OUTPUT, .oob_data_flag = OobDataFlag::NOT_PRESENT, @@ -144,8 +160,9 @@ TEST_F(PairingHandlerUnitTest, test_phase_1_failure) { std::unique_ptr<PairingHandlerLe> pairing_handler = std::make_unique<PairingHandlerLe>(PairingHandlerLe::PHASE1, initial_informations); - EXPECT_TRUE(WaitForOutgoingL2capPacket()); - EXPECT_EQ(outgoing_l2cap_packet_->GetCode(), Code::PAIRING_REQUEST); + std::optional<bluetooth::security::CommandView> pairing_request = WaitForOutgoingL2capPacket(); + EXPECT_TRUE(pairing_request.has_value()); + EXPECT_EQ(pairing_request->GetCode(), Code::PAIRING_REQUEST); EXPECT_CALL(*pairingResult, OnPairingFinished(VariantWith<PairingFailure>(_))).Times(1); @@ -154,8 +171,9 @@ TEST_F(PairingHandlerUnitTest, test_phase_1_failure) { bad_pairing_response.IsValid(); pairing_handler->OnCommandView(bad_pairing_response); - EXPECT_TRUE(WaitForOutgoingL2capPacket()); - EXPECT_EQ(outgoing_l2cap_packet_->GetCode(), Code::PAIRING_FAILED); + std::optional<bluetooth::security::CommandView> pairing_failure = WaitForOutgoingL2capPacket(); + EXPECT_TRUE(pairing_failure.has_value()); + EXPECT_EQ(pairing_failure->GetCode(), Code::PAIRING_FAILED); } TEST_F(PairingHandlerUnitTest, test_secure_connections_just_works) { @@ -168,9 +186,10 @@ TEST_F(PairingHandlerUnitTest, test_secure_connections_just_works) { std::unique_ptr<PairingHandlerLe> pairing_handler = std::make_unique<PairingHandlerLe>(PairingHandlerLe::PHASE1, initial_informations); - EXPECT_TRUE(WaitForOutgoingL2capPacket()); - EXPECT_EQ(outgoing_l2cap_packet_->GetCode(), Code::PAIRING_REQUEST); - CommandView pairing_request = outgoing_l2cap_packet_.value(); + std::optional<bluetooth::security::CommandView> pairing_request_pkt = WaitForOutgoingL2capPacket(); + EXPECT_TRUE(pairing_request_pkt.has_value()); + EXPECT_EQ(pairing_request_pkt->GetCode(), Code::PAIRING_REQUEST); + CommandView pairing_request = pairing_request_pkt.value(); auto pairing_response = BuilderToView( PairingResponseBuilder::Create(IoCapability::KEYBOARD_DISPLAY, OobDataFlag::NOT_PRESENT, @@ -179,10 +198,11 @@ TEST_F(PairingHandlerUnitTest, test_secure_connections_just_works) { // Phase 1 finished. // pairing public key - EXPECT_TRUE(WaitForOutgoingL2capPacket()); - EXPECT_EQ(Code::PAIRING_PUBLIC_KEY, outgoing_l2cap_packet_->GetCode()); + std::optional<bluetooth::security::CommandView> public_key_pkt = WaitForOutgoingL2capPacket(); + EXPECT_TRUE(public_key_pkt.has_value()); + EXPECT_EQ(Code::PAIRING_PUBLIC_KEY, public_key_pkt->GetCode()); EcdhPublicKey my_public_key; - auto ppkv = PairingPublicKeyView::Create(outgoing_l2cap_packet_.value()); + auto ppkv = PairingPublicKeyView::Create(public_key_pkt.value()); ppkv.IsValid(); my_public_key.x = ppkv.GetPublicKeyX(); my_public_key.y = ppkv.GetPublicKeyY(); @@ -197,7 +217,7 @@ TEST_F(PairingHandlerUnitTest, test_secure_connections_just_works) { Octet16 ra, rb; ra = rb = {0}; - Octet16 Nb = PairingHandlerLe::GenerateRandom<16>(); + Octet16 Nb = GenerateRandom<16>(); // Compute confirm Octet16 Cb = crypto_toolbox::f4((uint8_t*)public_key.x.data(), (uint8_t*)my_public_key.x.data(), Nb, 0); @@ -205,9 +225,10 @@ TEST_F(PairingHandlerUnitTest, test_secure_connections_just_works) { pairing_handler->OnCommandView(BuilderToView(PairingConfirmBuilder::Create(Cb))); // random - EXPECT_TRUE(WaitForOutgoingL2capPacket()); - EXPECT_EQ(Code::PAIRING_RANDOM, outgoing_l2cap_packet_->GetCode()); - auto prv = PairingRandomView::Create(outgoing_l2cap_packet_.value()); + std::optional<bluetooth::security::CommandView> random_pkt = WaitForOutgoingL2capPacket(); + EXPECT_TRUE(random_pkt.has_value()); + EXPECT_EQ(Code::PAIRING_RANDOM, random_pkt->GetCode()); + auto prv = PairingRandomView::Create(random_pkt.value()); prv.IsValid(); Octet16 Na = prv.GetRandomValue(); @@ -216,9 +237,9 @@ TEST_F(PairingHandlerUnitTest, test_secure_connections_just_works) { // Start of authentication stage 2 uint8_t a[7]; uint8_t b[7]; - memcpy(b, initial_informations.remote_connection_address.GetAddress().address, 6); + memcpy(b, initial_informations.remote_connection_address.GetAddress().data(), hci::Address::kLength); b[6] = (uint8_t)initial_informations.remote_connection_address.GetAddressType(); - memcpy(a, initial_informations.my_connection_address.GetAddress().address, 6); + memcpy(a, initial_informations.my_connection_address.GetAddress().data(), hci::Address::kLength); a[6] = (uint8_t)initial_informations.my_connection_address.GetAddressType(); Octet16 ltk, mac_key; @@ -237,9 +258,10 @@ TEST_F(PairingHandlerUnitTest, test_secure_connections_just_works) { Octet16 Ea = crypto_toolbox::f6(mac_key, Na, Nb, rb, iocapA.data(), a, b); Octet16 Eb = crypto_toolbox::f6(mac_key, Nb, Na, ra, iocapB.data(), b, a); - EXPECT_TRUE(WaitForOutgoingL2capPacket()); - EXPECT_EQ(Code::PAIRING_DH_KEY_CHECK, outgoing_l2cap_packet_->GetCode()); - auto pdhkcv = PairingDhKeyCheckView::Create(outgoing_l2cap_packet_.value()); + std::optional<bluetooth::security::CommandView> dh_key_pkt = WaitForOutgoingL2capPacket(); + EXPECT_TRUE(dh_key_pkt.has_value()); + EXPECT_EQ(Code::PAIRING_DH_KEY_CHECK, dh_key_pkt->GetCode()); + auto pdhkcv = PairingDhKeyCheckView::Create(dh_key_pkt.value()); pdhkcv.IsValid(); EXPECT_EQ(pdhkcv.GetDhKeyCheck(), Ea); @@ -250,8 +272,11 @@ TEST_F(PairingHandlerUnitTest, test_secure_connections_just_works) { } InitialInformations initial_informations_trsi{ - .my_role = hci::Role::MASTER, + .my_role = hci::Role::CENTRAL, .my_connection_address = hci::AddressWithType(), + .my_identity_address = {{}, hci::AddressType::PUBLIC_DEVICE_ADDRESS}, + .my_identity_resolving_key = + {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f}, .myPairingCapabilities = {.io_capability = IoCapability::NO_INPUT_NO_OUTPUT, .oob_data_flag = OobDataFlag::NOT_PRESENT, @@ -267,9 +292,9 @@ InitialInformations initial_informations_trsi{ .OnPairingFinished = OnPairingFinished, }; -/* This test verifies that when remote slave device sends security request , and user +/* This test verifies that when remote peripheral device sends security request , and user * does accept the prompt, we do send pairing request */ -TEST_F(PairingHandlerUnitTest, test_remote_slave_initiating) { +TEST_F(PairingHandlerUnitTest, test_remote_peripheral_initiating) { initial_informations_trsi.proper_l2cap_interface = up_buffer_.get(); initial_informations_trsi.l2cap_handler = handler_; initial_informations_trsi.user_interface_handler = handler_; @@ -280,16 +305,20 @@ TEST_F(PairingHandlerUnitTest, test_remote_slave_initiating) { // Simulate user accepting the pairing in UI pairing_handler->OnUiAction(PairingEvent::PAIRING_ACCEPTED, 0x01 /* Non-zero value means success */); - EXPECT_TRUE(WaitForOutgoingL2capPacket()); - EXPECT_EQ(Code::PAIRING_REQUEST, outgoing_l2cap_packet_->GetCode()); + std::optional<bluetooth::security::CommandView> pairing_request_pkt = WaitForOutgoingL2capPacket(); + EXPECT_TRUE(pairing_request_pkt.has_value()); + EXPECT_EQ(Code::PAIRING_REQUEST, pairing_request_pkt->GetCode()); // We don't care for the rest of the flow, let it die. pairing_handler.reset(); } InitialInformations initial_informations_trmi{ - .my_role = hci::Role::SLAVE, + .my_role = hci::Role::PERIPHERAL, .my_connection_address = hci::AddressWithType(), + .my_identity_address = {{}, hci::AddressType::PUBLIC_DEVICE_ADDRESS}, + .my_identity_resolving_key = + {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f}, .myPairingCapabilities = {.io_capability = IoCapability::NO_INPUT_NO_OUTPUT, .oob_data_flag = OobDataFlag::NOT_PRESENT, @@ -300,9 +329,13 @@ InitialInformations initial_informations_trmi{ .remotely_initiated = true, .remote_connection_address = hci::AddressWithType(), - .pairing_request = PairingRequestView::Create(BuilderToView( - PairingRequestBuilder::Create(IoCapability::NO_INPUT_NO_OUTPUT, OobDataFlag::NOT_PRESENT, - AuthReqMaskBondingFlag | AuthReqMaskMitm | AuthReqMaskSc, 16, 0x03, 0x03))), + .pairing_request = PairingRequestView::Create(BuilderToView(PairingRequestBuilder::Create( + IoCapability::NO_INPUT_NO_OUTPUT, + OobDataFlag::NOT_PRESENT, + AuthReqMaskBondingFlag | AuthReqMaskMitm | AuthReqMaskSc, + 16, + 0x03, + 0x03))), .user_interface = &uiMock, .le_security_interface = &leSecurityMock, @@ -311,7 +344,7 @@ InitialInformations initial_informations_trmi{ /* This test verifies that when remote device sends pairing request, and user does accept the prompt, we do send proper * reply back */ -TEST_F(PairingHandlerUnitTest, test_remote_master_initiating) { +TEST_F(PairingHandlerUnitTest, test_remote_central_initiating) { initial_informations_trmi.proper_l2cap_interface = up_buffer_.get(); initial_informations_trmi.l2cap_handler = handler_; initial_informations_trmi.user_interface_handler = handler_; @@ -322,8 +355,9 @@ TEST_F(PairingHandlerUnitTest, test_remote_master_initiating) { // Simulate user accepting the pairing in UI pairing_handler->OnUiAction(PairingEvent::PAIRING_ACCEPTED, 0x01 /* Non-zero value means success */); - EXPECT_TRUE(WaitForOutgoingL2capPacket()); - EXPECT_EQ(Code::PAIRING_RESPONSE, outgoing_l2cap_packet_->GetCode()); + std::optional<bluetooth::security::CommandView> pairing_response_pkt = WaitForOutgoingL2capPacket(); + EXPECT_TRUE(pairing_response_pkt.has_value()); + EXPECT_EQ(Code::PAIRING_RESPONSE, pairing_response_pkt->GetCode()); // Phase 1 finished. // We don't care for the rest of the flow, it's handled in in other tests. let it die. |