| /* |
| * |
| * Copyright 2019 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at: |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| * |
| */ |
| #include "security/pairing/classic_pairing_handler.h" |
| |
| #include <gtest/gtest.h> |
| #include <memory> |
| |
| #include "hci/hci_packets.h" |
| #include "l2cap/classic/fixed_channel_manager_mock.h" |
| #include "packet/raw_builder.h" |
| #include "security/channel/security_manager_channel.h" |
| #include "security/smp_packets.h" |
| #include "security/test/fake_hci_layer.h" |
| |
| namespace bluetooth { |
| namespace security { |
| namespace channel { |
| namespace { |
| |
| using bluetooth::security::channel::SecurityManagerChannel; |
| using hci::Address; |
| using hci::AuthenticationRequirements; |
| using hci::CommandCompleteBuilder; |
| using hci::IoCapabilityRequestReplyBuilder; |
| using hci::IoCapabilityRequestView; |
| using hci::OobDataPresent; |
| using hci::OpCode; |
| using os::Handler; |
| using os::Thread; |
| using packet::RawBuilder; |
| |
| class SecurityManagerChannelCallback : public ISecurityManagerChannelListener { |
| public: |
| explicit SecurityManagerChannelCallback(pairing::ClassicPairingHandler* pairing_handler) |
| : pairing_handler_(pairing_handler) {} |
| void OnHciEventReceived(hci::EventPacketView packet) override { |
| auto event = hci::EventPacketView::Create(packet); |
| ASSERT_LOG(event.IsValid(), "Received invalid packet"); |
| const hci::EventCode code = event.GetEventCode(); |
| switch (code) { |
| case hci::EventCode::PIN_CODE_REQUEST: |
| pairing_handler_->OnReceive(hci::PinCodeRequestView::Create(event)); |
| break; |
| case hci::EventCode::LINK_KEY_REQUEST: |
| pairing_handler_->OnReceive(hci::LinkKeyRequestView::Create(event)); |
| break; |
| case hci::EventCode::LINK_KEY_NOTIFICATION: |
| pairing_handler_->OnReceive(hci::LinkKeyNotificationView::Create(event)); |
| break; |
| case hci::EventCode::IO_CAPABILITY_REQUEST: |
| pairing_handler_->OnReceive(hci::IoCapabilityRequestView::Create(event)); |
| break; |
| case hci::EventCode::IO_CAPABILITY_RESPONSE: |
| pairing_handler_->OnReceive(hci::IoCapabilityResponseView::Create(event)); |
| break; |
| case hci::EventCode::SIMPLE_PAIRING_COMPLETE: |
| pairing_handler_->OnReceive(hci::SimplePairingCompleteView::Create(event)); |
| break; |
| case hci::EventCode::RETURN_LINK_KEYS: |
| pairing_handler_->OnReceive(hci::ReturnLinkKeysView::Create(event)); |
| break; |
| case hci::EventCode::REMOTE_OOB_DATA_REQUEST: |
| pairing_handler_->OnReceive(hci::RemoteOobDataRequestView::Create(event)); |
| break; |
| case hci::EventCode::USER_PASSKEY_NOTIFICATION: |
| pairing_handler_->OnReceive(hci::UserPasskeyNotificationView::Create(event)); |
| break; |
| case hci::EventCode::KEYPRESS_NOTIFICATION: |
| pairing_handler_->OnReceive(hci::KeypressNotificationView::Create(event)); |
| break; |
| case hci::EventCode::USER_CONFIRMATION_REQUEST: |
| pairing_handler_->OnReceive(hci::UserConfirmationRequestView::Create(event)); |
| break; |
| case hci::EventCode::USER_PASSKEY_REQUEST: |
| pairing_handler_->OnReceive(hci::UserPasskeyRequestView::Create(event)); |
| break; |
| default: |
| ASSERT_LOG(false, "Cannot handle received packet: %s", hci::EventCodeText(code).c_str()); |
| break; |
| } |
| } |
| |
| private: |
| pairing::ClassicPairingHandler* pairing_handler_ = nullptr; |
| }; |
| |
| static void pairing_complete_callback(bluetooth::hci::Address address) {} |
| |
| class ClassicPairingHandlerTest : public ::testing::Test { |
| protected: |
| void SetUp() override { |
| handler_ = new Handler(&thread_); |
| hci_layer_ = new FakeHciLayer(); |
| channel_ = new channel::SecurityManagerChannel(handler_, hci_layer_); |
| fake_registry_.InjectTestModule(&FakeHciLayer::Factory, hci_layer_); |
| fake_registry_.Start<FakeHciLayer>(&thread_); |
| security_record_ = std::make_shared<record::SecurityRecord>(device_); |
| std::shared_ptr<l2cap::classic::testing::MockFixedChannelManager> sptr = |
| std::shared_ptr<l2cap::classic::testing::MockFixedChannelManager>( |
| new l2cap::classic::testing::MockFixedChannelManager); |
| EXPECT_CALL(*sptr, RegisterService(::testing::_, ::testing::_, ::testing::_, ::testing::_, ::testing::_)) |
| .Times(::testing::AnyNumber()); |
| pairing_handler_ = new pairing::ClassicPairingHandler(sptr, channel_, security_record_, handler_, |
| common::Bind(&pairing_complete_callback)); |
| channel_callback_ = new SecurityManagerChannelCallback(pairing_handler_); |
| channel_->SetChannelListener(channel_callback_); |
| } |
| |
| void TearDown() override { |
| channel_->SetChannelListener(nullptr); |
| handler_->Clear(); |
| fake_registry_.SynchronizeModuleHandler(&FakeHciLayer::Factory, std::chrono::milliseconds(20)); |
| fake_registry_.StopAll(); |
| delete pairing_handler_; |
| delete handler_; |
| delete channel_; |
| delete channel_callback_; |
| } |
| |
| TestModuleRegistry fake_registry_; |
| Thread& thread_ = fake_registry_.GetTestThread(); |
| Handler* handler_ = nullptr; |
| FakeHciLayer* hci_layer_ = nullptr; |
| hci::AddressWithType device_; |
| SecurityManagerChannelCallback* channel_callback_ = nullptr; |
| channel::SecurityManagerChannel* channel_ = nullptr; |
| pairing::ClassicPairingHandler* pairing_handler_ = nullptr; |
| std::shared_ptr<record::SecurityRecord> security_record_ = nullptr; |
| }; |
| |
| // Security Manager Boot Sequence (Required for SSP, these are already set at boot time) |
| // - WriteSimplePairingMode |
| // - WriteSecureConnectionsHostSupport |
| // - WriteAuthenticatedPayloadTimeout |
| |
| /*** Locally initiated ***/ |
| // Security Pairing Sequence (JustWorks) |
| // -> *Establish L2CAP connection* |
| // -> AuthenticationRequested (should L2CAP request secure service which causes this?) |
| // <- LinkKeyRequest |
| // -> LinkKeyRequestNegativeReply |
| // <- IoCapabilityRequest |
| // -> IoCapabilityRequestReply |
| // <- IoCapabilityResponse |
| // <- UserConfirmationRequest |
| // -> UserConfirmationRequestReply (auto) |
| // <- SimplePairingComplete |
| // <- LinkKeyNotification |
| // <- AuthenticationComplete |
| // -> SetConnectionEncryption |
| // <- EncryptionChange |
| // -> L2capConnectionResponse (if triggered by L2cap connection request) |
| |
| void ReceiveLinkKeyRequest(FakeHciLayer* hci_layer, hci::AddressWithType device) { |
| hci_layer->IncomingEvent(hci::LinkKeyRequestBuilder::Create(device.GetAddress())); |
| } |
| |
| void ReceiveIoCapabilityRequest(FakeHciLayer* hci_layer, hci::AddressWithType device) { |
| hci_layer->IncomingEvent(hci::IoCapabilityRequestBuilder::Create(device.GetAddress())); |
| } |
| |
| void ReceiveIoCapabilityResponse(FakeHciLayer* hci_layer, hci::AddressWithType device, hci::IoCapability io_cap, |
| hci::OobDataPresent oob_present, hci::AuthenticationRequirements auth_reqs) { |
| hci_layer->IncomingEvent( |
| hci::IoCapabilityResponseBuilder::Create(device.GetAddress(), io_cap, oob_present, auth_reqs)); |
| } |
| |
| void ReceiveUserConfirmationRequest(FakeHciLayer* hci_layer, hci::AddressWithType device, uint32_t numeric_value) { |
| hci_layer->IncomingEvent(hci::UserConfirmationRequestBuilder::Create(device.GetAddress(), numeric_value)); |
| } |
| |
| void ReceiveSimplePairingComplete(FakeHciLayer* hci_layer, hci::ErrorCode status, hci::AddressWithType device) { |
| hci_layer->IncomingEvent(hci::SimplePairingCompleteBuilder::Create(status, device.GetAddress())); |
| } |
| |
| void ReceiveLinkKeyNotification(FakeHciLayer* hci_layer, hci::AddressWithType device, std::array<uint8_t, 16> link_key, |
| hci::KeyType key_type) { |
| hci_layer->IncomingEvent(hci::LinkKeyNotificationBuilder::Create(device.GetAddress(), link_key, key_type)); |
| } |
| |
| hci::SecurityCommandView GetLastCommand(FakeHciLayer* hci_layer) { |
| auto last_command = std::move(hci_layer->GetLastCommand()->command); |
| auto command_packet = GetPacketView(std::move(last_command)); |
| auto command_packet_view = hci::CommandPacketView::Create(command_packet); |
| ASSERT(command_packet_view.IsValid()); |
| auto security_command_view = hci::SecurityCommandView::Create(command_packet_view); |
| ASSERT(security_command_view.IsValid()); |
| return security_command_view; |
| } |
| |
| TEST_F(ClassicPairingHandlerTest, setup_teardown) {} |
| |
| // display_only + display_only is JustWorks no confirmation |
| // Needs dialog as per security a bug unless pairing is temporary |
| TEST_F(ClassicPairingHandlerTest, locally_initiatied_display_only_display_only_temp) { |
| hci::IoCapability injected_io_capability = hci::IoCapability::DISPLAY_ONLY; |
| hci::AuthenticationRequirements injected_authentication_requirements = hci::AuthenticationRequirements::NO_BONDING; |
| pairing_handler_->Initiate(true, injected_io_capability, hci::OobDataPresent::NOT_PRESENT, |
| injected_authentication_requirements); |
| ReceiveLinkKeyRequest(hci_layer_, device_); |
| auto security_command_view = GetLastCommand(hci_layer_); |
| auto link_key_neg_reply = hci::LinkKeyRequestNegativeReplyView::Create(security_command_view); |
| ASSERT_TRUE(link_key_neg_reply.IsValid()); |
| ASSERT_EQ(OpCode::LINK_KEY_REQUEST_NEGATIVE_REPLY, link_key_neg_reply.GetOpCode()); |
| ReceiveIoCapabilityRequest(hci_layer_, device_); |
| security_command_view = GetLastCommand(hci_layer_); |
| ASSERT_EQ(OpCode::IO_CAPABILITY_REQUEST_REPLY, security_command_view.GetOpCode()); |
| auto io_cap_request_reply = hci::IoCapabilityRequestReplyView::Create(security_command_view); |
| ASSERT_TRUE(io_cap_request_reply.IsValid()); |
| ASSERT_EQ(injected_io_capability, io_cap_request_reply.GetIoCapability()); |
| ASSERT_EQ(hci::OobDataPresent::NOT_PRESENT, io_cap_request_reply.GetOobPresent()); |
| ASSERT_EQ(injected_authentication_requirements, io_cap_request_reply.GetAuthenticationRequirements()); |
| ReceiveIoCapabilityResponse(hci_layer_, device_, hci::IoCapability::DISPLAY_ONLY, hci::OobDataPresent::NOT_PRESENT, |
| hci::AuthenticationRequirements::NO_BONDING); |
| uint32_t numeric_value = 0x123; |
| ReceiveUserConfirmationRequest(hci_layer_, device_, numeric_value); |
| security_command_view = GetLastCommand(hci_layer_); |
| ASSERT_EQ(OpCode::USER_CONFIRMATION_REQUEST_REPLY, security_command_view.GetOpCode()); |
| auto user_conf_request_reply = hci::UserConfirmationRequestReplyView::Create(security_command_view); |
| ASSERT_TRUE(user_conf_request_reply.IsValid()); |
| ReceiveSimplePairingComplete(hci_layer_, hci::ErrorCode::SUCCESS, device_); |
| std::array<uint8_t, 16> link_key = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5}; |
| hci::KeyType key_type = hci::KeyType::DEBUG_COMBINATION; |
| ReceiveLinkKeyNotification(hci_layer_, device_, link_key, key_type); |
| ASSERT_EQ(link_key, security_record_->GetLinkKey()); |
| ASSERT_EQ(key_type, security_record_->GetKeyType()); |
| } |
| |
| // display_only + display_yes_no is JustWorks no confirmation |
| // Needs dialog as per security a bug unless pairing is temporary |
| TEST_F(ClassicPairingHandlerTest, locally_initiatied_display_only_display_yes_no_temp) { |
| hci::IoCapability injected_io_capability = hci::IoCapability::DISPLAY_ONLY; |
| hci::AuthenticationRequirements injected_authentication_requirements = hci::AuthenticationRequirements::NO_BONDING; |
| pairing_handler_->Initiate(true, injected_io_capability, hci::OobDataPresent::NOT_PRESENT, |
| injected_authentication_requirements); |
| ReceiveLinkKeyRequest(hci_layer_, device_); |
| auto security_command_view = GetLastCommand(hci_layer_); |
| auto link_key_neg_reply = hci::LinkKeyRequestNegativeReplyView::Create(security_command_view); |
| ASSERT_TRUE(link_key_neg_reply.IsValid()); |
| ASSERT_EQ(OpCode::LINK_KEY_REQUEST_NEGATIVE_REPLY, link_key_neg_reply.GetOpCode()); |
| ReceiveIoCapabilityRequest(hci_layer_, device_); |
| security_command_view = GetLastCommand(hci_layer_); |
| ASSERT_EQ(OpCode::IO_CAPABILITY_REQUEST_REPLY, security_command_view.GetOpCode()); |
| auto io_cap_request_reply = hci::IoCapabilityRequestReplyView::Create(security_command_view); |
| ASSERT_TRUE(io_cap_request_reply.IsValid()); |
| ASSERT_EQ(injected_io_capability, io_cap_request_reply.GetIoCapability()); |
| ASSERT_EQ(hci::OobDataPresent::NOT_PRESENT, io_cap_request_reply.GetOobPresent()); |
| ASSERT_EQ(injected_authentication_requirements, io_cap_request_reply.GetAuthenticationRequirements()); |
| ReceiveIoCapabilityResponse(hci_layer_, device_, hci::IoCapability::DISPLAY_YES_NO, hci::OobDataPresent::NOT_PRESENT, |
| hci::AuthenticationRequirements::NO_BONDING); |
| uint32_t numeric_value = 0x123; |
| ReceiveUserConfirmationRequest(hci_layer_, device_, numeric_value); |
| security_command_view = GetLastCommand(hci_layer_); |
| ASSERT_EQ(OpCode::USER_CONFIRMATION_REQUEST_REPLY, security_command_view.GetOpCode()); |
| auto user_conf_request_reply = hci::UserConfirmationRequestReplyView::Create(security_command_view); |
| ASSERT_TRUE(user_conf_request_reply.IsValid()); |
| ReceiveSimplePairingComplete(hci_layer_, hci::ErrorCode::SUCCESS, device_); |
| std::array<uint8_t, 16> link_key = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5}; |
| hci::KeyType key_type = hci::KeyType::DEBUG_COMBINATION; |
| ReceiveLinkKeyNotification(hci_layer_, device_, link_key, key_type); |
| ASSERT_EQ(link_key, security_record_->GetLinkKey()); |
| ASSERT_EQ(key_type, security_record_->GetKeyType()); |
| } |
| |
| // display_only + no_input_no_output is JustWorks no confirmation |
| // Needs dialog as per security a bug unless pairing is temporary |
| TEST_F(ClassicPairingHandlerTest, locally_initiatied_display_only_no_input_no_output_temp) { |
| hci::IoCapability injected_io_capability = hci::IoCapability::DISPLAY_ONLY; |
| hci::AuthenticationRequirements injected_authentication_requirements = hci::AuthenticationRequirements::NO_BONDING; |
| pairing_handler_->Initiate(true, injected_io_capability, hci::OobDataPresent::NOT_PRESENT, |
| injected_authentication_requirements); |
| ReceiveLinkKeyRequest(hci_layer_, device_); |
| auto security_command_view = GetLastCommand(hci_layer_); |
| auto link_key_neg_reply = hci::LinkKeyRequestNegativeReplyView::Create(security_command_view); |
| ASSERT_TRUE(link_key_neg_reply.IsValid()); |
| ASSERT_EQ(OpCode::LINK_KEY_REQUEST_NEGATIVE_REPLY, link_key_neg_reply.GetOpCode()); |
| ReceiveIoCapabilityRequest(hci_layer_, device_); |
| security_command_view = GetLastCommand(hci_layer_); |
| ASSERT_EQ(OpCode::IO_CAPABILITY_REQUEST_REPLY, security_command_view.GetOpCode()); |
| auto io_cap_request_reply = hci::IoCapabilityRequestReplyView::Create(security_command_view); |
| ASSERT_TRUE(io_cap_request_reply.IsValid()); |
| ASSERT_EQ(injected_io_capability, io_cap_request_reply.GetIoCapability()); |
| ASSERT_EQ(hci::OobDataPresent::NOT_PRESENT, io_cap_request_reply.GetOobPresent()); |
| ASSERT_EQ(injected_authentication_requirements, io_cap_request_reply.GetAuthenticationRequirements()); |
| ReceiveIoCapabilityResponse(hci_layer_, device_, hci::IoCapability::NO_INPUT_NO_OUTPUT, |
| hci::OobDataPresent::NOT_PRESENT, hci::AuthenticationRequirements::NO_BONDING); |
| uint32_t numeric_value = 0x123; |
| ReceiveUserConfirmationRequest(hci_layer_, device_, numeric_value); |
| security_command_view = GetLastCommand(hci_layer_); |
| ASSERT_EQ(OpCode::USER_CONFIRMATION_REQUEST_REPLY, security_command_view.GetOpCode()); |
| auto user_conf_request_reply = hci::UserConfirmationRequestReplyView::Create(security_command_view); |
| ASSERT_TRUE(user_conf_request_reply.IsValid()); |
| ReceiveSimplePairingComplete(hci_layer_, hci::ErrorCode::SUCCESS, device_); |
| std::array<uint8_t, 16> link_key = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5}; |
| hci::KeyType key_type = hci::KeyType::DEBUG_COMBINATION; |
| ReceiveLinkKeyNotification(hci_layer_, device_, link_key, key_type); |
| ASSERT_EQ(link_key, security_record_->GetLinkKey()); |
| ASSERT_EQ(key_type, security_record_->GetKeyType()); |
| } |
| |
| // keyboard_only + no_input_no_output is JustWorks no confirmation |
| // Needs dialog as per security a bug unless pairing is temporary |
| TEST_F(ClassicPairingHandlerTest, locally_initiatied_keyboard_only_no_input_no_output_temp) { |
| hci::IoCapability injected_io_capability = hci::IoCapability::KEYBOARD_ONLY; |
| hci::AuthenticationRequirements injected_authentication_requirements = hci::AuthenticationRequirements::NO_BONDING; |
| pairing_handler_->Initiate(true, injected_io_capability, hci::OobDataPresent::NOT_PRESENT, |
| injected_authentication_requirements); |
| ReceiveLinkKeyRequest(hci_layer_, device_); |
| auto security_command_view = GetLastCommand(hci_layer_); |
| auto link_key_neg_reply = hci::LinkKeyRequestNegativeReplyView::Create(security_command_view); |
| ASSERT_TRUE(link_key_neg_reply.IsValid()); |
| ASSERT_EQ(OpCode::LINK_KEY_REQUEST_NEGATIVE_REPLY, link_key_neg_reply.GetOpCode()); |
| ReceiveIoCapabilityRequest(hci_layer_, device_); |
| security_command_view = GetLastCommand(hci_layer_); |
| ASSERT_EQ(OpCode::IO_CAPABILITY_REQUEST_REPLY, security_command_view.GetOpCode()); |
| auto io_cap_request_reply = hci::IoCapabilityRequestReplyView::Create(security_command_view); |
| ASSERT_TRUE(io_cap_request_reply.IsValid()); |
| ASSERT_EQ(injected_io_capability, io_cap_request_reply.GetIoCapability()); |
| ASSERT_EQ(hci::OobDataPresent::NOT_PRESENT, io_cap_request_reply.GetOobPresent()); |
| ASSERT_EQ(injected_authentication_requirements, io_cap_request_reply.GetAuthenticationRequirements()); |
| ReceiveIoCapabilityResponse(hci_layer_, device_, hci::IoCapability::NO_INPUT_NO_OUTPUT, |
| hci::OobDataPresent::NOT_PRESENT, hci::AuthenticationRequirements::NO_BONDING); |
| uint32_t numeric_value = 0x123; |
| ReceiveUserConfirmationRequest(hci_layer_, device_, numeric_value); |
| security_command_view = GetLastCommand(hci_layer_); |
| ASSERT_EQ(OpCode::USER_CONFIRMATION_REQUEST_REPLY, security_command_view.GetOpCode()); |
| auto user_conf_request_reply = hci::UserConfirmationRequestReplyView::Create(security_command_view); |
| ASSERT_TRUE(user_conf_request_reply.IsValid()); |
| ReceiveSimplePairingComplete(hci_layer_, hci::ErrorCode::SUCCESS, device_); |
| std::array<uint8_t, 16> link_key = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5}; |
| hci::KeyType key_type = hci::KeyType::DEBUG_COMBINATION; |
| ReceiveLinkKeyNotification(hci_layer_, device_, link_key, key_type); |
| ASSERT_EQ(link_key, security_record_->GetLinkKey()); |
| ASSERT_EQ(key_type, security_record_->GetKeyType()); |
| } |
| |
| // no_input_no_output + display_only is JustWorks no confirmation |
| // Needs dialog as per security a bug unless pairing is temporary |
| TEST_F(ClassicPairingHandlerTest, locally_initiatied_no_input_no_output_display_only_temp) { |
| hci::IoCapability injected_io_capability = hci::IoCapability::NO_INPUT_NO_OUTPUT; |
| hci::AuthenticationRequirements injected_authentication_requirements = hci::AuthenticationRequirements::NO_BONDING; |
| pairing_handler_->Initiate(true, injected_io_capability, hci::OobDataPresent::NOT_PRESENT, |
| injected_authentication_requirements); |
| ReceiveLinkKeyRequest(hci_layer_, device_); |
| auto security_command_view = GetLastCommand(hci_layer_); |
| auto link_key_neg_reply = hci::LinkKeyRequestNegativeReplyView::Create(security_command_view); |
| ASSERT_TRUE(link_key_neg_reply.IsValid()); |
| ASSERT_EQ(OpCode::LINK_KEY_REQUEST_NEGATIVE_REPLY, link_key_neg_reply.GetOpCode()); |
| ReceiveIoCapabilityRequest(hci_layer_, device_); |
| security_command_view = GetLastCommand(hci_layer_); |
| ASSERT_EQ(OpCode::IO_CAPABILITY_REQUEST_REPLY, security_command_view.GetOpCode()); |
| auto io_cap_request_reply = hci::IoCapabilityRequestReplyView::Create(security_command_view); |
| ASSERT_TRUE(io_cap_request_reply.IsValid()); |
| ASSERT_EQ(injected_io_capability, io_cap_request_reply.GetIoCapability()); |
| ASSERT_EQ(hci::OobDataPresent::NOT_PRESENT, io_cap_request_reply.GetOobPresent()); |
| ASSERT_EQ(injected_authentication_requirements, io_cap_request_reply.GetAuthenticationRequirements()); |
| ReceiveIoCapabilityResponse(hci_layer_, device_, hci::IoCapability::DISPLAY_ONLY, hci::OobDataPresent::NOT_PRESENT, |
| hci::AuthenticationRequirements::NO_BONDING); |
| uint32_t numeric_value = 0x123; |
| ReceiveUserConfirmationRequest(hci_layer_, device_, numeric_value); |
| security_command_view = GetLastCommand(hci_layer_); |
| ASSERT_EQ(OpCode::USER_CONFIRMATION_REQUEST_REPLY, security_command_view.GetOpCode()); |
| auto user_conf_request_reply = hci::UserConfirmationRequestReplyView::Create(security_command_view); |
| ASSERT_TRUE(user_conf_request_reply.IsValid()); |
| ReceiveSimplePairingComplete(hci_layer_, hci::ErrorCode::SUCCESS, device_); |
| std::array<uint8_t, 16> link_key = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5}; |
| hci::KeyType key_type = hci::KeyType::DEBUG_COMBINATION; |
| ReceiveLinkKeyNotification(hci_layer_, device_, link_key, key_type); |
| ASSERT_EQ(link_key, security_record_->GetLinkKey()); |
| ASSERT_EQ(key_type, security_record_->GetKeyType()); |
| } |
| |
| // no_input_no_output + display_yes_no is JustWorks no confirmation |
| // Needs dialog as per security a bug unless pairing is temporary |
| TEST_F(ClassicPairingHandlerTest, locally_initiatied_no_input_no_output_display_yes_no_temp) { |
| hci::IoCapability injected_io_capability = hci::IoCapability::NO_INPUT_NO_OUTPUT; |
| hci::AuthenticationRequirements injected_authentication_requirements = hci::AuthenticationRequirements::NO_BONDING; |
| pairing_handler_->Initiate(true, injected_io_capability, hci::OobDataPresent::NOT_PRESENT, |
| injected_authentication_requirements); |
| ReceiveLinkKeyRequest(hci_layer_, device_); |
| auto security_command_view = GetLastCommand(hci_layer_); |
| auto link_key_neg_reply = hci::LinkKeyRequestNegativeReplyView::Create(security_command_view); |
| ASSERT_TRUE(link_key_neg_reply.IsValid()); |
| ASSERT_EQ(OpCode::LINK_KEY_REQUEST_NEGATIVE_REPLY, link_key_neg_reply.GetOpCode()); |
| ReceiveIoCapabilityRequest(hci_layer_, device_); |
| security_command_view = GetLastCommand(hci_layer_); |
| ASSERT_EQ(OpCode::IO_CAPABILITY_REQUEST_REPLY, security_command_view.GetOpCode()); |
| auto io_cap_request_reply = hci::IoCapabilityRequestReplyView::Create(security_command_view); |
| ASSERT_TRUE(io_cap_request_reply.IsValid()); |
| ASSERT_EQ(injected_io_capability, io_cap_request_reply.GetIoCapability()); |
| ASSERT_EQ(hci::OobDataPresent::NOT_PRESENT, io_cap_request_reply.GetOobPresent()); |
| ASSERT_EQ(injected_authentication_requirements, io_cap_request_reply.GetAuthenticationRequirements()); |
| ReceiveIoCapabilityResponse(hci_layer_, device_, hci::IoCapability::DISPLAY_YES_NO, hci::OobDataPresent::NOT_PRESENT, |
| hci::AuthenticationRequirements::NO_BONDING); |
| uint32_t numeric_value = 0x123; |
| ReceiveUserConfirmationRequest(hci_layer_, device_, numeric_value); |
| security_command_view = GetLastCommand(hci_layer_); |
| ASSERT_EQ(OpCode::USER_CONFIRMATION_REQUEST_REPLY, security_command_view.GetOpCode()); |
| auto user_conf_request_reply = hci::UserConfirmationRequestReplyView::Create(security_command_view); |
| ASSERT_TRUE(user_conf_request_reply.IsValid()); |
| ReceiveSimplePairingComplete(hci_layer_, hci::ErrorCode::SUCCESS, device_); |
| std::array<uint8_t, 16> link_key = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5}; |
| hci::KeyType key_type = hci::KeyType::DEBUG_COMBINATION; |
| ReceiveLinkKeyNotification(hci_layer_, device_, link_key, key_type); |
| ASSERT_EQ(link_key, security_record_->GetLinkKey()); |
| ASSERT_EQ(key_type, security_record_->GetKeyType()); |
| } |
| |
| // no_input_no_output + keyboard_only is JustWorks no confirmation |
| // Needs dialog as per security a bug unless pairing is temporary |
| TEST_F(ClassicPairingHandlerTest, locally_initiatied_no_input_no_output_keyboard_only_temp) { |
| hci::IoCapability injected_io_capability = hci::IoCapability::NO_INPUT_NO_OUTPUT; |
| hci::AuthenticationRequirements injected_authentication_requirements = hci::AuthenticationRequirements::NO_BONDING; |
| pairing_handler_->Initiate(true, injected_io_capability, hci::OobDataPresent::NOT_PRESENT, |
| injected_authentication_requirements); |
| ReceiveLinkKeyRequest(hci_layer_, device_); |
| auto security_command_view = GetLastCommand(hci_layer_); |
| auto link_key_neg_reply = hci::LinkKeyRequestNegativeReplyView::Create(security_command_view); |
| ASSERT_TRUE(link_key_neg_reply.IsValid()); |
| ASSERT_EQ(OpCode::LINK_KEY_REQUEST_NEGATIVE_REPLY, link_key_neg_reply.GetOpCode()); |
| ReceiveIoCapabilityRequest(hci_layer_, device_); |
| security_command_view = GetLastCommand(hci_layer_); |
| ASSERT_EQ(OpCode::IO_CAPABILITY_REQUEST_REPLY, security_command_view.GetOpCode()); |
| auto io_cap_request_reply = hci::IoCapabilityRequestReplyView::Create(security_command_view); |
| ASSERT_TRUE(io_cap_request_reply.IsValid()); |
| ASSERT_EQ(injected_io_capability, io_cap_request_reply.GetIoCapability()); |
| ASSERT_EQ(hci::OobDataPresent::NOT_PRESENT, io_cap_request_reply.GetOobPresent()); |
| ASSERT_EQ(injected_authentication_requirements, io_cap_request_reply.GetAuthenticationRequirements()); |
| ReceiveIoCapabilityResponse(hci_layer_, device_, hci::IoCapability::KEYBOARD_ONLY, hci::OobDataPresent::NOT_PRESENT, |
| hci::AuthenticationRequirements::NO_BONDING); |
| uint32_t numeric_value = 0x123; |
| ReceiveUserConfirmationRequest(hci_layer_, device_, numeric_value); |
| security_command_view = GetLastCommand(hci_layer_); |
| ASSERT_EQ(OpCode::USER_CONFIRMATION_REQUEST_REPLY, security_command_view.GetOpCode()); |
| auto user_conf_request_reply = hci::UserConfirmationRequestReplyView::Create(security_command_view); |
| ASSERT_TRUE(user_conf_request_reply.IsValid()); |
| ReceiveSimplePairingComplete(hci_layer_, hci::ErrorCode::SUCCESS, device_); |
| std::array<uint8_t, 16> link_key = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5}; |
| hci::KeyType key_type = hci::KeyType::DEBUG_COMBINATION; |
| ReceiveLinkKeyNotification(hci_layer_, device_, link_key, key_type); |
| ASSERT_EQ(link_key, security_record_->GetLinkKey()); |
| ASSERT_EQ(key_type, security_record_->GetKeyType()); |
| } |
| |
| // no_input_no_output + no_input_no_output is JustWorks no confirmation |
| // Needs dialog as per security a bug unless pairing is temporary |
| TEST_F(ClassicPairingHandlerTest, locally_initiatied_no_input_no_output_no_input_no_output_temp) { |
| hci::IoCapability injected_io_capability = hci::IoCapability::NO_INPUT_NO_OUTPUT; |
| hci::AuthenticationRequirements injected_authentication_requirements = hci::AuthenticationRequirements::NO_BONDING; |
| pairing_handler_->Initiate(true, injected_io_capability, hci::OobDataPresent::NOT_PRESENT, |
| injected_authentication_requirements); |
| ReceiveLinkKeyRequest(hci_layer_, device_); |
| auto security_command_view = GetLastCommand(hci_layer_); |
| auto link_key_neg_reply = hci::LinkKeyRequestNegativeReplyView::Create(security_command_view); |
| ASSERT_TRUE(link_key_neg_reply.IsValid()); |
| ASSERT_EQ(OpCode::LINK_KEY_REQUEST_NEGATIVE_REPLY, link_key_neg_reply.GetOpCode()); |
| ReceiveIoCapabilityRequest(hci_layer_, device_); |
| security_command_view = GetLastCommand(hci_layer_); |
| ASSERT_EQ(OpCode::IO_CAPABILITY_REQUEST_REPLY, security_command_view.GetOpCode()); |
| auto io_cap_request_reply = hci::IoCapabilityRequestReplyView::Create(security_command_view); |
| ASSERT_TRUE(io_cap_request_reply.IsValid()); |
| ASSERT_EQ(injected_io_capability, io_cap_request_reply.GetIoCapability()); |
| ASSERT_EQ(hci::OobDataPresent::NOT_PRESENT, io_cap_request_reply.GetOobPresent()); |
| ASSERT_EQ(injected_authentication_requirements, io_cap_request_reply.GetAuthenticationRequirements()); |
| ReceiveIoCapabilityResponse(hci_layer_, device_, hci::IoCapability::NO_INPUT_NO_OUTPUT, |
| hci::OobDataPresent::NOT_PRESENT, hci::AuthenticationRequirements::NO_BONDING); |
| uint32_t numeric_value = 0x123; |
| ReceiveUserConfirmationRequest(hci_layer_, device_, numeric_value); |
| security_command_view = GetLastCommand(hci_layer_); |
| ASSERT_EQ(OpCode::USER_CONFIRMATION_REQUEST_REPLY, security_command_view.GetOpCode()); |
| auto user_conf_request_reply = hci::UserConfirmationRequestReplyView::Create(security_command_view); |
| ASSERT_TRUE(user_conf_request_reply.IsValid()); |
| ReceiveSimplePairingComplete(hci_layer_, hci::ErrorCode::SUCCESS, device_); |
| std::array<uint8_t, 16> link_key = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5}; |
| hci::KeyType key_type = hci::KeyType::DEBUG_COMBINATION; |
| ReceiveLinkKeyNotification(hci_layer_, device_, link_key, key_type); |
| ASSERT_EQ(link_key, security_record_->GetLinkKey()); |
| ASSERT_EQ(key_type, security_record_->GetKeyType()); |
| } |
| |
| // Remotely initiated |
| |
| // Collisions |
| |
| } // namespace |
| } // namespace channel |
| } // namespace security |
| } // namespace bluetooth |