OSDN Git Service

RootCanal: Check PIN on both sides
authorMyles Watson <mylesgw@google.com>
Fri, 15 Jan 2021 01:27:27 +0000 (17:27 -0800)
committerMyles Watson <mylesgw@google.com>
Fri, 15 Jan 2021 01:32:36 +0000 (17:32 -0800)
Bug: 148864229
Tag: #gd-refactor
Test: cert/run
Change-Id: I54801c552afe6cc1068c9104836fbe4a211d566c

vendor_libs/test_vendor_lib/model/controller/link_layer_controller.cc
vendor_libs/test_vendor_lib/model/controller/link_layer_controller.h
vendor_libs/test_vendor_lib/model/controller/security_manager.cc
vendor_libs/test_vendor_lib/model/controller/security_manager.h
vendor_libs/test_vendor_lib/packets/link_layer_packets.pdl

index ec9ccde..c58ac65 100644 (file)
@@ -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;
 }
 
index a9addf6..789f85a 100644 (file)
@@ -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(
index 8d7e1df..ef4db88 100644 (file)
@@ -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<uint8_t>& pin) {
+  host_pin_received_ = true;
+  host_pin_ = pin;
+}
+
+void SecurityManager::SetRemotePin(const Address& peer,
+                                   const std::vector<uint8_t>& 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
index d197b7c..738f7e0 100644 (file)
@@ -20,6 +20,7 @@
 #include <cstdint>
 #include <string>
 #include <unordered_map>
+#include <vector>
 
 #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<uint8_t>& pin);
+  void SetRemotePin(const Address& peer, const std::vector<uint8_t>& 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<uint8_t> 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<uint8_t> host_pin_;
+  bool host_pin_received_{false};
 
   bool authenticating_{false};
   uint16_t current_handle_{};
index 2c754f3..0b10c59 100644 (file)
@@ -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
+}