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

Commit 10110c50 authored by Martin Brabham's avatar Martin Brabham
Browse files

GD Security: InternalEnforceSecurityPolicy

Currently, the logic is a little confusing, this CL should simplify it.

Bug: 162984360
Tag: #gd-refactor
Test: cert/run --host SecurityTest:test_dut_initiated_no_input_no_output_no_input_no_output_twice_bond_and_enforce
Test: atest --host bluetooth_test_gd
Change-Id: I19753a29487c4bf2c3b40189c0576526d39657c8
parent 4b4cddda
Loading
Loading
Loading
Loading
+29 −56
Original line number Diff line number Diff line
@@ -403,8 +403,12 @@ void SecurityManagerImpl::OnPairingHandlerComplete(hci::Address address, Pairing
  auto record = this->security_database_.FindOrCreate(remote);
  record->CancelPairing();
  security_database_.SaveRecordsToStorage();
  // Only call update link if we need to
  auto policy_callback_entry = enforce_security_policy_callback_map_.find(remote);
  if (policy_callback_entry != enforce_security_policy_callback_map_.end()) {
    UpdateLinkSecurityCondition(remote);
  }
}

void SecurityManagerImpl::OnL2capRegistrationCompleteLe(
    l2cap::le::FixedChannelManager::RegistrationResult result,
@@ -743,54 +747,29 @@ void SecurityManagerImpl::InternalEnforceSecurityPolicy(
    l2cap::classic::SecurityEnforcementInterface::ResultCallback result_callback) {
  if (IsSecurityRequirementSatisfied(remote, policy)) {
    // Notify client immediately if already satisfied
    result_callback.Invoke(true);
    std::move(result_callback).Invoke(true);
    return;
  }

  hci::AuthenticationRequirements authentication_requirements = kDefaultAuthenticationRequirements;

  // At this point we don't meet the security requirements; must pair
  auto record = this->security_database_.FindOrCreate(remote);
  bool need_to_pair = false;
  hci::AuthenticationRequirements authentication_requirements = kDefaultAuthenticationRequirements;
  enforce_security_policy_callback_map_[remote] = {policy, std::move(result_callback)};

  switch (policy) {
    case l2cap::classic::SecurityPolicy::BEST:
    case l2cap::classic::SecurityPolicy::AUTHENTICATED_ENCRYPTED_TRANSPORT:
      if (!record->IsPaired() || record->IsTemporary()) {
        need_to_pair = true;
      } else if (record->IsAuthenticated()) {
        // if paired with MITM, only encryption is missing, so we just need to wait for encryption change callback
      } else {
        // We have an unauthenticated link key, so we need to pair again with MITM
        // Need to pair again with MITM
        need_to_pair = true;
      // Force MITM requirement locally
      authentication_requirements = hci::AuthenticationRequirements::GENERAL_BONDING_MITM_PROTECTION;
        if (record->RequiresMitmProtection()) {
          // Workaround for headset: If no MITM is needed during pairing, we don't mandate authenticated LK
          // TODO(b/165671060): Use IO cap to check whether we can waive authenticated LK requirement
          need_to_pair = false;
        }
      }
      break;
    case l2cap::classic::SecurityPolicy::ENCRYPTED_TRANSPORT:
      if (!record->IsPaired()) {
        need_to_pair = true;
        authentication_requirements = hci::AuthenticationRequirements::NO_BONDING;
      } else {
        // just need to wait for encryption change callback
      }
      authentication_requirements = hci::AuthenticationRequirements::GENERAL_BONDING;
      break;
    default:
      // This will never happen because of check in IsSecurityRequirementSatisfied
      return;
  }

  auto entry = enforce_security_policy_callback_map_.find(remote);
  if (entry != enforce_security_policy_callback_map_.end()) {
    LOG_WARN("Callback already pending for remote: '%s' !", remote.ToString().c_str());
  } else {
    enforce_security_policy_callback_map_[remote] = {policy, std::move(result_callback)};
  }

  if (need_to_pair && !record->IsPairing()) {
  LOG_WARN("Dispatch #3");
  DispatchPairingHandler(
      record,
@@ -799,38 +778,28 @@ void SecurityManagerImpl::InternalEnforceSecurityPolicy(
      this->local_oob_data_present_,
      std::as_const(authentication_requirements));
}
}

void SecurityManagerImpl::UpdateLinkSecurityCondition(hci::AddressWithType remote) {
  auto record = this->security_database_.FindOrCreate(remote);
  auto entry = enforce_security_policy_callback_map_.find(remote);
  if (entry == enforce_security_policy_callback_map_.end()) {
    LOG_ERROR("No security reuest pending for %s", remote.ToString().c_str());
    LOG_ERROR("No L2CAP security policy callback pending for %s", remote.ToString().c_str());
    return;
  }

  auto policy = entry->second.policy_;

  if (IsSecurityRequirementSatisfied(remote, policy)) {
    entry->second.callback_.Invoke(true);
  std::move(entry->second.callback_).Invoke(IsSecurityRequirementSatisfied(remote, entry->second.policy_));
  enforce_security_policy_callback_map_.erase(entry);
}
}

bool SecurityManagerImpl::IsSecurityRequirementSatisfied(
    hci::AddressWithType remote, l2cap::classic::SecurityPolicy policy) {
  auto record = security_database_.FindOrCreate(remote);

  switch (policy) {
    case l2cap::classic::SecurityPolicy::BEST:
    case l2cap::classic::SecurityPolicy::AUTHENTICATED_ENCRYPTED_TRANSPORT:
      return (record->IsPaired() && record->IsAuthenticated());
    case l2cap::classic::SecurityPolicy::ENCRYPTED_TRANSPORT:
      return record->IsPaired();
    case l2cap::classic::SecurityPolicy::_SDP_ONLY_NO_SECURITY_WHATSOEVER_PLAINTEXT_TRANSPORT_OK:
      return true;
    default:
      return false;
      return true;
  }
}

@@ -838,8 +807,12 @@ void SecurityManagerImpl::EnforceSecurityPolicy(
    hci::AddressWithType remote,
    l2cap::classic::SecurityPolicy policy,
    l2cap::classic::SecurityEnforcementInterface::ResultCallback result_callback) {
  LOG_INFO("Attempting to enforce security policy");
  auto record = security_database_.FindOrCreate(remote);
  if (!record->IsPairing()) {
    this->InternalEnforceSecurityPolicy(remote, policy, std::move(result_callback));
  }
}

void SecurityManagerImpl::EnforceLeSecurityPolicy(
    hci::AddressWithType remote, l2cap::le::SecurityPolicy policy,