417 lines
18 KiB
C++
417 lines
18 KiB
C++
/*
|
|
*
|
|
* 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 "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(record::SecurityRecord& record, bool locally_initiated,
|
|
hci::AuthenticationRequirements authentication_requirements) {
|
|
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: {
|
|
std::shared_ptr<record::SecurityRecord> record_copy =
|
|
std::make_shared<record::SecurityRecord>(record.GetPseudoAddress());
|
|
pairing_handler = std::make_shared<security::pairing::ClassicPairingHandler>(
|
|
l2cap_classic_module_->GetFixedChannelManager(), security_manager_channel_, record_copy, security_handler_,
|
|
std::move(callback), user_interface_, user_interface_handler_, "TODO: grab device name properly");
|
|
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, pairing::kDefaultIoCapability, pairing::kDefaultOobDataPresent,
|
|
authentication_requirements);
|
|
}
|
|
|
|
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));
|
|
// TODO(optedoblivion): Populate security record memory map from disk
|
|
}
|
|
|
|
void SecurityManagerImpl::CreateBond(hci::AddressWithType device) {
|
|
record::SecurityRecord& record = security_database_.FindOrCreate(device);
|
|
if (record.IsBonded()) {
|
|
NotifyDeviceBonded(device);
|
|
} else {
|
|
// Dispatch pairing handler, if we are calling create we are the initiator
|
|
DispatchPairingHandler(record, true, pairing::kDefaultAuthenticationRequirements);
|
|
}
|
|
}
|
|
|
|
void SecurityManagerImpl::CreateBondLe(hci::AddressWithType address) {
|
|
record::SecurityRecord& record = security_database_.FindOrCreate(address);
|
|
if (record.IsBonded()) {
|
|
NotifyDeviceBondFailed(address, PairingFailure("Already bonded"));
|
|
return;
|
|
}
|
|
|
|
pending_le_pairing_.address_ = address;
|
|
|
|
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();
|
|
}
|
|
}
|
|
|
|
void SecurityManagerImpl::RemoveBond(hci::AddressWithType device) {
|
|
CancelBond(device);
|
|
security_database_.Remove(device);
|
|
// Signal disconnect
|
|
// Remove security record
|
|
// Signal Remove from database
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
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, PairingResultOrFailure 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));
|
|
}
|
|
}
|
|
|
|
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();
|
|
auto event = hci::EventPacketView::Create(std::move(packet));
|
|
ASSERT_LOG(event.IsValid(), "Received invalid packet");
|
|
|
|
const hci::EventCode code = event.GetEventCode();
|
|
if (code != hci::EventCode::LINK_KEY_REQUEST) {
|
|
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 record =
|
|
security_database_.FindOrCreate(hci::AddressWithType{bd_addr, hci::AddressType::PUBLIC_DEVICE_ADDRESS});
|
|
auto authentication_requirements = hci::AuthenticationRequirements::NO_BONDING;
|
|
DispatchPairingHandler(record, true, authentication_requirements);
|
|
entry = pairing_handler_map_.find(bd_addr);
|
|
}
|
|
entry->second->OnReceive(packet);
|
|
}
|
|
|
|
void SecurityManagerImpl::OnHciEventReceived(hci::EventPacketView packet) {
|
|
auto event = hci::EventPacketView::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 enc_chg_packet = EncryptionChangeView::Create(event);
|
|
if (!enc_chg_packet.IsValid()) {
|
|
LOG_ERROR("Invalid EncryptionChange packet received");
|
|
return;
|
|
}
|
|
if (enc_chg_packet.GetConnectionHandle() == pending_le_pairing_.connection_handle_) {
|
|
pending_le_pairing_.handler_->OnHciEvent(event);
|
|
return;
|
|
}
|
|
break;
|
|
}
|
|
|
|
default:
|
|
ASSERT_LOG(false, "Cannot handle received packet: %s", hci::EventCodeText(code).c_str());
|
|
break;
|
|
}
|
|
}
|
|
|
|
void SecurityManagerImpl::OnHciLeEvent(hci::LeMetaEventView event) {
|
|
// hci::SubeventCode::LONG_TERM_KEY_REQUEST,
|
|
// hci::SubeventCode::READ_LOCAL_P256_PUBLIC_KEY_COMPLETE,
|
|
// hci::SubeventCode::GENERATE_DHKEY_COMPLETE,
|
|
LOG_ERROR("Unhandled HCI LE security event");
|
|
}
|
|
|
|
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 {
|
|
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::OnPairingHandlerComplete(hci::Address address, PairingResultOrFailure status) {
|
|
auto entry = pairing_handler_map_.find(address);
|
|
if (entry != pairing_handler_map_.end()) {
|
|
pairing_handler_map_.erase(entry);
|
|
}
|
|
if (!std::holds_alternative<PairingFailure>(status)) {
|
|
NotifyDeviceBonded(hci::AddressWithType(address, hci::AddressType::PUBLIC_DEVICE_ADDRESS));
|
|
} else {
|
|
NotifyDeviceBondFailed(hci::AddressWithType(address, hci::AddressType::PUBLIC_DEVICE_ADDRESS), status);
|
|
}
|
|
}
|
|
|
|
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");
|
|
}
|
|
|
|
void SecurityManagerImpl::OnSmpCommandLe() {
|
|
auto packet = pending_le_pairing_.channel_->GetQueueUpEnd()->TryDequeue();
|
|
if (!packet) LOG_ERROR("Received dequeue, but no data ready...");
|
|
|
|
auto temp_cmd_view = CommandView::Create(*packet);
|
|
pending_le_pairing_.handler_->OnCommandView(temp_cmd_view);
|
|
}
|
|
|
|
void SecurityManagerImpl::OnConnectionOpenLe(std::unique_ptr<l2cap::le::FixedChannel> channel) {
|
|
if (pending_le_pairing_.address_ != channel->GetDevice()) {
|
|
return;
|
|
}
|
|
pending_le_pairing_.channel_ = std::move(channel);
|
|
pending_le_pairing_.channel_->RegisterOnCloseCallback(
|
|
security_handler_, common::BindOnce(&SecurityManagerImpl::OnConnectionClosedLe, common::Unretained(this),
|
|
pending_le_pairing_.channel_->GetDevice()));
|
|
// TODO: this enqueue buffer must be stored together with pairing_handler, and we must make sure it doesn't go out of
|
|
// scope while the pairing happens
|
|
pending_le_pairing_.enqueue_buffer_ =
|
|
std::make_unique<os::EnqueueBuffer<packet::BasePacketBuilder>>(pending_le_pairing_.channel_->GetQueueUpEnd());
|
|
pending_le_pairing_.channel_->GetQueueUpEnd()->RegisterDequeue(
|
|
security_handler_, common::Bind(&SecurityManagerImpl::OnSmpCommandLe, common::Unretained(this)));
|
|
|
|
// 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_ = pending_le_pairing_.channel_->GetAclConnection()->GetHandle();
|
|
InitialInformations initial_informations{
|
|
.my_role = pending_le_pairing_.channel_->GetAclConnection()->GetRole(),
|
|
.my_connection_address = {hci::Address{{0x00, 0x11, 0xFF, 0xFF, 0x33, 0x22}} /*TODO: obtain my address*/,
|
|
hci::AddressType::RANDOM_DEVICE_ADDRESS},
|
|
/*TODO: properly obtain capabilities from device-specific storage*/
|
|
.myPairingCapabilities = {.io_capability = IoCapability::KEYBOARD_DISPLAY,
|
|
.oob_data_flag = OobDataFlag::NOT_PRESENT,
|
|
.auth_req = AuthReqMaskBondingFlag | AuthReqMaskMitm | AuthReqMaskSc,
|
|
.maximum_encryption_key_size = 16,
|
|
.initiator_key_distribution = 0x07,
|
|
.responder_key_distribution = 0x07},
|
|
.remotely_initiated = false,
|
|
.connection_handle = pending_le_pairing_.channel_->GetAclConnection()->GetHandle(),
|
|
.remote_connection_address = pending_le_pairing_.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 = std::nullopt, // TODO:
|
|
.my_oob_data = std::nullopt, // TODO:
|
|
/* 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 = pending_le_pairing_.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) {
|
|
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,
|
|
l2cap::classic::L2capClassicModule* l2cap_classic_module,
|
|
channel::SecurityManagerChannel* security_manager_channel,
|
|
hci::HciLayer* hci_layer)
|
|
: security_handler_(security_handler), l2cap_le_module_(l2cap_le_module),
|
|
l2cap_classic_module_(l2cap_classic_module), l2cap_manager_le_(l2cap_le_module_->GetFixedChannelManager()),
|
|
hci_security_interface_le_(hci_layer->GetLeSecurityInterface(
|
|
common::Bind(&SecurityManagerImpl::OnHciLeEvent, common::Unretained(this)), security_handler)),
|
|
security_manager_channel_(security_manager_channel) {
|
|
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");
|
|
|
|
if (std::holds_alternative<PairingFailure>(pairing_result)) {
|
|
PairingFailure failure = std::get<PairingFailure>(pairing_result);
|
|
LOG_INFO(" ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ failure message: %s",
|
|
failure.message.c_str());
|
|
return;
|
|
}
|
|
|
|
LOG_INFO("Pairing with %s was successfull",
|
|
std::get<PairingResult>(pairing_result).connection_address.ToString().c_str());
|
|
}
|
|
|
|
} // namespace internal
|
|
} // namespace security
|
|
} // namespace bluetooth
|