Martin Brabham | 80854c2 | 2019-11-12 14:52:42 -0800 | [diff] [blame^] | 1 | /* |
| 2 | * |
| 3 | * Copyright 2019 The Android Open Source Project |
| 4 | * |
| 5 | * Licensed under the Apache License, Version 2.0 (the "License"); |
| 6 | * you may not use this file except in compliance with the License. |
| 7 | * You may obtain a copy of the License at: |
| 8 | * |
| 9 | * http://www.apache.org/licenses/LICENSE-2.0 |
| 10 | * |
| 11 | * Unless required by applicable law or agreed to in writing, software |
| 12 | * distributed under the License is distributed on an "AS IS" BASIS, |
| 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 14 | * See the License for the specific language governing permissions and |
| 15 | * limitations under the License. |
| 16 | * |
| 17 | */ |
| 18 | #include "security/pairing/classic_pairing_handler.h" |
| 19 | |
| 20 | namespace bluetooth { |
| 21 | namespace security { |
| 22 | namespace pairing { |
| 23 | |
| 24 | void ClassicPairingHandler::OnRegistrationComplete( |
| 25 | l2cap::classic::FixedChannelManager::RegistrationResult result, |
| 26 | std::unique_ptr<l2cap::classic::FixedChannelService> fixed_channel_service) { |
| 27 | fixed_channel_service_ = std::move(fixed_channel_service); |
| 28 | fixed_channel_manager_->ConnectServices( |
| 29 | GetRecord()->GetDevice().GetAddress(), |
| 30 | common::Bind(&ClassicPairingHandler::OnConnectionFail, common::Unretained(this)), security_handler_); |
| 31 | } |
| 32 | |
| 33 | void ClassicPairingHandler::OnUnregistered() { |
| 34 | std::move(complete_callback_).Run(GetRecord()->GetDevice().GetAddress()); |
| 35 | } |
| 36 | |
| 37 | void ClassicPairingHandler::OnConnectionOpen(std::unique_ptr<l2cap::classic::FixedChannel> fixed_channel) { |
| 38 | ASSERT(fixed_channel_ == nullptr); |
| 39 | fixed_channel_ = std::move(fixed_channel); |
| 40 | fixed_channel_->Acquire(); |
| 41 | fixed_channel_->RegisterOnCloseCallback( |
| 42 | security_handler_, common::BindOnce(&ClassicPairingHandler::OnConnectionClose, common::Unretained(this))); |
| 43 | } |
| 44 | |
| 45 | void ClassicPairingHandler::OnConnectionFail(l2cap::classic::FixedChannelManager::ConnectionResult result) { |
| 46 | Cancel(); |
| 47 | } |
| 48 | void ClassicPairingHandler::OnConnectionClose(hci::ErrorCode error_code) { |
| 49 | // Called when the connection gets closed |
| 50 | LOG_ERROR("Connection closed due to: %s", hci::ErrorCodeText(error_code).c_str()); |
| 51 | ASSERT(fixed_channel_ != nullptr); |
| 52 | Cancel(); |
| 53 | } |
| 54 | |
| 55 | void ClassicPairingHandler::Initiate(bool locally_initiated, hci::IoCapability io_capability, |
| 56 | hci::OobDataPresent oob_present, |
| 57 | hci::AuthenticationRequirements auth_requirements) { |
| 58 | locally_initiated_ = locally_initiated; |
| 59 | local_io_capability_ = io_capability; |
| 60 | local_oob_present_ = oob_present; |
| 61 | local_authentication_requirements_ = auth_requirements; |
| 62 | |
| 63 | // TODO(optedoblivion): Read OOB data |
| 64 | // if host and controller support secure connections used HCIREADLOCALOOBEXTENDEDDATA vs HCIREADLOCALOOBDATA |
| 65 | |
| 66 | fixed_channel_manager_->RegisterService( |
| 67 | l2cap::kClassicPairingTriggerCid, security_policy_, |
| 68 | common::Bind(&ClassicPairingHandler::OnRegistrationComplete, common::Unretained(this)), |
| 69 | common::Bind(&ClassicPairingHandler::OnConnectionOpen, common::Unretained(this)), security_handler_); |
| 70 | } |
| 71 | |
| 72 | void ClassicPairingHandler::Cancel() { |
| 73 | if (fixed_channel_ != nullptr) { |
| 74 | fixed_channel_->Release(); |
| 75 | } |
| 76 | if (fixed_channel_service_ != nullptr) { |
| 77 | fixed_channel_service_->Unregister(common::Bind(&ClassicPairingHandler::OnUnregistered, common::Unretained(this)), |
| 78 | security_handler_); |
| 79 | } |
| 80 | } |
| 81 | |
| 82 | void ClassicPairingHandler::OnReceive(hci::ChangeConnectionLinkKeyCompleteView packet) { |
| 83 | ASSERT(packet.IsValid()); |
| 84 | LOG_INFO("Received unsupported event: %s", hci::EventCodeText(packet.GetEventCode()).c_str()); |
| 85 | } |
| 86 | |
| 87 | void ClassicPairingHandler::OnReceive(hci::MasterLinkKeyCompleteView packet) { |
| 88 | ASSERT(packet.IsValid()); |
| 89 | LOG_INFO("Received unsupported event: %s", hci::EventCodeText(packet.GetEventCode()).c_str()); |
| 90 | } |
| 91 | |
| 92 | void ClassicPairingHandler::OnReceive(hci::PinCodeRequestView packet) { |
| 93 | ASSERT(packet.IsValid()); |
| 94 | LOG_INFO("Received: %s", hci::EventCodeText(packet.GetEventCode()).c_str()); |
| 95 | ASSERT_LOG(GetRecord()->GetDevice().GetAddress() == packet.GetBdAddr(), "Address mismatch"); |
| 96 | } |
| 97 | |
| 98 | void ClassicPairingHandler::OnReceive(hci::LinkKeyRequestView packet) { |
| 99 | ASSERT(packet.IsValid()); |
| 100 | // TODO(optedoblivion): Add collision detection here |
| 101 | LOG_INFO("Received: %s", hci::EventCodeText(packet.GetEventCode()).c_str()); |
| 102 | ASSERT_LOG(GetRecord()->GetDevice().GetAddress() == packet.GetBdAddr(), "Address mismatch"); |
| 103 | if (GetRecord()->IsBonded() || GetRecord()->IsPaired()) { |
| 104 | auto packet = |
| 105 | hci::LinkKeyRequestReplyBuilder::Create(GetRecord()->GetDevice().GetAddress(), GetRecord()->GetLinkKey()); |
| 106 | this->GetChannel()->SendCommand(std::move(packet)); |
| 107 | } else { |
| 108 | auto packet = hci::LinkKeyRequestNegativeReplyBuilder::Create(GetRecord()->GetDevice().GetAddress()); |
| 109 | this->GetChannel()->SendCommand(std::move(packet)); |
| 110 | } |
| 111 | } |
| 112 | |
| 113 | void ClassicPairingHandler::OnReceive(hci::LinkKeyNotificationView packet) { |
| 114 | ASSERT(packet.IsValid()); |
| 115 | LOG_INFO("Received: %s", hci::EventCodeText(packet.GetEventCode()).c_str()); |
| 116 | ASSERT_LOG(GetRecord()->GetDevice().GetAddress() == packet.GetBdAddr(), "Address mismatch"); |
| 117 | GetRecord()->SetLinkKey(packet.GetLinkKey(), packet.GetKeyType()); |
| 118 | } |
| 119 | |
| 120 | void ClassicPairingHandler::OnReceive(hci::IoCapabilityRequestView packet) { |
| 121 | ASSERT(packet.IsValid()); |
| 122 | LOG_INFO("Received: %s", hci::EventCodeText(packet.GetEventCode()).c_str()); |
| 123 | ASSERT_LOG(GetRecord()->GetDevice().GetAddress() == packet.GetBdAddr(), "Address mismatch"); |
| 124 | hci::IoCapability io_capability = local_io_capability_; |
| 125 | hci::OobDataPresent oob_present = hci::OobDataPresent::NOT_PRESENT; |
| 126 | hci::AuthenticationRequirements authentication_requirements = local_authentication_requirements_; |
| 127 | auto reply_packet = hci::IoCapabilityRequestReplyBuilder::Create(GetRecord()->GetDevice().GetAddress(), io_capability, |
| 128 | oob_present, authentication_requirements); |
| 129 | this->GetChannel()->SendCommand(std::move(reply_packet)); |
| 130 | } |
| 131 | |
| 132 | void ClassicPairingHandler::OnReceive(hci::IoCapabilityResponseView packet) { |
| 133 | ASSERT(packet.IsValid()); |
| 134 | LOG_INFO("Received: %s", hci::EventCodeText(packet.GetEventCode()).c_str()); |
| 135 | ASSERT_LOG(GetRecord()->GetDevice().GetAddress() == packet.GetBdAddr(), "Address mismatch"); |
| 136 | |
| 137 | // Using local variable until device database pointer is ready |
| 138 | remote_io_capability_ = packet.GetIoCapability(); |
| 139 | // TODO(optedoblivion): device->SetIoCapability(packet.GetIoCapability); |
| 140 | } |
| 141 | |
| 142 | void ClassicPairingHandler::OnReceive(hci::SimplePairingCompleteView packet) { |
| 143 | ASSERT(packet.IsValid()); |
| 144 | LOG_INFO("Received: %s", hci::EventCodeText(packet.GetEventCode()).c_str()); |
| 145 | ASSERT_LOG(GetRecord()->GetDevice().GetAddress() == packet.GetBdAddr(), "Address mismatch"); |
| 146 | Cancel(); |
| 147 | } |
| 148 | |
| 149 | void ClassicPairingHandler::OnReceive(hci::ReturnLinkKeysView packet) { |
| 150 | ASSERT(packet.IsValid()); |
| 151 | LOG_INFO("Received: %s", hci::EventCodeText(packet.GetEventCode()).c_str()); |
| 152 | } |
| 153 | |
| 154 | void ClassicPairingHandler::OnReceive(hci::EncryptionChangeView packet) { |
| 155 | ASSERT(packet.IsValid()); |
| 156 | LOG_INFO("Received: %s", hci::EventCodeText(packet.GetEventCode()).c_str()); |
| 157 | } |
| 158 | |
| 159 | void ClassicPairingHandler::OnReceive(hci::EncryptionKeyRefreshCompleteView packet) { |
| 160 | ASSERT(packet.IsValid()); |
| 161 | LOG_INFO("Received: %s", hci::EventCodeText(packet.GetEventCode()).c_str()); |
| 162 | } |
| 163 | |
| 164 | void ClassicPairingHandler::OnReceive(hci::RemoteOobDataRequestView packet) { |
| 165 | ASSERT(packet.IsValid()); |
| 166 | LOG_INFO("Received: %s", hci::EventCodeText(packet.GetEventCode()).c_str()); |
| 167 | ASSERT_LOG(GetRecord()->GetDevice().GetAddress() == packet.GetBdAddr(), "Address mismatch"); |
| 168 | } |
| 169 | |
| 170 | void ClassicPairingHandler::OnReceive(hci::UserPasskeyNotificationView packet) { |
| 171 | ASSERT(packet.IsValid()); |
| 172 | LOG_INFO("Received: %s", hci::EventCodeText(packet.GetEventCode()).c_str()); |
| 173 | ASSERT_LOG(GetRecord()->GetDevice().GetAddress() == packet.GetBdAddr(), "Address mismatch"); |
| 174 | } |
| 175 | |
| 176 | void ClassicPairingHandler::OnReceive(hci::KeypressNotificationView packet) { |
| 177 | ASSERT(packet.IsValid()); |
| 178 | LOG_INFO("Received: %s", hci::EventCodeText(packet.GetEventCode()).c_str()); |
| 179 | LOG_INFO("Notification Type: %s", hci::KeypressNotificationTypeText(packet.GetNotificationType()).c_str()); |
| 180 | switch (packet.GetNotificationType()) { |
| 181 | case hci::KeypressNotificationType::ENTRY_STARTED: |
| 182 | // Get ready to keep track of key input |
| 183 | break; |
| 184 | case hci::KeypressNotificationType::DIGIT_ENTERED: |
| 185 | // Append digit to key |
| 186 | break; |
| 187 | case hci::KeypressNotificationType::DIGIT_ERASED: |
| 188 | // erase last digit from key |
| 189 | break; |
| 190 | case hci::KeypressNotificationType::CLEARED: |
| 191 | // erase all digits from key |
| 192 | break; |
| 193 | case hci::KeypressNotificationType::ENTRY_COMPLETED: |
| 194 | // set full key to security record |
| 195 | break; |
| 196 | } |
| 197 | } |
| 198 | |
| 199 | /** |
| 200 | * Here we decide what type of pairing authentication method we will use |
| 201 | * |
| 202 | * The table is on pg 2133 of the Core v5.1 spec. |
| 203 | */ |
| 204 | void ClassicPairingHandler::OnReceive(hci::UserConfirmationRequestView packet) { |
| 205 | ASSERT(packet.IsValid()); |
| 206 | LOG_INFO("Received: %s", hci::EventCodeText(packet.GetEventCode()).c_str()); |
| 207 | ASSERT_LOG(GetRecord()->GetDevice().GetAddress() == packet.GetBdAddr(), "Address mismatch"); |
| 208 | // if locally_initialized, use default, otherwise us remote io caps |
| 209 | hci::IoCapability initiator_io_capability = (locally_initiated_) ? local_io_capability_ : remote_io_capability_; |
| 210 | hci::IoCapability responder_io_capability = (!locally_initiated_) ? local_io_capability_ : remote_io_capability_; |
| 211 | // TODO(optedoblivion): Check for TEMPORARY pairing case |
| 212 | switch (initiator_io_capability) { |
| 213 | case hci::IoCapability::DISPLAY_ONLY: |
| 214 | switch (responder_io_capability) { |
| 215 | case hci::IoCapability::DISPLAY_ONLY: |
| 216 | // NumericComparison, Both auto confirm |
| 217 | LOG_INFO("Numeric Comparison: A and B auto confirm"); |
| 218 | GetChannel()->SendCommand( |
| 219 | hci::UserConfirmationRequestReplyBuilder::Create(GetRecord()->GetDevice().GetAddress())); |
| 220 | // Unauthenticated |
| 221 | break; |
| 222 | case hci::IoCapability::DISPLAY_YES_NO: |
| 223 | // NumericComparison, Initiator auto confirm, Responder display |
| 224 | GetChannel()->SendCommand( |
| 225 | hci::UserConfirmationRequestReplyBuilder::Create(GetRecord()->GetDevice().GetAddress())); |
| 226 | LOG_INFO("Numeric Comparison: A auto confirm"); |
| 227 | // Unauthenticated |
| 228 | break; |
| 229 | case hci::IoCapability::KEYBOARD_ONLY: |
| 230 | // PassKey Entry, Initiator display, Responder input |
| 231 | // TODO(optedoblivion): Notify UI |
| 232 | LOG_INFO("Notify UI"); |
| 233 | // Authenticated |
| 234 | break; |
| 235 | case hci::IoCapability::NO_INPUT_NO_OUTPUT: |
| 236 | // NumericComparison, Both auto confirm |
| 237 | LOG_INFO("Numeric Comparison: A and B auto confirm"); |
| 238 | GetChannel()->SendCommand( |
| 239 | hci::UserConfirmationRequestReplyBuilder::Create(GetRecord()->GetDevice().GetAddress())); |
| 240 | // Unauthenticated |
| 241 | break; |
| 242 | } |
| 243 | break; |
| 244 | case hci::IoCapability::DISPLAY_YES_NO: |
| 245 | switch (responder_io_capability) { |
| 246 | case hci::IoCapability::DISPLAY_ONLY: |
| 247 | // NumericComparison, Initiator display, Responder auto confirm |
| 248 | // TODO(optedoblivion): Notify UI |
| 249 | LOG_INFO("Notify UI"); |
| 250 | // Unauthenticated |
| 251 | break; |
| 252 | case hci::IoCapability::DISPLAY_YES_NO: |
| 253 | // NumericComparison Both Display, Both confirm |
| 254 | // TODO(optedoblivion): Notify UI |
| 255 | LOG_INFO("Notify UI"); |
| 256 | // Authenticated |
| 257 | break; |
| 258 | case hci::IoCapability::KEYBOARD_ONLY: |
| 259 | // PassKey Entry, Initiator display, Responder input |
| 260 | // TODO(optedoblivion): Notify UI |
| 261 | LOG_INFO("Notify UI"); |
| 262 | // Authenticated |
| 263 | break; |
| 264 | case hci::IoCapability::NO_INPUT_NO_OUTPUT: |
| 265 | // NumericComparison, auto confirm Responder, Yes/No confirm Initiator. Don't show confirmation value |
| 266 | // TODO(optedoblivion): Notify UI |
| 267 | LOG_INFO("Notify UI"); |
| 268 | // Unauthenticated |
| 269 | break; |
| 270 | } |
| 271 | break; |
| 272 | case hci::IoCapability::KEYBOARD_ONLY: |
| 273 | switch (responder_io_capability) { |
| 274 | case hci::IoCapability::DISPLAY_ONLY: |
| 275 | // PassKey Entry, Responder display, Initiator input |
| 276 | // TODO(optedoblivion): Notify UI |
| 277 | LOG_INFO("Notify UI"); |
| 278 | // Authenticated |
| 279 | break; |
| 280 | case hci::IoCapability::DISPLAY_YES_NO: |
| 281 | // PassKey Entry, Responder display, Initiator input |
| 282 | // TODO(optedoblivion): Notify UI |
| 283 | LOG_INFO("Notify UI"); |
| 284 | // Authenticated |
| 285 | break; |
| 286 | case hci::IoCapability::KEYBOARD_ONLY: |
| 287 | // PassKey Entry, both input |
| 288 | // TODO(optedoblivion): Notify UI |
| 289 | LOG_INFO("Notify UI"); |
| 290 | // Authenticated |
| 291 | break; |
| 292 | case hci::IoCapability::NO_INPUT_NO_OUTPUT: |
| 293 | // NumericComparison, both auto confirm |
| 294 | LOG_INFO("Numeric Comparison: A and B auto confirm"); |
| 295 | GetChannel()->SendCommand( |
| 296 | hci::UserConfirmationRequestReplyBuilder::Create(GetRecord()->GetDevice().GetAddress())); |
| 297 | // Unauthenticated |
| 298 | break; |
| 299 | } |
| 300 | break; |
| 301 | case hci::IoCapability::NO_INPUT_NO_OUTPUT: |
| 302 | switch (responder_io_capability) { |
| 303 | case hci::IoCapability::DISPLAY_ONLY: |
| 304 | // NumericComparison, both auto confirm |
| 305 | LOG_INFO("Numeric Comparison: A and B auto confirm"); |
| 306 | GetChannel()->SendCommand( |
| 307 | hci::UserConfirmationRequestReplyBuilder::Create(GetRecord()->GetDevice().GetAddress())); |
| 308 | // Unauthenticated |
| 309 | break; |
| 310 | case hci::IoCapability::DISPLAY_YES_NO: |
| 311 | // NumericComparison, Initiator auto confirm, Responder Yes/No confirm, no show conf val |
| 312 | LOG_INFO("Numeric Comparison: A auto confirm"); |
| 313 | GetChannel()->SendCommand( |
| 314 | hci::UserConfirmationRequestReplyBuilder::Create(GetRecord()->GetDevice().GetAddress())); |
| 315 | // Unauthenticated |
| 316 | break; |
| 317 | case hci::IoCapability::KEYBOARD_ONLY: |
| 318 | // NumericComparison, both auto confirm |
| 319 | LOG_INFO("Numeric Comparison: A and B auto confirm"); |
| 320 | GetChannel()->SendCommand( |
| 321 | hci::UserConfirmationRequestReplyBuilder::Create(GetRecord()->GetDevice().GetAddress())); |
| 322 | // Unauthenticated |
| 323 | break; |
| 324 | case hci::IoCapability::NO_INPUT_NO_OUTPUT: |
| 325 | // NumericComparison, both auto confirm |
| 326 | LOG_INFO("Numeric Comparison: A and B auto confirm"); |
| 327 | GetChannel()->SendCommand( |
| 328 | hci::UserConfirmationRequestReplyBuilder::Create(GetRecord()->GetDevice().GetAddress())); |
| 329 | // Unauthenticated |
| 330 | break; |
| 331 | } |
| 332 | break; |
| 333 | } |
| 334 | } |
| 335 | |
| 336 | void ClassicPairingHandler::OnReceive(hci::UserPasskeyRequestView packet) { |
| 337 | ASSERT(packet.IsValid()); |
| 338 | ASSERT_LOG(GetRecord()->GetDevice().GetAddress() == packet.GetBdAddr(), "Address mismatch"); |
| 339 | } |
| 340 | |
| 341 | } // namespace pairing |
| 342 | } // namespace security |
| 343 | } // namespace bluetooth |