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