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