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 #include "common/bind.h"
21
22 namespace bluetooth {
23 namespace security {
24 namespace pairing {
25
NotifyUiDisplayYesNo(uint32_t numeric_value)26 void ClassicPairingHandler::NotifyUiDisplayYesNo(uint32_t numeric_value) {
27 ASSERT(user_interface_handler_ != nullptr);
28 ConfirmationData data(*GetRecord()->GetPseudoAddress(), device_name_, numeric_value);
29 data.SetRemoteIoCaps(remote_io_capability_);
30 data.SetRemoteAuthReqs(remote_authentication_requirements_);
31 data.SetRemoteOobDataPresent(remote_oob_present_);
32 user_interface_handler_->CallOn(user_interface_, &UI::DisplayConfirmValue, data);
33 }
34
NotifyUiDisplayYesNo()35 void ClassicPairingHandler::NotifyUiDisplayYesNo() {
36 ASSERT(user_interface_handler_ != nullptr);
37 ConfirmationData data(*GetRecord()->GetPseudoAddress(), device_name_);
38 data.SetRemoteIoCaps(remote_io_capability_);
39 data.SetRemoteAuthReqs(remote_authentication_requirements_);
40 data.SetRemoteOobDataPresent(remote_oob_present_);
41 user_interface_handler_->CallOn(user_interface_, &UI::DisplayYesNoDialog, data);
42 }
43
NotifyUiDisplayPasskey(uint32_t passkey)44 void ClassicPairingHandler::NotifyUiDisplayPasskey(uint32_t passkey) {
45 ASSERT(user_interface_handler_ != nullptr);
46 ConfirmationData data(*GetRecord()->GetPseudoAddress(), device_name_, passkey);
47 data.SetRemoteIoCaps(remote_io_capability_);
48 data.SetRemoteAuthReqs(remote_authentication_requirements_);
49 data.SetRemoteOobDataPresent(remote_oob_present_);
50 user_interface_handler_->CallOn(user_interface_, &UI::DisplayPasskey, data);
51 }
52
NotifyUiDisplayPasskeyInput()53 void ClassicPairingHandler::NotifyUiDisplayPasskeyInput() {
54 ASSERT(user_interface_handler_ != nullptr);
55 ConfirmationData data(*GetRecord()->GetPseudoAddress(), device_name_);
56 data.SetRemoteIoCaps(remote_io_capability_);
57 data.SetRemoteAuthReqs(remote_authentication_requirements_);
58 data.SetRemoteOobDataPresent(remote_oob_present_);
59 user_interface_handler_->CallOn(user_interface_, &UI::DisplayEnterPasskeyDialog, data);
60 }
61
NotifyUiDisplayPinCodeInput()62 void ClassicPairingHandler::NotifyUiDisplayPinCodeInput() {
63 ASSERT(user_interface_handler_ != nullptr);
64 ConfirmationData data(*GetRecord()->GetPseudoAddress(), device_name_);
65 data.SetRemoteIoCaps(remote_io_capability_);
66 data.SetRemoteAuthReqs(remote_authentication_requirements_);
67 data.SetRemoteOobDataPresent(remote_oob_present_);
68 user_interface_handler_->CallOn(user_interface_, &UI::DisplayEnterPinDialog, data);
69 }
70
NotifyUiDisplayCancel()71 void ClassicPairingHandler::NotifyUiDisplayCancel() {
72 ASSERT(user_interface_handler_ != nullptr);
73 user_interface_handler_->CallOn(user_interface_, &UI::Cancel, *GetRecord()->GetPseudoAddress());
74 }
75
OnPairingPromptAccepted(const bluetooth::hci::AddressWithType & address,bool confirmed)76 void ClassicPairingHandler::OnPairingPromptAccepted(const bluetooth::hci::AddressWithType& address, bool confirmed) {
77 // NOTE: This is not used by Classic, only by LE
78 LOG_ALWAYS_FATAL("This is not supported by Classic Pairing Handler, only LE");
79 }
80
OnConfirmYesNo(const bluetooth::hci::AddressWithType & address,bool confirmed)81 void ClassicPairingHandler::OnConfirmYesNo(const bluetooth::hci::AddressWithType& address, bool confirmed) {
82 if (confirmed) {
83 GetChannel()->SendCommand(
84 hci::UserConfirmationRequestReplyBuilder::Create(GetRecord()->GetPseudoAddress()->GetAddress()));
85 } else {
86 GetChannel()->SendCommand(
87 hci::UserConfirmationRequestNegativeReplyBuilder::Create(GetRecord()->GetPseudoAddress()->GetAddress()));
88 }
89 }
90
OnPasskeyEntry(const bluetooth::hci::AddressWithType & address,uint32_t passkey)91 void ClassicPairingHandler::OnPasskeyEntry(const bluetooth::hci::AddressWithType& address, uint32_t passkey) {
92 GetChannel()->SendCommand(hci::UserPasskeyRequestReplyBuilder::Create(address.GetAddress(), passkey));
93 }
94
OnPinEntry(const bluetooth::hci::AddressWithType & address,std::vector<uint8_t> pin)95 void ClassicPairingHandler::OnPinEntry(const bluetooth::hci::AddressWithType& address, std::vector<uint8_t> pin) {
96 std::array<uint8_t, 16> padded_pin;
97 for (size_t i = 0; i < 16 && i < pin.size(); i++) {
98 padded_pin[i] = pin[i];
99 }
100 LOG_INFO("%s", ADDRESS_TO_LOGGABLE_CSTR(address.GetAddress()));
101 GetChannel()->SendCommand(hci::PinCodeRequestReplyBuilder::Create(address.GetAddress(), pin.size(), padded_pin));
102 }
103
Initiate(bool locally_initiated,hci::IoCapability io_capability,hci::AuthenticationRequirements auth_requirements,OobData remote_p192_oob_data,OobData remote_p256_oob_data)104 void ClassicPairingHandler::Initiate(
105 bool locally_initiated,
106 hci::IoCapability io_capability,
107 hci::AuthenticationRequirements auth_requirements,
108 OobData remote_p192_oob_data,
109 OobData remote_p256_oob_data) {
110 LOG_INFO("Initiate");
111 locally_initiated_ = locally_initiated;
112 local_io_capability_ = io_capability;
113 local_authentication_requirements_ = auth_requirements;
114 remote_p192_oob_data_ = remote_p192_oob_data;
115 remote_p256_oob_data_ = remote_p256_oob_data;
116 bool has192 = remote_p192_oob_data.IsValid();
117 bool has256 = remote_p256_oob_data.IsValid();
118 bool has_both = has192 && has256;
119
120 if (has_both) {
121 remote_oob_present_ = hci::OobDataPresent::P_192_AND_256_PRESENT;
122 } else {
123 if (has192) {
124 remote_oob_present_ = hci::OobDataPresent::P_192_PRESENT;
125 } else if (has256) {
126 remote_oob_present_ = hci::OobDataPresent::P_256_PRESENT;
127 }
128 }
129
130 if (locally_initiated_) {
131 GetChannel()->Connect(GetRecord()->GetPseudoAddress()->GetAddress());
132 }
133 }
134
OnNameRequestComplete(hci::Address address,bool success)135 void ClassicPairingHandler::OnNameRequestComplete(hci::Address address, bool success) {
136 if (GetNameDbModule()->IsNameCached(address)) {
137 auto remote_name = GetNameDbModule()->ReadCachedRemoteName(address);
138 std::string tmp_name;
139 for (uint8_t i : remote_name) {
140 tmp_name += i;
141 }
142 device_name_ = tmp_name;
143 }
144 has_gotten_name_response_ = true;
145 // For PIN Pairing
146 if (is_legacy_pin_code_) {
147 NotifyUiDisplayPinCodeInput();
148 }
149 // For SSP/Numeric comparison flow
150 if (user_confirmation_request_) {
151 this->OnReceive(*user_confirmation_request_);
152 }
153 // For OOB Flow; we go to link key notification and must wait for name
154 if (link_key_notification_) {
155 this->OnReceive(*link_key_notification_);
156 }
157 }
158
Cancel()159 void ClassicPairingHandler::Cancel() {
160 if (is_cancelled_) return;
161 is_cancelled_ = true;
162 PairingResultOrFailure result = PairingResult();
163 if (last_status_ != hci::ErrorCode::SUCCESS) {
164 result = PairingFailure(hci::ErrorCodeText(last_status_));
165 }
166 std::move(complete_callback_).Run(GetRecord()->GetPseudoAddress()->GetAddress(), result);
167 }
168
OnReceive(hci::ChangeConnectionLinkKeyCompleteView packet)169 void ClassicPairingHandler::OnReceive(hci::ChangeConnectionLinkKeyCompleteView packet) {
170 ASSERT(packet.IsValid());
171 LOG_INFO("Received unsupported event: %s", hci::EventCodeText(packet.GetEventCode()).c_str());
172 }
173
OnReceive(hci::CentralLinkKeyCompleteView packet)174 void ClassicPairingHandler::OnReceive(hci::CentralLinkKeyCompleteView packet) {
175 ASSERT(packet.IsValid());
176 LOG_INFO("Received unsupported event: %s", hci::EventCodeText(packet.GetEventCode()).c_str());
177 }
178
OnReceive(hci::PinCodeRequestView packet)179 void ClassicPairingHandler::OnReceive(hci::PinCodeRequestView packet) {
180 ASSERT(packet.IsValid());
181 LOG_INFO("Received: %s", hci::EventCodeText(packet.GetEventCode()).c_str());
182 ASSERT_LOG(GetRecord()->GetPseudoAddress()->GetAddress() == packet.GetBdAddr(), "Address mismatch");
183 is_legacy_pin_code_ = true;
184 GetNameDbModule()->ReadRemoteNameRequest(
185 GetRecord()->GetPseudoAddress()->GetAddress(),
186 common::BindOnce(&ClassicPairingHandler::OnNameRequestComplete, common::Unretained(this)),
187 security_handler_);
188 }
189
OnReceive(hci::LinkKeyRequestView packet)190 void ClassicPairingHandler::OnReceive(hci::LinkKeyRequestView packet) {
191 ASSERT(packet.IsValid());
192 if (already_link_key_replied_) {
193 LOG_WARN("Pairing is already in progress...");
194 return;
195 }
196 already_link_key_replied_ = true;
197 LOG_INFO("Received: %s", hci::EventCodeText(packet.GetEventCode()).c_str());
198 ASSERT_LOG(GetRecord()->GetPseudoAddress()->GetAddress() == packet.GetBdAddr(), "Address mismatch");
199 if (GetRecord()->IsPaired()) {
200 LOG_INFO("Sending: LINK_KEY_REQUEST_REPLY");
201 this->GetChannel()->SendCommand(hci::LinkKeyRequestReplyBuilder::Create(
202 GetRecord()->GetPseudoAddress()->GetAddress(), GetRecord()->GetLinkKey()));
203 last_status_ = hci::ErrorCode::SUCCESS;
204 Cancel();
205 } else {
206 LOG_INFO("Sending: LINK_KEY_REQUEST_NEGATIVE_REPLY");
207 this->GetChannel()->SendCommand(
208 hci::LinkKeyRequestNegativeReplyBuilder::Create(GetRecord()->GetPseudoAddress()->GetAddress()));
209 }
210 }
211
OnReceive(hci::LinkKeyNotificationView packet)212 void ClassicPairingHandler::OnReceive(hci::LinkKeyNotificationView packet) {
213 ASSERT(packet.IsValid());
214 LOG_INFO("Received: %s", hci::EventCodeText(packet.GetEventCode()).c_str());
215 ASSERT_LOG(GetRecord()->GetPseudoAddress()->GetAddress() == packet.GetBdAddr(), "Address mismatch");
216 GetRecord()->SetLinkKey(packet.GetLinkKey(), packet.GetKeyType());
217 if (!has_gotten_name_response_) {
218 link_key_notification_ = std::make_optional<hci::LinkKeyNotificationView>(packet);
219 return;
220 }
221 if (is_legacy_pin_code_) {
222 last_status_ = hci::ErrorCode::SUCCESS;
223 }
224 Cancel();
225 }
226
OnReceive(hci::IoCapabilityRequestView packet)227 void ClassicPairingHandler::OnReceive(hci::IoCapabilityRequestView packet) {
228 ASSERT(packet.IsValid());
229 LOG_INFO("Received: %s", hci::EventCodeText(packet.GetEventCode()).c_str());
230 ASSERT_LOG(GetRecord()->GetPseudoAddress()->GetAddress() == packet.GetBdAddr(), "Address mismatch");
231 hci::IoCapability io_capability = local_io_capability_;
232 hci::OobDataPresent oob_present = remote_oob_present_;
233 hci::AuthenticationRequirements authentication_requirements = local_authentication_requirements_;
234 auto reply_packet = hci::IoCapabilityRequestReplyBuilder::Create(
235 GetRecord()->GetPseudoAddress()->GetAddress(), io_capability, oob_present, authentication_requirements);
236 this->GetChannel()->SendCommand(std::move(reply_packet));
237 GetNameDbModule()->ReadRemoteNameRequest(
238 GetRecord()->GetPseudoAddress()->GetAddress(),
239 common::BindOnce(&ClassicPairingHandler::OnNameRequestComplete, common::Unretained(this)),
240 security_handler_);
241 }
242
OnReceive(hci::IoCapabilityResponseView packet)243 void ClassicPairingHandler::OnReceive(hci::IoCapabilityResponseView packet) {
244 ASSERT(packet.IsValid());
245 LOG_INFO("Received: %s", hci::EventCodeText(packet.GetEventCode()).c_str());
246 ASSERT_LOG(GetRecord()->GetPseudoAddress()->GetAddress() == packet.GetBdAddr(), "Address mismatch");
247
248 remote_io_capability_ = packet.GetIoCapability();
249 remote_authentication_requirements_ = packet.GetAuthenticationRequirements();
250
251 switch (remote_authentication_requirements_) {
252 case hci::AuthenticationRequirements::NO_BONDING:
253 GetRecord()->SetIsEncryptionRequired(
254 local_authentication_requirements_ != hci::AuthenticationRequirements::NO_BONDING ||
255 local_authentication_requirements_ != hci::AuthenticationRequirements::NO_BONDING_MITM_PROTECTION);
256 GetRecord()->SetRequiresMitmProtection(
257 local_authentication_requirements_ == hci::AuthenticationRequirements::DEDICATED_BONDING_MITM_PROTECTION ||
258 local_authentication_requirements_ == hci::AuthenticationRequirements::GENERAL_BONDING_MITM_PROTECTION ||
259 local_authentication_requirements_ == hci::AuthenticationRequirements::NO_BONDING_MITM_PROTECTION);
260 // TODO(optedoblivion): check for HID device (CoD) and if HID don't make temporary
261 GetRecord()->SetIsTemporary(
262 local_authentication_requirements_ == hci::AuthenticationRequirements::NO_BONDING ||
263 local_authentication_requirements_ == hci::AuthenticationRequirements::NO_BONDING_MITM_PROTECTION);
264 break;
265 case hci::AuthenticationRequirements::NO_BONDING_MITM_PROTECTION:
266 GetRecord()->SetIsEncryptionRequired(
267 local_authentication_requirements_ != hci::AuthenticationRequirements::NO_BONDING ||
268 local_authentication_requirements_ != hci::AuthenticationRequirements::NO_BONDING_MITM_PROTECTION);
269 GetRecord()->SetRequiresMitmProtection(true);
270 GetRecord()->SetIsTemporary(
271 local_authentication_requirements_ == hci::AuthenticationRequirements::NO_BONDING ||
272 local_authentication_requirements_ == hci::AuthenticationRequirements::NO_BONDING_MITM_PROTECTION);
273 break;
274 case hci::AuthenticationRequirements::DEDICATED_BONDING:
275 GetRecord()->SetIsEncryptionRequired(true);
276 GetRecord()->SetRequiresMitmProtection(
277 local_authentication_requirements_ == hci::AuthenticationRequirements::DEDICATED_BONDING_MITM_PROTECTION ||
278 local_authentication_requirements_ == hci::AuthenticationRequirements::GENERAL_BONDING_MITM_PROTECTION ||
279 local_authentication_requirements_ == hci::AuthenticationRequirements::NO_BONDING_MITM_PROTECTION);
280 break;
281 case hci::AuthenticationRequirements::DEDICATED_BONDING_MITM_PROTECTION:
282 GetRecord()->SetIsEncryptionRequired(true);
283 GetRecord()->SetRequiresMitmProtection(true);
284 break;
285 case hci::AuthenticationRequirements::GENERAL_BONDING:
286 GetRecord()->SetIsEncryptionRequired(true);
287 GetRecord()->SetRequiresMitmProtection(
288 local_authentication_requirements_ == hci::AuthenticationRequirements::DEDICATED_BONDING_MITM_PROTECTION ||
289 local_authentication_requirements_ == hci::AuthenticationRequirements::GENERAL_BONDING_MITM_PROTECTION ||
290 local_authentication_requirements_ == hci::AuthenticationRequirements::NO_BONDING_MITM_PROTECTION);
291 break;
292 case hci::AuthenticationRequirements::GENERAL_BONDING_MITM_PROTECTION:
293 GetRecord()->SetIsEncryptionRequired(true);
294 GetRecord()->SetRequiresMitmProtection(true);
295 break;
296 default:
297 GetRecord()->SetIsEncryptionRequired(true);
298 GetRecord()->SetRequiresMitmProtection(true);
299 break;
300 }
301
302 has_gotten_io_cap_response_ = true;
303 if (user_confirmation_request_) {
304 this->OnReceive(*user_confirmation_request_);
305 }
306 }
307
OnReceive(hci::SimplePairingCompleteView packet)308 void ClassicPairingHandler::OnReceive(hci::SimplePairingCompleteView packet) {
309 ASSERT(packet.IsValid());
310 LOG_INFO("Received: %s", hci::EventCodeText(packet.GetEventCode()).c_str());
311 ASSERT_LOG(GetRecord()->GetPseudoAddress()->GetAddress() == packet.GetBdAddr(), "Address mismatch");
312 last_status_ = packet.GetStatus();
313 if (last_status_ != hci::ErrorCode::SUCCESS) {
314 LOG_INFO("Failed SimplePairingComplete: %s", hci::ErrorCodeText(last_status_).c_str());
315 // Cancel here since we won't get LinkKeyNotification
316 Cancel();
317 }
318 }
319
OnReceive(hci::ReturnLinkKeysView packet)320 void ClassicPairingHandler::OnReceive(hci::ReturnLinkKeysView packet) {
321 ASSERT(packet.IsValid());
322 LOG_INFO("Received: %s", hci::EventCodeText(packet.GetEventCode()).c_str());
323 }
324
OnReceive(hci::EncryptionChangeView packet)325 void ClassicPairingHandler::OnReceive(hci::EncryptionChangeView packet) {
326 ASSERT(packet.IsValid());
327 LOG_INFO("Received: %s", hci::EventCodeText(packet.GetEventCode()).c_str());
328 }
329
OnReceive(hci::EncryptionKeyRefreshCompleteView packet)330 void ClassicPairingHandler::OnReceive(hci::EncryptionKeyRefreshCompleteView packet) {
331 ASSERT(packet.IsValid());
332 LOG_INFO("Received: %s", hci::EventCodeText(packet.GetEventCode()).c_str());
333 }
334
OnReceive(hci::RemoteOobDataRequestView packet)335 void ClassicPairingHandler::OnReceive(hci::RemoteOobDataRequestView packet) {
336 ASSERT(packet.IsValid());
337 LOG_INFO("Received: %s", hci::EventCodeText(packet.GetEventCode()).c_str());
338 ASSERT_LOG(GetRecord()->GetPseudoAddress()->GetAddress() == packet.GetBdAddr(), "Address mismatch");
339
340 // Corev5.2 V2PF
341 switch (remote_oob_present_) {
342 case hci::OobDataPresent::NOT_PRESENT:
343 LOG_WARN("Missing remote OOB data");
344 GetChannel()->SendCommand(
345 hci::RemoteOobDataRequestNegativeReplyBuilder::Create(GetRecord()->GetPseudoAddress()->GetAddress()));
346 break;
347 case hci::OobDataPresent::P_192_PRESENT:
348 LOG_INFO("P192 Present");
349 // TODO(optedoblivion): Figure this out and remove
350 secure_connections_enabled_ = false;
351 if (secure_connections_enabled_) {
352 GetChannel()->SendCommand(hci::RemoteOobExtendedDataRequestReplyBuilder::Create(
353 GetRecord()->GetPseudoAddress()->GetAddress(),
354 this->remote_p192_oob_data_.GetC(),
355 this->remote_p192_oob_data_.GetR(),
356 this->remote_p256_oob_data_.GetC(),
357 this->remote_p256_oob_data_.GetR()));
358 } else {
359 GetChannel()->SendCommand(hci::RemoteOobDataRequestReplyBuilder::Create(
360 GetRecord()->GetPseudoAddress()->GetAddress(),
361 this->remote_p192_oob_data_.GetC(),
362 this->remote_p192_oob_data_.GetR()));
363 }
364 break;
365 case hci::OobDataPresent::P_256_PRESENT:
366 LOG_INFO("P256 Present");
367 GetChannel()->SendCommand(hci::RemoteOobExtendedDataRequestReplyBuilder::Create(
368 GetRecord()->GetPseudoAddress()->GetAddress(),
369 this->remote_p192_oob_data_.GetC(),
370 this->remote_p192_oob_data_.GetR(),
371 this->remote_p256_oob_data_.GetC(),
372 this->remote_p256_oob_data_.GetR()));
373 break;
374 case hci::OobDataPresent::P_192_AND_256_PRESENT:
375 LOG_INFO("P192 and P256 Present");
376 GetChannel()->SendCommand(hci::RemoteOobExtendedDataRequestReplyBuilder::Create(
377 GetRecord()->GetPseudoAddress()->GetAddress(),
378 this->remote_p192_oob_data_.GetC(),
379 this->remote_p192_oob_data_.GetR(),
380 this->remote_p256_oob_data_.GetC(),
381 this->remote_p256_oob_data_.GetR()));
382 break;
383 }
384 }
385
OnReceive(hci::UserPasskeyNotificationView packet)386 void ClassicPairingHandler::OnReceive(hci::UserPasskeyNotificationView packet) {
387 ASSERT(packet.IsValid());
388 LOG_INFO("Received: %s", hci::EventCodeText(packet.GetEventCode()).c_str());
389 ASSERT_LOG(GetRecord()->GetPseudoAddress()->GetAddress() == packet.GetBdAddr(), "Address mismatch");
390 NotifyUiDisplayPasskey(packet.GetPasskey());
391 }
392
OnReceive(hci::KeypressNotificationView packet)393 void ClassicPairingHandler::OnReceive(hci::KeypressNotificationView packet) {
394 ASSERT(packet.IsValid());
395 LOG_INFO("Received: %s", hci::EventCodeText(packet.GetEventCode()).c_str());
396 LOG_INFO("Notification Type: %s", hci::KeypressNotificationTypeText(packet.GetNotificationType()).c_str());
397 switch (packet.GetNotificationType()) {
398 case hci::KeypressNotificationType::ENTRY_STARTED:
399 // Tell the UI to highlight the first digit
400 break;
401 case hci::KeypressNotificationType::DIGIT_ENTERED:
402 // Tell the UI to move one digit to the right
403 break;
404 case hci::KeypressNotificationType::DIGIT_ERASED:
405 // Tell the UI to move back one digit
406 break;
407 case hci::KeypressNotificationType::CLEARED:
408 // Tell the UI to highlight the first digit again
409 break;
410 case hci::KeypressNotificationType::ENTRY_COMPLETED:
411 // Tell the UI to hide the dialog
412 break;
413 }
414 }
415
416 /**
417 * Here we decide what type of pairing authentication method we will use
418 *
419 * The table is on pg 2133 of the Core v5.1 spec.
420 */
421
OnReceive(hci::UserConfirmationRequestView packet)422 void ClassicPairingHandler::OnReceive(hci::UserConfirmationRequestView packet) {
423 // Ensure we have io cap response otherwise checks will be wrong if it comes late
424 // Ensure we have the name response otherwise we cannot show a name for the device to the user
425 if (!has_gotten_io_cap_response_ || !has_gotten_name_response_) {
426 user_confirmation_request_ = std::make_optional<hci::UserConfirmationRequestView>(packet);
427 return;
428 }
429 ASSERT(packet.IsValid());
430 LOG_INFO("Received: %s", hci::EventCodeText(packet.GetEventCode()).c_str());
431 ASSERT_LOG(GetRecord()->GetPseudoAddress()->GetAddress() == packet.GetBdAddr(), "Address mismatch");
432 // if locally_initialized, use default, otherwise us remote io caps
433 hci::IoCapability initiator_io_capability = (locally_initiated_) ? local_io_capability_ : remote_io_capability_;
434 hci::IoCapability responder_io_capability = (!locally_initiated_) ? local_io_capability_ : remote_io_capability_;
435 switch (initiator_io_capability) {
436 case hci::IoCapability::DISPLAY_ONLY:
437 switch (responder_io_capability) {
438 case hci::IoCapability::DISPLAY_ONLY:
439 // NumericComparison, Both auto confirm
440 LOG_INFO("Numeric Comparison: A and B auto confirm");
441 if (!GetRecord()->RequiresMitmProtection()) {
442 GetChannel()->SendCommand(
443 hci::UserConfirmationRequestReplyBuilder::Create(GetRecord()->GetPseudoAddress()->GetAddress()));
444 // NOTE(optedoblivion) BTA needs a callback for when auto accepting JustWorks
445 // If we auto accept from the ClassicPairingHandler in GD then we won't
446 // get a callback to this shim function.
447 // We will have to call it anyway until we eliminate the need
448 // TODO(optedoblivion): REMOVE WHEN SHIM LEAVES
449 NotifyUiDisplayYesNo();
450 } else {
451 GetChannel()->SendCommand(hci::UserConfirmationRequestNegativeReplyBuilder::Create(
452 GetRecord()->GetPseudoAddress()->GetAddress()));
453 }
454 // Unauthenticated
455 GetRecord()->SetAuthenticated(false);
456 break;
457 case hci::IoCapability::DISPLAY_YES_NO:
458 // NumericComparison, Initiator auto confirm, Responder display
459 if (!GetRecord()->RequiresMitmProtection()) {
460 GetChannel()->SendCommand(
461 hci::UserConfirmationRequestReplyBuilder::Create(GetRecord()->GetPseudoAddress()->GetAddress()));
462 // TODO(optedoblivion): REMOVE WHEN SHIM LEAVES
463 NotifyUiDisplayYesNo();
464 } else {
465 GetChannel()->SendCommand(hci::UserConfirmationRequestNegativeReplyBuilder::Create(
466 GetRecord()->GetPseudoAddress()->GetAddress()));
467 }
468 LOG_INFO("Numeric Comparison: A auto confirm");
469 // Unauthenticated
470 GetRecord()->SetAuthenticated(true);
471 break;
472 case hci::IoCapability::KEYBOARD_ONLY:
473 // PassKey Entry, Initiator display, Responder input
474 NotifyUiDisplayPasskey(packet.GetNumericValue());
475 LOG_INFO("Passkey Entry: A display, B input");
476 // Authenticated
477 GetRecord()->SetAuthenticated(true);
478 break;
479 case hci::IoCapability::NO_INPUT_NO_OUTPUT:
480 // NumericComparison, Both auto confirm
481 LOG_INFO("Numeric Comparison: A and B auto confirm");
482 if (!GetRecord()->RequiresMitmProtection()) {
483 GetChannel()->SendCommand(
484 hci::UserConfirmationRequestReplyBuilder::Create(GetRecord()->GetPseudoAddress()->GetAddress()));
485 // TODO(optedoblivion): REMOVE WHEN SHIM LEAVES
486 NotifyUiDisplayYesNo();
487 } else {
488 GetChannel()->SendCommand(hci::UserConfirmationRequestNegativeReplyBuilder::Create(
489 GetRecord()->GetPseudoAddress()->GetAddress()));
490 }
491 // Unauthenticated
492 GetRecord()->SetAuthenticated(true);
493 break;
494 }
495 break;
496 case hci::IoCapability::DISPLAY_YES_NO:
497 switch (responder_io_capability) {
498 case hci::IoCapability::DISPLAY_ONLY:
499 // NumericComparison, Initiator display, Responder auto confirm
500 LOG_INFO("Numeric Comparison: A DisplayYesNo, B auto confirm");
501 NotifyUiDisplayYesNo(packet.GetNumericValue());
502 // Unauthenticated
503 GetRecord()->SetAuthenticated(true);
504 break;
505 case hci::IoCapability::DISPLAY_YES_NO:
506 // NumericComparison Both Display, Both confirm
507 LOG_INFO("Numeric Comparison: A and B DisplayYesNo");
508 NotifyUiDisplayYesNo(packet.GetNumericValue());
509 // Authenticated
510 GetRecord()->SetAuthenticated(true);
511 break;
512 case hci::IoCapability::KEYBOARD_ONLY:
513 // PassKey Entry, Initiator display, Responder input
514 NotifyUiDisplayPasskey(packet.GetNumericValue());
515 LOG_INFO("Passkey Entry: A display, B input");
516 // Authenticated
517 GetRecord()->SetAuthenticated(true);
518 break;
519 case hci::IoCapability::NO_INPUT_NO_OUTPUT:
520 // NumericComparison, auto confirm Responder, Yes/No confirm Initiator. Don't show confirmation value
521 LOG_INFO("Numeric Comparison: A DisplayYesNo, B auto confirm, no show value");
522 NotifyUiDisplayYesNo();
523 // Unauthenticated
524 GetRecord()->SetAuthenticated(true);
525 break;
526 }
527 break;
528 case hci::IoCapability::KEYBOARD_ONLY:
529 switch (responder_io_capability) {
530 case hci::IoCapability::DISPLAY_ONLY:
531 // PassKey Entry, Responder display, Initiator input
532 NotifyUiDisplayPasskeyInput();
533 LOG_INFO("Passkey Entry: A input, B display");
534 // Authenticated
535 GetRecord()->SetAuthenticated(true);
536 break;
537 case hci::IoCapability::DISPLAY_YES_NO:
538 // PassKey Entry, Responder display, Initiator input
539 NotifyUiDisplayPasskeyInput();
540 LOG_INFO("Passkey Entry: A input, B display");
541 // Authenticated
542 GetRecord()->SetAuthenticated(true);
543 break;
544 case hci::IoCapability::KEYBOARD_ONLY:
545 // PassKey Entry, both input
546 NotifyUiDisplayPasskeyInput();
547 LOG_INFO("Passkey Entry: A input, B input");
548 // Authenticated
549 GetRecord()->SetAuthenticated(true);
550 break;
551 case hci::IoCapability::NO_INPUT_NO_OUTPUT:
552 // NumericComparison, both auto confirm
553 LOG_INFO("Numeric Comparison: A and B auto confirm");
554 if (!GetRecord()->RequiresMitmProtection()) {
555 GetChannel()->SendCommand(
556 hci::UserConfirmationRequestReplyBuilder::Create(GetRecord()->GetPseudoAddress()->GetAddress()));
557 // TODO(optedoblivion): REMOVE WHEN SHIM LEAVES
558 NotifyUiDisplayYesNo();
559 } else {
560 GetChannel()->SendCommand(hci::UserConfirmationRequestNegativeReplyBuilder::Create(
561 GetRecord()->GetPseudoAddress()->GetAddress()));
562 }
563 // Unauthenticated
564 GetRecord()->SetAuthenticated(false);
565 break;
566 }
567 break;
568 case hci::IoCapability::NO_INPUT_NO_OUTPUT:
569 switch (responder_io_capability) {
570 case hci::IoCapability::DISPLAY_ONLY:
571 // NumericComparison, both auto confirm
572 LOG_INFO("Numeric Comparison: A and B auto confirm");
573 if (!GetRecord()->RequiresMitmProtection()) {
574 GetChannel()->SendCommand(
575 hci::UserConfirmationRequestReplyBuilder::Create(GetRecord()->GetPseudoAddress()->GetAddress()));
576 // TODO(optedoblivion): REMOVE WHEN SHIM LEAVES
577 NotifyUiDisplayYesNo();
578 } else {
579 GetChannel()->SendCommand(hci::UserConfirmationRequestNegativeReplyBuilder::Create(
580 GetRecord()->GetPseudoAddress()->GetAddress()));
581 }
582 // Unauthenticated
583 GetRecord()->SetAuthenticated(false);
584 break;
585 case hci::IoCapability::DISPLAY_YES_NO:
586 // NumericComparison, Initiator auto confirm, Responder Yes/No confirm, no show conf val
587 LOG_INFO("Numeric Comparison: A auto confirm");
588 if (!GetRecord()->RequiresMitmProtection()) {
589 GetChannel()->SendCommand(
590 hci::UserConfirmationRequestReplyBuilder::Create(GetRecord()->GetPseudoAddress()->GetAddress()));
591 // TODO(optedoblivion): REMOVE WHEN SHIM LEAVES
592 NotifyUiDisplayYesNo();
593 } else {
594 GetChannel()->SendCommand(hci::UserConfirmationRequestNegativeReplyBuilder::Create(
595 GetRecord()->GetPseudoAddress()->GetAddress()));
596 }
597 // Unauthenticated
598 GetRecord()->SetAuthenticated(false);
599 break;
600 case hci::IoCapability::KEYBOARD_ONLY:
601 // NumericComparison, both auto confirm
602 LOG_INFO("Numeric Comparison: A and B auto confirm");
603 if (!GetRecord()->RequiresMitmProtection()) {
604 GetChannel()->SendCommand(
605 hci::UserConfirmationRequestReplyBuilder::Create(GetRecord()->GetPseudoAddress()->GetAddress()));
606 // TODO(optedoblivion): REMOVE WHEN SHIM LEAVES
607 NotifyUiDisplayYesNo();
608 } else {
609 GetChannel()->SendCommand(hci::UserConfirmationRequestNegativeReplyBuilder::Create(
610 GetRecord()->GetPseudoAddress()->GetAddress()));
611 }
612 // Unauthenticated
613 GetRecord()->SetAuthenticated(false);
614 break;
615 case hci::IoCapability::NO_INPUT_NO_OUTPUT:
616 // NumericComparison, both auto confirm
617 LOG_INFO("Numeric Comparison: A and B auto confirm");
618 if (!GetRecord()->RequiresMitmProtection()) {
619 GetChannel()->SendCommand(
620 hci::UserConfirmationRequestReplyBuilder::Create(GetRecord()->GetPseudoAddress()->GetAddress()));
621 // TODO(optedoblivion): REMOVE WHEN SHIM LEAVES
622 NotifyUiDisplayYesNo();
623 } else {
624 GetChannel()->SendCommand(hci::UserConfirmationRequestNegativeReplyBuilder::Create(
625 GetRecord()->GetPseudoAddress()->GetAddress()));
626 }
627 // Unauthenticated
628 GetRecord()->SetAuthenticated(false);
629 break;
630 }
631 break;
632 }
633 }
634
OnReceive(hci::UserPasskeyRequestView packet)635 void ClassicPairingHandler::OnReceive(hci::UserPasskeyRequestView packet) {
636 ASSERT(packet.IsValid());
637 ASSERT_LOG(GetRecord()->GetPseudoAddress()->GetAddress() == packet.GetBdAddr(), "Address mismatch");
638 }
639
OnUserInput(bool user_input)640 void ClassicPairingHandler::OnUserInput(bool user_input) {
641 if (user_input) {
642 UserClickedYes();
643 } else {
644 UserClickedNo();
645 }
646 }
647
UserClickedYes()648 void ClassicPairingHandler::UserClickedYes() {
649 GetChannel()->SendCommand(
650 hci::UserConfirmationRequestReplyBuilder::Create(GetRecord()->GetPseudoAddress()->GetAddress()));
651 }
652
UserClickedNo()653 void ClassicPairingHandler::UserClickedNo() {
654 GetChannel()->SendCommand(
655 hci::UserConfirmationRequestNegativeReplyBuilder::Create(GetRecord()->GetPseudoAddress()->GetAddress()));
656 }
657
OnPasskeyInput(uint32_t passkey)658 void ClassicPairingHandler::OnPasskeyInput(uint32_t passkey) {
659 passkey_ = passkey;
660 }
661
662 } // namespace pairing
663 } // namespace security
664 } // namespace bluetooth
665