Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit fa817026 authored by Treehugger Robot's avatar Treehugger Robot Committed by Gerrit Code Review
Browse files

Merge "RootCanal: Check PIN on both sides"

parents 23b3d30f 29e263c1
Loading
Loading
Loading
Loading
+127 −2
Original line number Diff line number Diff line
@@ -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;
  }
  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;
}

+2 −0
Original line number Diff line number Diff line
@@ -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(
+25 −0
Original line number Diff line number Diff line
@@ -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
+10 −0
Original line number Diff line number Diff line
@@ -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_{};
+14 −0
Original line number Diff line number Diff line
@@ -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
}