You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

889 lines
36 KiB

/*
*
* 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_manager_impl.h"
#include <iostream>
#include "common/bind.h"
#include "crypto_toolbox/crypto_toolbox.h"
#include "hci/address_with_type.h"
#include "os/log.h"
#include "os/rand.h"
#include "security/initial_informations.h"
#include "security/internal/security_manager_impl.h"
#include "security/pairing_handler_le.h"
#include "security/security_manager.h"
#include "security/ui.h"
namespace bluetooth {
namespace security {
namespace internal {
void SecurityManagerImpl::DispatchPairingHandler(
std::shared_ptr<record::SecurityRecord> record,
bool locally_initiated,
hci::IoCapability io_capability,
hci::AuthenticationRequirements auth_requirements,
pairing::OobData remote_p192_oob_data,
pairing::OobData remote_p256_oob_data) {
common::OnceCallback<void(hci::Address, PairingResultOrFailure)> callback =
common::BindOnce(&SecurityManagerImpl::OnPairingHandlerComplete, common::Unretained(this));
auto entry = pairing_handler_map_.find(record->GetPseudoAddress()->GetAddress());
if (entry != pairing_handler_map_.end()) {
LOG_WARN("Device already has a pairing handler, and is in the middle of pairing!");
return;
}
std::shared_ptr<pairing::PairingHandler> pairing_handler = nullptr;
switch (record->GetPseudoAddress()->GetAddressType()) {
case hci::AddressType::PUBLIC_DEVICE_ADDRESS: {
pairing_handler = std::make_shared<security::pairing::ClassicPairingHandler>(
security_manager_channel_,
record,
security_handler_,
std::move(callback),
user_interface_,
user_interface_handler_,
record->GetPseudoAddress()->ToString(),
name_db_module_);
break;
}
default:
ASSERT_LOG(false, "Pairing type %hhu not implemented!", record->GetPseudoAddress()->GetAddressType());
}
auto new_entry = std::pair<hci::Address, std::shared_ptr<pairing::PairingHandler>>(
record->GetPseudoAddress()->GetAddress(), pairing_handler);
pairing_handler_map_.insert(std::move(new_entry));
pairing_handler->Initiate(
locally_initiated, io_capability, auth_requirements, remote_p192_oob_data, remote_p256_oob_data);
}
void SecurityManagerImpl::Init() {
security_manager_channel_->SetChannelListener(this);
security_manager_channel_->SendCommand(hci::WriteSimplePairingModeBuilder::Create(hci::Enable::ENABLED));
security_manager_channel_->SendCommand(hci::WriteSecureConnectionsHostSupportBuilder::Create(hci::Enable::ENABLED));
ASSERT_LOG(storage_module_ != nullptr, "Storage module must not be null!");
security_database_.LoadRecordsFromStorage();
storage::AdapterConfig adapter_config = storage_module_->GetAdapterConfig();
if (!adapter_config.GetLeIdentityResolvingKey()) {
auto mutation = storage_module_->Modify();
mutation.Add(adapter_config.SetLeIdentityResolvingKey(bluetooth::os::GenerateRandom<16>()));
mutation.Commit();
}
Address controllerAddress = controller_->GetMacAddress();
if (!adapter_config.GetAddress() || adapter_config.GetAddress().value() != controllerAddress) {
auto mutation = storage_module_->Modify();
mutation.Add(adapter_config.SetAddress(controllerAddress));
mutation.Commit();
}
local_identity_address_ =
hci::AddressWithType(adapter_config.GetAddress().value(), hci::AddressType::PUBLIC_DEVICE_ADDRESS);
local_identity_resolving_key_ = adapter_config.GetLeIdentityResolvingKey().value().bytes;
hci::LeAddressManager::AddressPolicy address_policy = hci::LeAddressManager::AddressPolicy::USE_RESOLVABLE_ADDRESS;
hci::AddressWithType address_with_type(hci::Address{}, hci::AddressType::RANDOM_DEVICE_ADDRESS);
/* 7 minutes minimum, 15 minutes maximum for random address refreshing */
auto minimum_rotation_time = std::chrono::minutes(7);
auto maximum_rotation_time = std::chrono::minutes(15);
acl_manager_->SetPrivacyPolicyForInitiatorAddress(
address_policy, address_with_type, minimum_rotation_time, maximum_rotation_time);
}
void SecurityManagerImpl::CreateBond(hci::AddressWithType device) {
this->CreateBondOutOfBand(device, pairing::OobData(), pairing::OobData());
}
void SecurityManagerImpl::CreateBondOutOfBand(
hci::AddressWithType device, pairing::OobData remote_p192_oob_data, pairing::OobData remote_p256_oob_data) {
auto record = security_database_.FindOrCreate(device);
if (record->IsPaired()) {
// Bonded means we saved it, but the caller doesn't care
// Bonded will always mean paired
NotifyDeviceBonded(device);
} else {
if (!record->IsPairing()) {
// Dispatch pairing handler, if we are calling create we are the initiator
LOG_WARN("Dispatch #1");
DispatchPairingHandler(
record,
true,
this->local_io_capability_,
this->local_authentication_requirements_,
remote_p192_oob_data,
remote_p256_oob_data);
}
}
}
void SecurityManagerImpl::CreateBondLe(hci::AddressWithType address) {
auto record = security_database_.FindOrCreate(address);
if (record->IsPaired()) {
NotifyDeviceBondFailed(address, PairingFailure("Already bonded"));
return;
}
pending_le_pairing_.address_ = address;
LeFixedChannelEntry* stored_chan = FindStoredLeChannel(address);
if (stored_chan) {
// We are already connected
ConnectionIsReadyStartPairing(stored_chan);
return;
}
l2cap_manager_le_->ConnectServices(
address, common::BindOnce(&SecurityManagerImpl::OnConnectionFailureLe, common::Unretained(this)),
security_handler_);
}
void SecurityManagerImpl::CancelBond(hci::AddressWithType device) {
auto entry = pairing_handler_map_.find(device.GetAddress());
if (entry != pairing_handler_map_.end()) {
auto cancel_me = entry->second;
pairing_handler_map_.erase(entry);
cancel_me->Cancel();
}
auto record = security_database_.FindOrCreate(device);
record->CancelPairing();
WipeLePairingHandler();
}
void SecurityManagerImpl::RemoveBond(hci::AddressWithType device) {
CancelBond(device);
security_manager_channel_->Disconnect(device.GetAddress());
security_database_.Remove(device);
security_manager_channel_->SendCommand(hci::DeleteStoredLinkKeyBuilder::Create(
device.GetAddress(), hci::DeleteStoredLinkKeyDeleteAllFlag::SPECIFIED_BD_ADDR));
NotifyDeviceUnbonded(device);
}
void SecurityManagerImpl::SetUserInterfaceHandler(UI* user_interface, os::Handler* handler) {
if (user_interface_ != nullptr || user_interface_handler_ != nullptr) {
LOG_ALWAYS_FATAL("Listener has already been registered!");
}
user_interface_ = user_interface;
user_interface_handler_ = handler;
}
// TODO(jpawlowski): remove once we have config file abstraction in cert tests
void SecurityManagerImpl::SetLeInitiatorAddressPolicyForTest(
hci::LeAddressManager::AddressPolicy address_policy,
hci::AddressWithType fixed_address,
crypto_toolbox::Octet16 rotation_irk,
std::chrono::milliseconds minimum_rotation_time,
std::chrono::milliseconds maximum_rotation_time) {
acl_manager_->SetPrivacyPolicyForInitiatorAddressForTest(
address_policy, fixed_address, rotation_irk, minimum_rotation_time, maximum_rotation_time);
}
void SecurityManagerImpl::RegisterCallbackListener(ISecurityManagerListener* listener, os::Handler* handler) {
for (auto it = listeners_.begin(); it != listeners_.end(); ++it) {
if (it->first == listener) {
LOG_ALWAYS_FATAL("Listener has already been registered!");
}
}
listeners_.push_back({listener, handler});
}
void SecurityManagerImpl::UnregisterCallbackListener(ISecurityManagerListener* listener) {
for (auto it = listeners_.begin(); it != listeners_.end(); ++it) {
if (it->first == listener) {
listeners_.erase(it);
return;
}
}
LOG_ALWAYS_FATAL("Listener has not been registered!");
}
void SecurityManagerImpl::NotifyDeviceBonded(hci::AddressWithType device) {
for (auto& iter : listeners_) {
iter.second->Post(common::Bind(&ISecurityManagerListener::OnDeviceBonded, common::Unretained(iter.first), device));
}
}
void SecurityManagerImpl::NotifyDeviceBondFailed(hci::AddressWithType device, PairingFailure status) {
for (auto& iter : listeners_) {
iter.second->Post(
common::Bind(&ISecurityManagerListener::OnDeviceBondFailed, common::Unretained(iter.first), device, status));
}
}
void SecurityManagerImpl::NotifyDeviceUnbonded(hci::AddressWithType device) {
for (auto& iter : listeners_) {
iter.second->Post(
common::Bind(&ISecurityManagerListener::OnDeviceUnbonded, common::Unretained(iter.first), device));
}
acl_manager_->RemoveDeviceFromConnectList(device);
}
void SecurityManagerImpl::NotifyEncryptionStateChanged(hci::EncryptionChangeView encryption_change_view) {
for (auto& iter : listeners_) {
iter.second->Post(common::Bind(&ISecurityManagerListener::OnEncryptionStateChanged, common::Unretained(iter.first),
encryption_change_view));
}
}
template <class T>
void SecurityManagerImpl::HandleEvent(T packet) {
ASSERT(packet.IsValid());
auto entry = pairing_handler_map_.find(packet.GetBdAddr());
if (entry == pairing_handler_map_.end()) {
auto bd_addr = packet.GetBdAddr();
auto event_code = packet.GetEventCode();
if (event_code != hci::EventCode::LINK_KEY_REQUEST && event_code != hci::EventCode::PIN_CODE_REQUEST &&
event_code != hci::EventCode::IO_CAPABILITY_RESPONSE) {
LOG_ERROR("No classic pairing handler for device '%s' ready for command %s ", bd_addr.ToString().c_str(),
hci::EventCodeText(event_code).c_str());
return;
}
auto device = storage_module_->GetDeviceByClassicMacAddress(bd_addr);
auto record =
security_database_.FindOrCreate(hci::AddressWithType{bd_addr, hci::AddressType::PUBLIC_DEVICE_ADDRESS});
LOG_WARN("Dispatch #2");
DispatchPairingHandler(
record,
false,
this->local_io_capability_,
this->local_authentication_requirements_,
pairing::OobData(),
pairing::OobData());
entry = pairing_handler_map_.find(bd_addr);
}
entry->second->OnReceive(packet);
}
void SecurityManagerImpl::OnHciEventReceived(hci::EventView packet) {
auto event = hci::EventView::Create(packet);
ASSERT_LOG(event.IsValid(), "Received invalid packet");
const hci::EventCode code = event.GetEventCode();
switch (code) {
case hci::EventCode::PIN_CODE_REQUEST:
HandleEvent<hci::PinCodeRequestView>(hci::PinCodeRequestView::Create(event));
break;
case hci::EventCode::LINK_KEY_REQUEST:
HandleEvent(hci::LinkKeyRequestView::Create(event));
break;
case hci::EventCode::LINK_KEY_NOTIFICATION:
HandleEvent(hci::LinkKeyNotificationView::Create(event));
break;
case hci::EventCode::IO_CAPABILITY_REQUEST:
HandleEvent(hci::IoCapabilityRequestView::Create(event));
break;
case hci::EventCode::IO_CAPABILITY_RESPONSE:
HandleEvent(hci::IoCapabilityResponseView::Create(event));
break;
case hci::EventCode::SIMPLE_PAIRING_COMPLETE:
HandleEvent(hci::SimplePairingCompleteView::Create(event));
break;
case hci::EventCode::REMOTE_OOB_DATA_REQUEST:
HandleEvent(hci::RemoteOobDataRequestView::Create(event));
break;
case hci::EventCode::USER_PASSKEY_NOTIFICATION:
HandleEvent(hci::UserPasskeyNotificationView::Create(event));
break;
case hci::EventCode::KEYPRESS_NOTIFICATION:
HandleEvent(hci::KeypressNotificationView::Create(event));
break;
case hci::EventCode::USER_CONFIRMATION_REQUEST:
HandleEvent(hci::UserConfirmationRequestView::Create(event));
break;
case hci::EventCode::USER_PASSKEY_REQUEST:
HandleEvent(hci::UserPasskeyRequestView::Create(event));
break;
case hci::EventCode::REMOTE_HOST_SUPPORTED_FEATURES_NOTIFICATION:
LOG_INFO("Unhandled event: %s", hci::EventCodeText(code).c_str());
break;
case hci::EventCode::ENCRYPTION_CHANGE: {
EncryptionChangeView encryption_change_view = EncryptionChangeView::Create(event);
if (!encryption_change_view.IsValid()) {
LOG_ERROR("Invalid EncryptionChange packet received");
return;
}
if (encryption_change_view.GetConnectionHandle() == pending_le_pairing_.connection_handle_) {
pending_le_pairing_.handler_->OnHciEvent(event);
return;
}
NotifyEncryptionStateChanged(encryption_change_view);
break;
}
default:
ASSERT_LOG(false, "Cannot handle received packet: %s", hci::EventCodeText(code).c_str());
break;
}
}
void SecurityManagerImpl::OnConnectionClosed(hci::Address address) {
auto entry = pairing_handler_map_.find(address);
if (entry != pairing_handler_map_.end()) {
LOG_INFO("Cancelling pairing handler for '%s'", address.ToString().c_str());
entry->second->Cancel();
}
auto record = security_database_.FindOrCreate(hci::AddressWithType(address, hci::AddressType::PUBLIC_DEVICE_ADDRESS));
if (record->IsTemporary()) {
security_database_.Remove(hci::AddressWithType(address, hci::AddressType::PUBLIC_DEVICE_ADDRESS));
}
if (this->facade_disconnect_callback_) {
this->security_handler_->Call(
*this->facade_disconnect_callback_, hci::AddressWithType(address, hci::AddressType::PUBLIC_DEVICE_ADDRESS));
}
}
void SecurityManagerImpl::OnHciLeEvent(hci::LeMetaEventView event) {
hci::SubeventCode code = event.GetSubeventCode();
if (code == hci::SubeventCode::LONG_TERM_KEY_REQUEST) {
hci::LeLongTermKeyRequestView le_long_term_key_request_view = hci::LeLongTermKeyRequestView::Create(event);
if (!le_long_term_key_request_view.IsValid()) {
LOG_ERROR("Invalid LeLongTermKeyRequestView packet received");
return;
}
if (le_long_term_key_request_view.GetConnectionHandle() == pending_le_pairing_.connection_handle_) {
pending_le_pairing_.handler_->OnHciLeEvent(event);
return;
}
LOG_INFO("Unhandled HCI LE security event, code %s", hci::SubeventCodeText(code).c_str());
return;
}
// hci::SubeventCode::READ_LOCAL_P256_PUBLIC_KEY_COMPLETE,
// hci::SubeventCode::GENERATE_DHKEY_COMPLETE,
LOG_ERROR("Unhandled HCI LE security event, code %s", hci::SubeventCodeText(code).c_str());
}
void SecurityManagerImpl::OnPairingPromptAccepted(const bluetooth::hci::AddressWithType& address, bool confirmed) {
auto entry = pairing_handler_map_.find(address.GetAddress());
if (entry != pairing_handler_map_.end()) {
entry->second->OnPairingPromptAccepted(address, confirmed);
} else {
if (pending_le_pairing_.address_ == address) {
pending_le_pairing_.handler_->OnUiAction(PairingEvent::UI_ACTION_TYPE::PAIRING_ACCEPTED, confirmed);
}
}
}
void SecurityManagerImpl::OnConfirmYesNo(const bluetooth::hci::AddressWithType& address, bool confirmed) {
auto entry = pairing_handler_map_.find(address.GetAddress());
if (entry != pairing_handler_map_.end()) {
entry->second->OnConfirmYesNo(address, confirmed);
} else {
if (pending_le_pairing_.address_ == address) {
pending_le_pairing_.handler_->OnUiAction(PairingEvent::UI_ACTION_TYPE::CONFIRM_YESNO, confirmed);
}
}
}
void SecurityManagerImpl::OnPasskeyEntry(const bluetooth::hci::AddressWithType& address, uint32_t passkey) {
auto entry = pairing_handler_map_.find(address.GetAddress());
if (entry != pairing_handler_map_.end()) {
entry->second->OnPasskeyEntry(address, passkey);
} else {
if (pending_le_pairing_.address_ == address) {
pending_le_pairing_.handler_->OnUiAction(PairingEvent::UI_ACTION_TYPE::PASSKEY, passkey);
}
}
}
void SecurityManagerImpl::OnPinEntry(const bluetooth::hci::AddressWithType& address, std::vector<uint8_t> pin) {
auto entry = pairing_handler_map_.find(address.GetAddress());
if (entry != pairing_handler_map_.end()) {
LOG_INFO("PIN for %s", address.ToString().c_str());
entry->second->OnPinEntry(address, pin);
} else {
LOG_WARN("No handler found for PIN for %s", address.ToString().c_str());
// TODO(jpawlowski): Implement LE version
}
}
void SecurityManagerImpl::OnPairingHandlerComplete(hci::Address address, PairingResultOrFailure status) {
auto entry = pairing_handler_map_.find(address);
if (entry != pairing_handler_map_.end()) {
pairing_handler_map_.erase(entry);
security_manager_channel_->Release(address);
}
auto remote = hci::AddressWithType(address, hci::AddressType::PUBLIC_DEVICE_ADDRESS);
if (!std::holds_alternative<PairingFailure>(status)) {
NotifyDeviceBonded(remote);
} else {
NotifyDeviceBondFailed(remote, std::get<PairingFailure>(status));
}
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,
std::unique_ptr<l2cap::le::FixedChannelService> le_smp_service) {
ASSERT_LOG(result == bluetooth::l2cap::le::FixedChannelManager::RegistrationResult::SUCCESS,
"Failed to register to LE SMP Fixed Channel Service");
}
LeFixedChannelEntry* SecurityManagerImpl::FindStoredLeChannel(const hci::AddressWithType& device) {
for (LeFixedChannelEntry& storage : all_channels_) {
if (storage.channel_->GetDevice() == device) {
return &storage;
}
}
return nullptr;
}
bool SecurityManagerImpl::EraseStoredLeChannel(const hci::AddressWithType& device) {
for (auto it = all_channels_.begin(); it != all_channels_.end(); it++) {
if (it->channel_->GetDevice() == device) {
all_channels_.erase(it);
return true;
}
}
return false;
}
void SecurityManagerImpl::OnSmpCommandLe(hci::AddressWithType device) {
LeFixedChannelEntry* stored_chan = FindStoredLeChannel(device);
if (!stored_chan) {
LOG_ALWAYS_FATAL("Received SMP command for unknown channel");
return;
}
std::unique_ptr<l2cap::le::FixedChannel>& channel = stored_chan->channel_;
auto packet = channel->GetQueueUpEnd()->TryDequeue();
if (!packet) {
LOG_ERROR("Received dequeue, but no data ready...");
return;
}
// Pending pairing - pass the data to the handler
auto temp_cmd_view = CommandView::Create(*packet);
if (pending_le_pairing_.address_ == device) {
pending_le_pairing_.handler_->OnCommandView(temp_cmd_view);
return;
}
// no pending pairing attempt
if (!temp_cmd_view.IsValid()) {
LOG_ERROR("Invalid Command packet");
return;
}
if (temp_cmd_view.GetCode() == Code::SECURITY_REQUEST) {
// TODO: either start encryption or pairing
LOG_WARN("Unhandled security request!!!");
return;
}
auto my_role = channel->GetLinkOptions()->GetRole();
if (temp_cmd_view.GetCode() == Code::PAIRING_REQUEST && my_role == hci::Role::PERIPHERAL) {
// TODO: if (pending_le_pairing_) { do not start another }
LOG_INFO("start of security request handling!");
stored_chan->channel_->Acquire();
PairingRequestView pairing_request = PairingRequestView::Create(temp_cmd_view);
auto& enqueue_buffer = stored_chan->enqueue_buffer_;
std::optional<InitialInformations::out_of_band_data> remote_oob_data = std::nullopt;
if (remote_oob_data_address_.has_value() && remote_oob_data_address_.value() == channel->GetDevice())
remote_oob_data = InitialInformations::out_of_band_data{.le_sc_c = remote_oob_data_le_sc_c_.value(),
.le_sc_r = remote_oob_data_le_sc_r_.value()};
// TODO: this doesn't have to be a unique ptr, if there is a way to properly std::move it into place where it's
// stored
pending_le_pairing_.connection_handle_ = channel->GetLinkOptions()->GetHandle();
InitialInformations initial_informations{
.my_role = my_role,
.my_connection_address = channel->GetLinkOptions()->GetLocalAddress(),
.my_identity_address = local_identity_address_,
.my_identity_resolving_key = local_identity_resolving_key_,
/*TODO: properly obtain capabilities from device-specific storage*/
.myPairingCapabilities = {.io_capability = local_le_io_capability_,
.oob_data_flag = local_le_oob_data_present_,
.auth_req = local_le_auth_req_,
.maximum_encryption_key_size = local_maximum_encryption_key_size_,
.initiator_key_distribution = 0x07,
.responder_key_distribution = 0x07},
.remotely_initiated = true,
.connection_handle = channel->GetLinkOptions()->GetHandle(),
.remote_connection_address = channel->GetDevice(),
.remote_name = "TODO: grab proper device name in sec mgr",
/* contains pairing request, if the pairing was remotely initiated */
.pairing_request = pairing_request,
.remote_oob_data = remote_oob_data,
.my_oob_data = local_le_oob_data_,
/* Used by Pairing Handler to present user with requests*/
.user_interface = user_interface_,
.user_interface_handler = user_interface_handler_,
/* HCI interface to use */
.le_security_interface = hci_security_interface_le_,
.proper_l2cap_interface = enqueue_buffer.get(),
.l2cap_handler = security_handler_,
/* Callback to execute once the Pairing process is finished */
// TODO: make it an common::OnceCallback ?
.OnPairingFinished = std::bind(&SecurityManagerImpl::OnPairingFinished, this, std::placeholders::_1),
};
pending_le_pairing_.address_ = device;
pending_le_pairing_.handler_ = std::make_unique<PairingHandlerLe>(PairingHandlerLe::PHASE1, initial_informations);
}
}
void SecurityManagerImpl::OnConnectionOpenLe(std::unique_ptr<l2cap::le::FixedChannel> channel_param) {
auto enqueue_buffer_temp =
std::make_unique<os::EnqueueBuffer<packet::BasePacketBuilder>>(channel_param->GetQueueUpEnd());
all_channels_.push_back({std::move(channel_param), std::move(enqueue_buffer_temp)});
auto& stored_channel = all_channels_.back();
auto& channel = stored_channel.channel_;
channel->RegisterOnCloseCallback(
security_handler_,
common::BindOnce(&SecurityManagerImpl::OnConnectionClosedLe, common::Unretained(this), channel->GetDevice()));
channel->GetQueueUpEnd()->RegisterDequeue(
security_handler_,
common::Bind(&SecurityManagerImpl::OnSmpCommandLe, common::Unretained(this), channel->GetDevice()));
if (pending_le_pairing_.address_ != channel->GetDevice()) {
return;
}
ConnectionIsReadyStartPairing(&stored_channel);
}
void SecurityManagerImpl::ConnectionIsReadyStartPairing(LeFixedChannelEntry* stored_channel) {
auto& channel = stored_channel->channel_;
auto& enqueue_buffer = stored_channel->enqueue_buffer_;
stored_channel->channel_->Acquire();
std::optional<InitialInformations::out_of_band_data> remote_oob_data = std::nullopt;
if (remote_oob_data_address_.has_value() && remote_oob_data_address_.value() == channel->GetDevice())
remote_oob_data = InitialInformations::out_of_band_data{.le_sc_c = remote_oob_data_le_sc_c_.value(),
.le_sc_r = remote_oob_data_le_sc_r_.value()};
// TODO: this doesn't have to be a unique ptr, if there is a way to properly std::move it into place where it's stored
pending_le_pairing_.connection_handle_ = channel->GetLinkOptions()->GetHandle();
InitialInformations initial_informations{
.my_role = channel->GetLinkOptions()->GetRole(),
.my_connection_address = channel->GetLinkOptions()->GetLocalAddress(),
.my_identity_address = local_identity_address_,
.my_identity_resolving_key = local_identity_resolving_key_,
/*TODO: properly obtain capabilities from device-specific storage*/
.myPairingCapabilities = {.io_capability = local_le_io_capability_,
.oob_data_flag = local_le_oob_data_present_,
.auth_req = local_le_auth_req_,
.maximum_encryption_key_size = local_maximum_encryption_key_size_,
.initiator_key_distribution = 0x07,
.responder_key_distribution = 0x07},
.remotely_initiated = false,
.connection_handle = channel->GetLinkOptions()->GetHandle(),
.remote_connection_address = channel->GetDevice(),
.remote_name = "TODO: grab proper device name in sec mgr",
/* contains pairing request, if the pairing was remotely initiated */
.pairing_request = std::nullopt, // TODO: handle remotely initiated pairing in SecurityManager properly
.remote_oob_data = remote_oob_data,
.my_oob_data = local_le_oob_data_,
/* Used by Pairing Handler to present user with requests*/
.user_interface = user_interface_,
.user_interface_handler = user_interface_handler_,
/* HCI interface to use */
.le_security_interface = hci_security_interface_le_,
.proper_l2cap_interface = enqueue_buffer.get(),
.l2cap_handler = security_handler_,
/* Callback to execute once the Pairing process is finished */
// TODO: make it an common::OnceCallback ?
.OnPairingFinished = std::bind(&SecurityManagerImpl::OnPairingFinished, this, std::placeholders::_1),
};
pending_le_pairing_.handler_ = std::make_unique<PairingHandlerLe>(PairingHandlerLe::PHASE1, initial_informations);
}
void SecurityManagerImpl::OnConnectionClosedLe(hci::AddressWithType address, hci::ErrorCode error_code) {
if (pending_le_pairing_.address_ != address) {
LeFixedChannelEntry* stored_chan = FindStoredLeChannel(address);
if (!stored_chan) {
LOG_ALWAYS_FATAL("Received connection closed for unknown channel");
return;
}
stored_chan->channel_->GetQueueUpEnd()->UnregisterDequeue();
stored_chan->enqueue_buffer_.reset();
EraseStoredLeChannel(address);
return;
}
pending_le_pairing_.handler_->SendExitSignal();
NotifyDeviceBondFailed(address, PairingFailure("Connection closed"));
}
void SecurityManagerImpl::OnConnectionFailureLe(bluetooth::l2cap::le::FixedChannelManager::ConnectionResult result) {
if (result.connection_result_code ==
bluetooth::l2cap::le::FixedChannelManager::ConnectionResultCode::FAIL_ALL_SERVICES_HAVE_CHANNEL) {
// TODO: already connected
}
// This callback is invoked only for devices we attempted to connect to.
NotifyDeviceBondFailed(pending_le_pairing_.address_, PairingFailure("Connection establishment failed"));
}
SecurityManagerImpl::SecurityManagerImpl(
os::Handler* security_handler,
l2cap::le::L2capLeModule* l2cap_le_module,
channel::SecurityManagerChannel* security_manager_channel,
hci::HciLayer* hci_layer,
hci::AclManager* acl_manager,
hci::Controller* controller,
storage::StorageModule* storage_module,
neighbor::NameDbModule* name_db_module)
: security_handler_(security_handler),
l2cap_le_module_(l2cap_le_module),
l2cap_manager_le_(l2cap_le_module_->GetFixedChannelManager()),
hci_security_interface_le_(
hci_layer->GetLeSecurityInterface(security_handler_->BindOn(this, &SecurityManagerImpl::OnHciLeEvent))),
security_manager_channel_(security_manager_channel),
acl_manager_(acl_manager),
controller_(controller),
storage_module_(storage_module),
security_record_storage_(storage_module, security_handler),
security_database_(security_record_storage_),
name_db_module_(name_db_module) {
Init();
l2cap_manager_le_->RegisterService(
bluetooth::l2cap::kSmpCid,
common::BindOnce(&SecurityManagerImpl::OnL2capRegistrationCompleteLe, common::Unretained(this)),
common::Bind(&SecurityManagerImpl::OnConnectionOpenLe, common::Unretained(this)), security_handler_);
}
void SecurityManagerImpl::OnPairingFinished(security::PairingResultOrFailure pairing_result) {
LOG_INFO(" ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ Received pairing result");
LeFixedChannelEntry* stored_chan = FindStoredLeChannel(pending_le_pairing_.address_);
if (stored_chan) {
stored_chan->channel_->Release();
}
if (std::holds_alternative<PairingFailure>(pairing_result)) {
PairingFailure failure = std::get<PairingFailure>(pairing_result);
LOG_INFO(" ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ failure message: %s",
failure.message.c_str());
NotifyDeviceBondFailed(stored_chan->channel_->GetDevice(), failure);
return;
}
auto result = std::get<PairingResult>(pairing_result);
LOG_INFO("Pairing with %s was successful", result.connection_address.ToString().c_str());
// TODO: ensure that the security level is not weaker than what we already have.
auto record = this->security_database_.FindOrCreate(result.connection_address);
record->identity_address_ = result.distributed_keys.remote_identity_address;
record->remote_ltk = result.distributed_keys.remote_ltk;
record->key_size = result.key_size;
record->security_level = result.security_level;
record->remote_ediv = result.distributed_keys.remote_ediv;
record->remote_rand = result.distributed_keys.remote_rand;
record->remote_irk = result.distributed_keys.remote_irk;
record->remote_signature_key = result.distributed_keys.remote_signature_key;
if (result.distributed_keys.remote_link_key)
record->SetLinkKey(*result.distributed_keys.remote_link_key, hci::KeyType::AUTHENTICATED_P256);
security_database_.SaveRecordsToStorage();
NotifyDeviceBonded(result.connection_address);
// We also notify bond complete using identity address. That's what old stack used to do.
if (result.distributed_keys.remote_identity_address)
NotifyDeviceBonded(*result.distributed_keys.remote_identity_address);
security_handler_->CallOn(this, &SecurityManagerImpl::WipeLePairingHandler);
}
void SecurityManagerImpl::WipeLePairingHandler() {
pending_le_pairing_.handler_.reset();
pending_le_pairing_.connection_handle_ = 0;
pending_le_pairing_.address_ = hci::AddressWithType();
}
// Facade Configuration API functions
void SecurityManagerImpl::SetDisconnectCallback(FacadeDisconnectCallback callback) {
this->facade_disconnect_callback_ = std::make_optional<FacadeDisconnectCallback>(callback);
}
void SecurityManagerImpl::SetIoCapability(hci::IoCapability io_capability) {
this->local_io_capability_ = io_capability;
}
void SecurityManagerImpl::SetLeIoCapability(security::IoCapability io_capability) {
this->local_le_io_capability_ = io_capability;
}
void SecurityManagerImpl::SetLeAuthRequirements(uint8_t auth_req) {
this->local_le_auth_req_ = auth_req;
}
void SecurityManagerImpl::SetLeMaximumEncryptionKeySize(uint8_t maximum_encryption_key_size) {
this->local_maximum_encryption_key_size_ = maximum_encryption_key_size;
}
void SecurityManagerImpl::SetLeOobDataPresent(OobDataFlag data_present) {
this->local_le_oob_data_present_ = data_present;
}
void SecurityManagerImpl::GetOutOfBandData(channel::SecurityCommandStatusCallback callback) {
this->security_manager_channel_->SendCommand(
hci::ReadLocalOobDataBuilder::Create(), std::forward<channel::SecurityCommandStatusCallback>(callback));
}
void SecurityManagerImpl::GetLeOutOfBandData(
std::array<uint8_t, 16>* confirmation_value, std::array<uint8_t, 16>* random_value) {
local_le_oob_data_ = std::make_optional<MyOobData>(PairingHandlerLe::GenerateOobData());
*confirmation_value = local_le_oob_data_.value().c;
*random_value = local_le_oob_data_.value().r;
}
void SecurityManagerImpl::SetOutOfBandData(
hci::AddressWithType remote_address,
std::array<uint8_t, 16> confirmation_value,
std::array<uint8_t, 16> random_value) {
remote_oob_data_address_ = remote_address;
remote_oob_data_le_sc_c_ = confirmation_value;
remote_oob_data_le_sc_r_ = random_value;
}
void SecurityManagerImpl::SetAuthenticationRequirements(hci::AuthenticationRequirements authentication_requirements) {
this->local_authentication_requirements_ = authentication_requirements;
}
void SecurityManagerImpl::InternalEnforceSecurityPolicy(
hci::AddressWithType remote,
l2cap::classic::SecurityPolicy policy,
l2cap::classic::SecurityEnforcementInterface::ResultCallback result_callback) {
if (IsSecurityRequirementSatisfied(remote, policy)) {
// Notify client immediately if already satisfied
std::move(result_callback).Invoke(true);
return;
}
// At this point we don't meet the security requirements; must pair
auto record = this->security_database_.FindOrCreate(remote);
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:
// Force MITM requirement locally
authentication_requirements = hci::AuthenticationRequirements::GENERAL_BONDING_MITM_PROTECTION;
break;
case l2cap::classic::SecurityPolicy::ENCRYPTED_TRANSPORT:
authentication_requirements = hci::AuthenticationRequirements::GENERAL_BONDING;
break;
default:
// I could hear the voice of Myles, "This should be an ASSERT!"
ASSERT_LOG(false, "Unreachable code path");
return;
}
LOG_WARN("Dispatch #3");
DispatchPairingHandler(
record,
true,
this->local_io_capability_,
std::as_const(authentication_requirements),
pairing::OobData(),
pairing::OobData());
}
void SecurityManagerImpl::UpdateLinkSecurityCondition(hci::AddressWithType remote) {
auto entry = enforce_security_policy_callback_map_.find(remote);
if (entry == enforce_security_policy_callback_map_.end()) {
LOG_ERROR("No L2CAP security policy callback pending for %s", remote.ToString().c_str());
return;
}
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();
default:
return true;
}
}
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,
l2cap::le::SecurityEnforcementInterface::ResultCallback result_callback) {
bool result = false;
// TODO(jpawlowski): Implement for LE
switch (policy) {
case l2cap::le::SecurityPolicy::BEST:
break;
case l2cap::le::SecurityPolicy::AUTHENTICATED_ENCRYPTED_TRANSPORT:
break;
case l2cap::le::SecurityPolicy::ENCRYPTED_TRANSPORT:
break;
case l2cap::le::SecurityPolicy::NO_SECURITY_WHATSOEVER_PLAINTEXT_TRANSPORT_OK:
result = true;
break;
case l2cap::le::SecurityPolicy::_NOT_FOR_YOU__AUTHENTICATED_PAIRING_WITH_128_BIT_KEY:
break;
case l2cap::le::SecurityPolicy::_NOT_FOR_YOU__AUTHORIZATION:
break;
}
result_callback.Invoke(result);
}
} // namespace internal
} // namespace security
} // namespace bluetooth