From eec8a5bc063d9899e0d1c04fb14a224f9e8cf2e7 Mon Sep 17 00:00:00 2001 From: Myles Watson Date: Thu, 14 Jan 2021 17:27:27 -0800 Subject: [PATCH] RootCanal: Check PIN on both sides Bug: 148864229 Tag: #gd-refactor Test: cert/run Change-Id: I54801c552afe6cc1068c9104836fbe4a211d566c --- .../model/controller/link_layer_controller.cc | 129 ++++++++++++++++++++- .../model/controller/link_layer_controller.h | 2 + .../model/controller/security_manager.cc | 25 ++++ .../model/controller/security_manager.h | 10 ++ .../test_vendor_lib/packets/link_layer_packets.pdl | 14 +++ 5 files changed, 178 insertions(+), 2 deletions(-) diff --git a/vendor_libs/test_vendor_lib/model/controller/link_layer_controller.cc b/vendor_libs/test_vendor_lib/model/controller/link_layer_controller.cc index ec9ccdecd..c58ac659b 100644 --- a/vendor_libs/test_vendor_lib/model/controller/link_layer_controller.cc +++ b/vendor_libs/test_vendor_lib/model/controller/link_layer_controller.cc @@ -285,6 +285,12 @@ void LinkLayerController::IncomingPacket( case (model::packets::PacketType::PASSKEY_FAILED): IncomingPasskeyFailedPacket(incoming); break; + case (model::packets::PacketType::PIN_REQUEST): + IncomingPinRequestPacket(incoming); + break; + case (model::packets::PacketType::PIN_RESPONSE): + IncomingPinResponsePacket(incoming); + break; case (model::packets::PacketType::REMOTE_NAME_REQUEST): IncomingRemoteNameRequest(incoming); break; @@ -1339,6 +1345,111 @@ void LinkLayerController::IncomingPasskeyFailedPacket( }); } +void LinkLayerController::IncomingPinRequestPacket( + model::packets::LinkLayerPacketView incoming) { + auto request = model::packets::PinRequestView::Create(incoming); + ASSERT(request.IsValid()); + auto peer = incoming.GetSourceAddress(); + auto handle = connections_.GetHandle(AddressWithType( + peer, bluetooth::hci::AddressType::PUBLIC_DEVICE_ADDRESS)); + if (handle == kReservedHandle) { + LOG_INFO("Dropping %s request (no connection)", peer.ToString().c_str()); + auto wrong_pin = request.GetPinCode(); + wrong_pin[0] = wrong_pin[0]++; + SendLinkLayerPacket(model::packets::PinResponseBuilder::Create( + properties_.GetAddress(), peer, wrong_pin)); + return; + } + if (security_manager_.AuthenticationInProgress()) { + auto current_peer = security_manager_.GetAuthenticationAddress(); + if (current_peer != peer) { + LOG_INFO("Dropping %s request (%s in progress)", peer.ToString().c_str(), + current_peer.ToString().c_str()); + auto wrong_pin = request.GetPinCode(); + wrong_pin[0] = wrong_pin[0]++; + SendLinkLayerPacket(model::packets::PinResponseBuilder::Create( + properties_.GetAddress(), peer, wrong_pin)); + return; + } + } else { + LOG_INFO("Incoming authentication request %s", peer.ToString().c_str()); + security_manager_.AuthenticationRequest(peer, handle); + } + auto current_peer = security_manager_.GetAuthenticationAddress(); + security_manager_.SetRemotePin(peer, request.GetPinCode()); + if (security_manager_.GetPinRequested(peer)) { + if (security_manager_.GetLocalPinResponseReceived(peer)) { + SendLinkLayerPacket(model::packets::PinResponseBuilder::Create( + properties_.GetAddress(), peer, request.GetPinCode())); + if (security_manager_.PinCompare()) { + LOG_INFO("Authenticating %s", peer.ToString().c_str()); + SaveKeyAndAuthenticate('L', peer); // Legacy + } else { + security_manager_.AuthenticationRequestFinished(); + ScheduleTask(milliseconds(5), [this, peer]() { + send_event_(bluetooth::hci::SimplePairingCompleteBuilder::Create( + ErrorCode::AUTHENTICATION_FAILURE, peer)); + }); + } + } + } else { + LOG_INFO("PIN pairing %s", properties_.GetAddress().ToString().c_str()); + ScheduleTask(milliseconds(5), [this, peer]() { + security_manager_.SetPinRequested(peer); + send_event_(bluetooth::hci::PinCodeRequestBuilder::Create(peer)); + }); + } +} + +void LinkLayerController::IncomingPinResponsePacket( + model::packets::LinkLayerPacketView incoming) { + auto request = model::packets::PinResponseView::Create(incoming); + ASSERT(request.IsValid()); + auto peer = incoming.GetSourceAddress(); + auto handle = connections_.GetHandle(AddressWithType( + peer, bluetooth::hci::AddressType::PUBLIC_DEVICE_ADDRESS)); + if (handle == kReservedHandle) { + LOG_INFO("Dropping %s request (no connection)", peer.ToString().c_str()); + return; + } + if (security_manager_.AuthenticationInProgress()) { + auto current_peer = security_manager_.GetAuthenticationAddress(); + if (current_peer != peer) { + LOG_INFO("Dropping %s request (%s in progress)", peer.ToString().c_str(), + current_peer.ToString().c_str()); + return; + } + } else { + LOG_INFO("Dropping response without authentication request %s", + peer.ToString().c_str()); + return; + } + auto current_peer = security_manager_.GetAuthenticationAddress(); + security_manager_.SetRemotePin(peer, request.GetPinCode()); + if (security_manager_.GetPinRequested(peer)) { + if (security_manager_.GetLocalPinResponseReceived(peer)) { + SendLinkLayerPacket(model::packets::PinResponseBuilder::Create( + properties_.GetAddress(), peer, request.GetPinCode())); + if (security_manager_.PinCompare()) { + LOG_INFO("Authenticating %s", peer.ToString().c_str()); + SaveKeyAndAuthenticate('L', peer); // Legacy + } else { + security_manager_.AuthenticationRequestFinished(); + ScheduleTask(milliseconds(5), [this, peer]() { + send_event_(bluetooth::hci::SimplePairingCompleteBuilder::Create( + ErrorCode::AUTHENTICATION_FAILURE, peer)); + }); + } + } + } else { + LOG_INFO("PIN pairing %s", properties_.GetAddress().ToString().c_str()); + ScheduleTask(milliseconds(5), [this, peer]() { + security_manager_.SetPinRequested(peer); + send_event_(bluetooth::hci::PinCodeRequestBuilder::Create(peer)); + }); + } +} + void LinkLayerController::IncomingPagePacket( model::packets::LinkLayerPacketView incoming) { auto page = model::packets::PageView::Create(incoming); @@ -1677,8 +1788,22 @@ ErrorCode LinkLayerController::PinCodeRequestReply(const Address& peer, LOG_INFO("No Pin Requested for %s", peer.ToString().c_str()); return ErrorCode::COMMAND_DISALLOWED; } - LOG_INFO("Authenticating %s", peer.ToString().c_str()); - SaveKeyAndAuthenticate('L', peer); // Legacy + security_manager_.SetLocalPin(peer, pin); + if (security_manager_.GetRemotePinResponseReceived(peer)) { + if (security_manager_.PinCompare()) { + LOG_INFO("Authenticating %s", peer.ToString().c_str()); + SaveKeyAndAuthenticate('L', peer); // Legacy + } else { + security_manager_.AuthenticationRequestFinished(); + ScheduleTask(milliseconds(5), [this, peer]() { + send_event_(bluetooth::hci::SimplePairingCompleteBuilder::Create( + ErrorCode::AUTHENTICATION_FAILURE, peer)); + }); + } + } else { + SendLinkLayerPacket(model::packets::PinRequestBuilder::Create( + properties_.GetAddress(), peer, pin)); + } return ErrorCode::SUCCESS; } diff --git a/vendor_libs/test_vendor_lib/model/controller/link_layer_controller.h b/vendor_libs/test_vendor_lib/model/controller/link_layer_controller.h index a9addf6e7..789f85a23 100644 --- a/vendor_libs/test_vendor_lib/model/controller/link_layer_controller.h +++ b/vendor_libs/test_vendor_lib/model/controller/link_layer_controller.h @@ -369,6 +369,8 @@ class LinkLayerController { void IncomingPageResponsePacket(model::packets::LinkLayerPacketView packet); void IncomingPasskeyPacket(model::packets::LinkLayerPacketView packet); void IncomingPasskeyFailedPacket(model::packets::LinkLayerPacketView packet); + void IncomingPinRequestPacket(model::packets::LinkLayerPacketView packet); + void IncomingPinResponsePacket(model::packets::LinkLayerPacketView packet); void IncomingReadRemoteLmpFeatures( model::packets::LinkLayerPacketView packet); void IncomingReadRemoteLmpFeaturesResponse( diff --git a/vendor_libs/test_vendor_lib/model/controller/security_manager.cc b/vendor_libs/test_vendor_lib/model/controller/security_manager.cc index 8d7e1dfca..ef4db880c 100644 --- a/vendor_libs/test_vendor_lib/model/controller/security_manager.cc +++ b/vendor_libs/test_vendor_lib/model/controller/security_manager.cc @@ -64,6 +64,8 @@ void SecurityManager::AuthenticationRequest(const Address& addr, uint16_t handle current_handle_ = handle; peer_address_ = addr; peer_pin_requested_ = false; + peer_pin_received_ = false; + host_pin_received_ = false; } void SecurityManager::AuthenticationRequestFinished() { @@ -198,4 +200,27 @@ bool SecurityManager::GetPinRequested(const Address& addr) { return peer_pin_requested_; } +void SecurityManager::SetLocalPin(const Address& peer, + const std::vector& pin) { + host_pin_received_ = true; + host_pin_ = pin; +} + +void SecurityManager::SetRemotePin(const Address& peer, + const std::vector& pin) { + peer_pin_received_ = true; + peer_pin_ = pin; +} + +bool SecurityManager::GetLocalPinResponseReceived(const Address& peer) { + return host_pin_received_; +} + +bool SecurityManager::GetRemotePinResponseReceived(const Address& peer) { + return peer_pin_received_; +} + +bool SecurityManager::PinCompare() { + return host_pin_received_ && peer_pin_received_ && peer_pin_ == host_pin_; +} } // namespace test_vendor_lib diff --git a/vendor_libs/test_vendor_lib/model/controller/security_manager.h b/vendor_libs/test_vendor_lib/model/controller/security_manager.h index d197b7cc8..738f7e0ff 100644 --- a/vendor_libs/test_vendor_lib/model/controller/security_manager.h +++ b/vendor_libs/test_vendor_lib/model/controller/security_manager.h @@ -20,6 +20,7 @@ #include #include #include +#include #include "hci/address.h" @@ -80,6 +81,11 @@ class SecurityManager { void SetPinRequested(const Address& addr); bool GetPinRequested(const Address& addr); + void SetLocalPin(const Address& peer, const std::vector& pin); + void SetRemotePin(const Address& peer, const std::vector& pin); + bool GetLocalPinResponseReceived(const Address& peer); + bool GetRemotePinResponseReceived(const Address& peer); + bool PinCompare(); void SetPeerIoCapability(const Address& addr, uint8_t io_capability, uint8_t oob_present_flag, uint8_t authentication_requirements); @@ -100,12 +106,16 @@ class SecurityManager { AuthenticationType peer_authentication_requirements_{ AuthenticationType::NO_BONDING}; bool peer_pin_requested_{false}; + bool peer_pin_received_{false}; + std::vector peer_pin_; bool host_capabilities_valid_{false}; IoCapabilityType host_io_capability_{IoCapabilityType::DISPLAY_ONLY}; uint8_t host_oob_present_flag_{0}; AuthenticationType host_authentication_requirements_{ AuthenticationType::NO_BONDING}; + std::vector host_pin_; + bool host_pin_received_{false}; bool authenticating_{false}; uint16_t current_handle_{}; diff --git a/vendor_libs/test_vendor_lib/packets/link_layer_packets.pdl b/vendor_libs/test_vendor_lib/packets/link_layer_packets.pdl index 2c754f383..0b10c593c 100644 --- a/vendor_libs/test_vendor_lib/packets/link_layer_packets.pdl +++ b/vendor_libs/test_vendor_lib/packets/link_layer_packets.pdl @@ -46,6 +46,8 @@ enum PacketType : 8 { PASSKEY = 0x27, PASSKEY_FAILED = 0x28, KEYPRESS_NOTIFICATION = 0x29, + PIN_REQUEST = 0x2A, + PIN_RESPONSE = 0x2B, } packet LinkLayerPacket { @@ -336,3 +338,15 @@ packet PasskeyFailed : LinkLayerPacket (type = PASSKEY_FAILED){ packet KeypressNotification : LinkLayerPacket (type = KEYPRESS_NOTIFICATION){ notification_type : PasskeyNotificationType, } + +packet PinRequest : LinkLayerPacket (type = PIN_REQUEST) { + _size_(pin_code) : 5, // 0x01 - 0x10 + _reserved_ : 3, + pin_code : 8[], // string parameter, first octet first +} + +packet PinResponse : LinkLayerPacket (type = PIN_RESPONSE) { + _size_(pin_code) : 5, // 0x01 - 0x10 + _reserved_ : 3, + pin_code : 8[], // string parameter, first octet first +} -- 2.11.0