1 // Copyright 2023 The Pigweed Authors
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License"); you may not
4 // use this file except in compliance with the License. You may obtain a copy of
5 // the License at
6 //
7 // https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11 // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12 // License for the specific language governing permissions and limitations under
13 // the License.
14
15 // inclusive-language: disable
16
17 #include "pw_bluetooth_sapphire/internal/host/sm/phase_2_legacy.h"
18
19 #include <cstdint>
20 #include <memory>
21
22 #include "pw_bluetooth_sapphire/internal/host/common/byte_buffer.h"
23 #include "pw_bluetooth_sapphire/internal/host/common/device_address.h"
24 #include "pw_bluetooth_sapphire/internal/host/common/random.h"
25 #include "pw_bluetooth_sapphire/internal/host/common/uint128.h"
26 #include "pw_bluetooth_sapphire/internal/host/hci/connection.h"
27 #include "pw_bluetooth_sapphire/internal/host/l2cap/fake_channel_test.h"
28 #include "pw_bluetooth_sapphire/internal/host/sm/fake_phase_listener.h"
29 #include "pw_bluetooth_sapphire/internal/host/sm/packet.h"
30 #include "pw_bluetooth_sapphire/internal/host/sm/smp.h"
31 #include "pw_bluetooth_sapphire/internal/host/sm/types.h"
32 #include "pw_bluetooth_sapphire/internal/host/sm/util.h"
33 #include "pw_bluetooth_sapphire/internal/host/testing/test_helpers.h"
34 #include "pw_unit_test/framework.h"
35
36 namespace bt::sm {
37 namespace {
38
39 const PairingFeatures kDefaultFeatures = {
40 .initiator = true,
41 .secure_connections = false,
42 .will_bond = true,
43 .generate_ct_key = std::optional<CrossTransportKeyAlgo>{std::nullopt},
44 .method = PairingMethod::kJustWorks,
45 .encryption_key_size = kMaxEncryptionKeySize,
46 .local_key_distribution = KeyDistGen::kIdKey,
47 .remote_key_distribution = KeyDistGen::kIdKey | KeyDistGen::kEncKey};
48
49 const PairingRequestParams kDefaultPreq{
50 .io_capability = IOCapability::kNoInputNoOutput,
51 .oob_data_flag = OOBDataFlag::kNotPresent,
52 .auth_req = AuthReq::kBondingFlag,
53 .max_encryption_key_size = kMaxEncryptionKeySize,
54 .initiator_key_dist_gen = KeyDistGen::kIdKey,
55 .responder_key_dist_gen = KeyDistGen::kIdKey | KeyDistGen::kEncKey};
56
57 const PairingResponseParams kDefaultPres{
58 .io_capability = IOCapability::kNoInputNoOutput,
59 .oob_data_flag = OOBDataFlag::kNotPresent,
60 .auth_req = AuthReq::kBondingFlag,
61 .max_encryption_key_size = kMaxEncryptionKeySize,
62 .initiator_key_dist_gen = KeyDistGen::kIdKey,
63 .responder_key_dist_gen = KeyDistGen::kIdKey | KeyDistGen::kEncKey};
64
65 const DeviceAddress kAddr1(DeviceAddress::Type::kLEPublic,
66 {0x00, 0x00, 0x00, 0x00, 0x00, 0x01});
67 const DeviceAddress kAddr2(DeviceAddress::Type::kLEPublic,
68 {0x00, 0x00, 0x00, 0x00, 0x00, 0x02});
69 struct Phase2LegacyArgs {
70 PairingFeatures features = kDefaultFeatures;
71 PairingRequestParams preq = kDefaultPreq;
72 PairingResponseParams pres = kDefaultPres;
73 const DeviceAddress* initiator_addr = &kAddr1;
74 const DeviceAddress* responder_addr = &kAddr2;
75 };
76
77 using util::PacketSize;
78
79 class Phase2LegacyTest : public l2cap::testing::FakeChannelTest {
80 public:
81 Phase2LegacyTest() = default;
82 ~Phase2LegacyTest() override = default;
83
heap_dispatcher()84 pw::async::HeapDispatcher& heap_dispatcher() { return heap_dispatcher_; }
85
86 protected:
SetUp()87 void SetUp() override { NewPhase2Legacy(); }
88
TearDown()89 void TearDown() override { phase_2_legacy_ = nullptr; }
90
NewPhase2Legacy(Phase2LegacyArgs phase_args=Phase2LegacyArgs (),bt::LinkType ll_type=bt::LinkType::kLE)91 void NewPhase2Legacy(Phase2LegacyArgs phase_args = Phase2LegacyArgs(),
92 bt::LinkType ll_type = bt::LinkType::kLE) {
93 l2cap::ChannelId cid = ll_type == bt::LinkType::kLE ? l2cap::kLESMPChannelId
94 : l2cap::kSMPChannelId;
95 ChannelOptions options(cid);
96 options.link_type = ll_type;
97
98 phase_args_ = phase_args;
99
100 listener_ = std::make_unique<FakeListener>();
101 fake_chan_ = CreateFakeChannel(options);
102 sm_chan_ = std::make_unique<PairingChannel>(fake_chan_->GetWeakPtr());
103 auto role =
104 phase_args.features.initiator ? Role::kInitiator : Role::kResponder;
105 StaticByteBuffer<PacketSize<PairingRequestParams>()> preq, pres;
106 preq.WriteObj(phase_args.preq);
107 pres.WriteObj(phase_args.pres);
108 phase_2_legacy_ =
109 std::make_unique<Phase2Legacy>(sm_chan_->GetWeakPtr(),
110 listener_->as_weak_ptr(),
111 role,
112 phase_args.features,
113 preq,
114 pres,
115 *phase_args.initiator_addr,
116 *phase_args.responder_addr,
117 [this](const UInt128& stk) {
118 phase_2_complete_count_++;
119 stk_ = stk;
120 });
121 }
122
Receive128BitCmd(Code cmd_code,const UInt128 & value)123 void Receive128BitCmd(Code cmd_code, const UInt128& value) {
124 fake_chan()->Receive(Make128BitCmd(cmd_code, value));
125 }
126
Make128BitCmd(Code cmd_code,const UInt128 & value)127 DynamicByteBuffer Make128BitCmd(Code cmd_code, const UInt128& value) {
128 StaticByteBuffer<PacketSize<UInt128>()> buffer;
129 PacketWriter writer(cmd_code, &buffer);
130 *writer.mutable_payload<UInt128>() = value;
131 return DynamicByteBuffer(buffer);
132 }
133
GenerateConfirmValue(const UInt128 & random,uint32_t tk=0) const134 UInt128 GenerateConfirmValue(const UInt128& random, uint32_t tk = 0) const {
135 tk = htole32(tk);
136 UInt128 tk128;
137 tk128.fill(0);
138 std::memcpy(tk128.data(), &tk, sizeof(tk));
139 StaticByteBuffer<PacketSize<PairingRequestParams>()> preq, pres;
140 preq.WriteObj(phase_args_.preq);
141 pres.WriteObj(phase_args_.pres);
142
143 UInt128 out_value;
144 util::C1(tk128,
145 random,
146 preq,
147 pres,
148 *phase_args_.initiator_addr,
149 *phase_args_.responder_addr,
150 &out_value);
151 return out_value;
152 }
153
154 struct MatchingPair {
155 UInt128 confirm;
156 UInt128 random;
157 };
GenerateMatchingConfirmAndRandom(uint32_t tk)158 MatchingPair GenerateMatchingConfirmAndRandom(uint32_t tk) {
159 MatchingPair pair;
160 random_generator()->Get(
161 {reinterpret_cast<std::byte*>(pair.random.data()), pair.random.size()});
162 pair.confirm = GenerateConfirmValue(pair.random, tk);
163 return pair;
164 }
165
ExtractCodeAnd128BitCmd(ByteBufferPtr sdu)166 static std::pair<Code, UInt128> ExtractCodeAnd128BitCmd(ByteBufferPtr sdu) {
167 BT_ASSERT_MSG(sdu, "Tried to ExtractCodeAnd128BitCmd from nullptr in test");
168 auto maybe_reader = ValidPacketReader::ParseSdu(sdu);
169 BT_ASSERT_MSG(maybe_reader.is_ok(),
170 "Tried to ExtractCodeAnd128BitCmd from invalid SMP packet");
171 return {maybe_reader.value().code(),
172 maybe_reader.value().payload<UInt128>()};
173 }
174
DestroyPhase2()175 void DestroyPhase2() { phase_2_legacy_.reset(nullptr); }
fake_chan() const176 l2cap::testing::FakeChannel* fake_chan() const { return fake_chan_.get(); }
phase_2_legacy()177 Phase2Legacy* phase_2_legacy() { return phase_2_legacy_.get(); }
listener()178 FakeListener* listener() { return listener_.get(); }
179
phase_2_complete_count() const180 int phase_2_complete_count() const { return phase_2_complete_count_; }
stk() const181 UInt128 stk() const { return stk_; }
182
183 private:
184 std::unique_ptr<FakeListener> listener_;
185 std::unique_ptr<l2cap::testing::FakeChannel> fake_chan_;
186 std::unique_ptr<PairingChannel> sm_chan_;
187 std::unique_ptr<Phase2Legacy> phase_2_legacy_;
188 Phase2LegacyArgs phase_args_;
189 int phase_2_complete_count_ = 0;
190 UInt128 stk_;
191 pw::async::HeapDispatcher heap_dispatcher_{dispatcher()};
192
193 BT_DISALLOW_COPY_AND_ASSIGN_ALLOW_MOVE(Phase2LegacyTest);
194 };
195
196 using Phase2LegacyDeathTest = Phase2LegacyTest;
197
TEST_F(Phase2LegacyDeathTest,InvalidPairingMethodDies)198 TEST_F(Phase2LegacyDeathTest, InvalidPairingMethodDies) {
199 Phase2LegacyArgs args;
200 // Legacy Pairing does not permit Numeric Comparison (V5.0, Vol. 3, Part H,
201 // Section 2.3.5.1)
202 args.features.method = PairingMethod::kNumericComparison;
203 ASSERT_DEATH_IF_SUPPORTED(NewPhase2Legacy(args), "method");
204 }
205
TEST_F(Phase2LegacyTest,InitiatorJustWorksStkSucceeds)206 TEST_F(Phase2LegacyTest, InitiatorJustWorksStkSucceeds) {
207 Phase2LegacyArgs args;
208 args.features.initiator = true;
209 args.features.method = PairingMethod::kJustWorks;
210 NewPhase2Legacy(args);
211 // Using Just Works, pairing should request user confirmation
212 FakeListener::ConfirmCallback confirm_cb = nullptr;
213 listener()->set_confirm_delegate(
214 [&](FakeListener::ConfirmCallback cb) { confirm_cb = std::move(cb); });
215
216 Code sent_code = kInvalidCode;
217 std::optional<UInt128> sent_payload = std::nullopt;
218 fake_chan()->SetSendCallback(
219 [&](ByteBufferPtr sdu) {
220 std::tie(sent_code, sent_payload) =
221 ExtractCodeAnd128BitCmd(std::move(sdu));
222 },
223 dispatcher());
224 phase_2_legacy()->Start();
225 // We should request user confirmation, but not send a message until we
226 // receive it.
227 ASSERT_EQ(kInvalidCode, sent_code);
228 ASSERT_TRUE(confirm_cb);
229 confirm_cb(true);
230 RunUntilIdle();
231 ASSERT_EQ(kPairingConfirm, sent_code);
232
233 // Reset |sent_payload| to be able to detect that the FakeChannel's
234 // |send_callback| is notified.
235 sent_payload = std::nullopt;
236 MatchingPair values =
237 GenerateMatchingConfirmAndRandom(0); // Just Works TK is 0
238 Receive128BitCmd(kPairingConfirm, values.confirm);
239 RunUntilIdle();
240 ASSERT_EQ(kPairingRandom, sent_code);
241 ASSERT_TRUE(sent_payload.has_value());
242
243 // Receive the peer pairing random & verify pairing completes successfully
244 Receive128BitCmd(kPairingRandom, values.random);
245 RunUntilIdle();
246 ASSERT_EQ(1, phase_2_complete_count());
247 UInt128 generated_stk;
248 util::S1({0}, values.random, *sent_payload, &generated_stk);
249 ASSERT_EQ(generated_stk, stk());
250 }
251
TEST_F(Phase2LegacyTest,InitiatorPasskeyInputStkSucceeds)252 TEST_F(Phase2LegacyTest, InitiatorPasskeyInputStkSucceeds) {
253 Phase2LegacyArgs args;
254 args.features.initiator = true;
255 args.features.method = PairingMethod::kPasskeyEntryInput;
256 // preq & pres are set for consistency w/ args.features - not necessary for
257 // the test to pass.
258 args.preq.io_capability = IOCapability::kKeyboardOnly;
259 args.preq.auth_req |= AuthReq::kMITM;
260 args.pres.io_capability = IOCapability::kDisplayOnly;
261 NewPhase2Legacy(args);
262 FakeListener::PasskeyResponseCallback passkey_responder = nullptr;
263 listener()->set_request_passkey_delegate(
264 [&](FakeListener::PasskeyResponseCallback cb) {
265 passkey_responder = std::move(cb);
266 });
267
268 Code sent_code = kInvalidCode;
269 std::optional<UInt128> sent_payload = std::nullopt;
270 fake_chan()->SetSendCallback(
271 [&](ByteBufferPtr sdu) {
272 std::tie(sent_code, sent_payload) =
273 ExtractCodeAnd128BitCmd(std::move(sdu));
274 },
275 dispatcher());
276 phase_2_legacy()->Start();
277
278 // We should request user confirmation, but not send a message until we
279 // receive it.
280 ASSERT_EQ(kInvalidCode, sent_code);
281 ASSERT_TRUE(passkey_responder);
282 const int32_t kTk = 0x1234;
283 const UInt128 kTk128 = {0x34, 0x12};
284 passkey_responder(kTk);
285 RunUntilIdle();
286 ASSERT_EQ(kPairingConfirm, sent_code);
287
288 // Reset |sent_payload| to be able to detect that the FakeChannel's
289 // |send_callback| is notified.
290 sent_payload = std::nullopt;
291 MatchingPair values = GenerateMatchingConfirmAndRandom(kTk);
292 Receive128BitCmd(kPairingConfirm, values.confirm);
293 RunUntilIdle();
294 ASSERT_EQ(kPairingRandom, sent_code);
295 ASSERT_TRUE(sent_payload.has_value());
296
297 // Receive the peer pairing random & verify pairing completes successfully
298 Receive128BitCmd(kPairingRandom, values.random);
299 RunUntilIdle();
300 ASSERT_EQ(1, phase_2_complete_count());
301 UInt128 generated_stk;
302 util::S1(kTk128, values.random, *sent_payload, &generated_stk);
303 ASSERT_EQ(generated_stk, stk());
304 }
305
306 // This test is shorter than InitiatorPasskeyInputStkSucceeds because it only
307 // tests the code paths that differ for PasskeyDisplay, which all take place
308 // before sending the Confirm value.
TEST_F(Phase2LegacyTest,InitiatorPasskeyDisplaySucceeds)309 TEST_F(Phase2LegacyTest, InitiatorPasskeyDisplaySucceeds) {
310 Phase2LegacyArgs args;
311 args.features.initiator = true;
312 args.features.method = PairingMethod::kPasskeyEntryDisplay;
313 // preq & pres are set for consistency w/ args.features - not necessary for
314 // the test to pass.
315 args.preq.io_capability = IOCapability::kDisplayOnly;
316 args.preq.auth_req |= AuthReq::kMITM;
317 args.pres.io_capability = IOCapability::kKeyboardOnly;
318 NewPhase2Legacy(args);
319
320 FakeListener::ConfirmCallback display_confirmer = nullptr;
321 listener()->set_display_delegate(
322 [&](uint32_t, bool, FakeListener::ConfirmCallback cb) {
323 display_confirmer = std::move(cb);
324 });
325
326 Code sent_code = kInvalidCode;
327 std::optional<UInt128> sent_payload = std::nullopt;
328 fake_chan()->SetSendCallback(
329 [&](ByteBufferPtr sdu) {
330 std::tie(sent_code, sent_payload) =
331 ExtractCodeAnd128BitCmd(std::move(sdu));
332 },
333 dispatcher());
334 phase_2_legacy()->Start();
335 // We should request user confirmation, but not send a message until we
336 // receive it.
337 ASSERT_EQ(kInvalidCode, sent_code);
338 ASSERT_TRUE(display_confirmer);
339 display_confirmer(true);
340 RunUntilIdle();
341 ASSERT_EQ(kPairingConfirm, sent_code);
342 ASSERT_TRUE(sent_payload.has_value());
343 // After sending Pairing Confirm, the behavior is the same as
344 // InitiatorPasskeyInputStkSucceeds
345 }
346
TEST_F(Phase2LegacyTest,InitiatorReceivesConfirmBeforeTkFails)347 TEST_F(Phase2LegacyTest, InitiatorReceivesConfirmBeforeTkFails) {
348 Phase2LegacyArgs args;
349 args.features.initiator = true;
350 NewPhase2Legacy(args);
351 FakeListener::ConfirmCallback confirm_cb = nullptr;
352 listener()->set_confirm_delegate(
353 [&](FakeListener::ConfirmCallback cb) { confirm_cb = std::move(cb); });
354
355 ByteBufferPtr sent_sdu = nullptr;
356 fake_chan()->SetSendCallback(
357 [&](ByteBufferPtr sdu) { sent_sdu = std::move(sdu); }, dispatcher());
358 phase_2_legacy()->Start();
359 ASSERT_TRUE(confirm_cb);
360 ASSERT_FALSE(sent_sdu);
361
362 // Receive peer confirm (generated from arbitrary peer rand {0}) before
363 // |confirm_cb| is notified
364 const auto kPairingConfirmCmd =
365 Make128BitCmd(kPairingConfirm, GenerateConfirmValue({0}));
366 const StaticByteBuffer<PacketSize<ErrorCode>()> kExpectedFailure{
367 kPairingFailed, ErrorCode::kUnspecifiedReason};
368 ASSERT_TRUE(ReceiveAndExpect(kPairingConfirmCmd, kExpectedFailure));
369 }
370
TEST_F(Phase2LegacyTest,InvalidConfirmValueFails)371 TEST_F(Phase2LegacyTest, InvalidConfirmValueFails) {
372 Code sent_code = kInvalidCode;
373 std::optional<UInt128> sent_payload = std::nullopt;
374 fake_chan()->SetSendCallback(
375 [&](ByteBufferPtr sdu) {
376 std::tie(sent_code, sent_payload) =
377 ExtractCodeAnd128BitCmd(std::move(sdu));
378 },
379 dispatcher());
380 phase_2_legacy()->Start();
381 RunUntilIdle();
382 ASSERT_EQ(kPairingConfirm, sent_code);
383 // Reset |sent_payload| to be able to detect that the FakeChannel's
384 // |send_callback| is notified.
385 sent_payload = std::nullopt;
386 MatchingPair values =
387 GenerateMatchingConfirmAndRandom(0); // Just Works TK is 0
388 Receive128BitCmd(kPairingConfirm, values.confirm);
389 RunUntilIdle();
390 ASSERT_EQ(kPairingRandom, sent_code);
391 // Change the peer random so that the confirm value we sent does not match the
392 // random value.
393 UInt128 mismatched_peer_rand = values.random;
394 mismatched_peer_rand[0] += 1;
395 const auto kPairingRandomCmd =
396 Make128BitCmd(kPairingRandom, mismatched_peer_rand);
397 const StaticByteBuffer<PacketSize<ErrorCode>()> kExpectedFailure{
398 kPairingFailed, ErrorCode::kConfirmValueFailed};
399 ASSERT_TRUE(ReceiveAndExpect(kPairingRandomCmd, kExpectedFailure));
400 ASSERT_EQ(1, listener()->pairing_error_count());
401 }
402
TEST_F(Phase2LegacyTest,JustWorksUserConfirmationRejectedPairingFails)403 TEST_F(Phase2LegacyTest, JustWorksUserConfirmationRejectedPairingFails) {
404 Phase2LegacyArgs args;
405 args.features.method = PairingMethod::kJustWorks;
406 NewPhase2Legacy(args);
407 // Reject the TK request
408 bool confirmation_requested = false;
409 listener()->set_confirm_delegate([&](FakeListener::ConfirmCallback cb) {
410 confirmation_requested = true;
411 cb(false);
412 });
413 (void)heap_dispatcher().Post(
414 [this](pw::async::Context /*ctx*/, pw::Status status) {
415 if (status.ok()) {
416 phase_2_legacy()->Start();
417 }
418 });
419 const StaticByteBuffer<PacketSize<ErrorCode>()> kExpectedFailure{
420 kPairingFailed, ErrorCode::kUnspecifiedReason};
421 ASSERT_TRUE(Expect(kExpectedFailure));
422 ASSERT_TRUE(confirmation_requested);
423 ASSERT_EQ(1, listener()->pairing_error_count());
424 }
425
TEST_F(Phase2LegacyTest,PasskeyInputRejectedPairingFails)426 TEST_F(Phase2LegacyTest, PasskeyInputRejectedPairingFails) {
427 Phase2LegacyArgs args;
428 args.features.method = PairingMethod::kPasskeyEntryInput;
429 NewPhase2Legacy(args);
430 // Reject the TK request
431 bool confirmation_requested = false;
432 listener()->set_request_passkey_delegate(
433 [&](FakeListener::PasskeyResponseCallback cb) {
434 confirmation_requested = true;
435 const int64_t kGenericNegativeInt = -12;
436 cb(kGenericNegativeInt);
437 });
438 (void)heap_dispatcher().Post(
439 [this](pw::async::Context /*ctx*/, pw::Status status) {
440 if (status.ok()) {
441 phase_2_legacy()->Start();
442 }
443 });
444 const StaticByteBuffer<PacketSize<ErrorCode>()> kExpectedFailure{
445 kPairingFailed, ErrorCode::kPasskeyEntryFailed};
446 ASSERT_TRUE(Expect(kExpectedFailure));
447 ASSERT_TRUE(confirmation_requested);
448 ASSERT_EQ(1, listener()->pairing_error_count());
449 }
450
TEST_F(Phase2LegacyTest,PasskeyDisplayRejectedPairingFails)451 TEST_F(Phase2LegacyTest, PasskeyDisplayRejectedPairingFails) {
452 Phase2LegacyArgs args;
453 args.features.method = PairingMethod::kPasskeyEntryDisplay;
454 NewPhase2Legacy(args);
455 // Reject the TK request
456 bool confirmation_requested = false;
457 listener()->set_display_delegate(
458 [&](uint32_t /*ignore*/, bool, FakeListener::ConfirmCallback cb) {
459 confirmation_requested = true;
460 cb(false);
461 });
462 (void)heap_dispatcher().Post(
463 [this](pw::async::Context /*ctx*/, pw::Status status) {
464 if (status.ok()) {
465 phase_2_legacy()->Start();
466 }
467 });
468 const StaticByteBuffer<PacketSize<ErrorCode>()> kExpectedFailure{
469 kPairingFailed, ErrorCode::kUnspecifiedReason};
470 ASSERT_TRUE(Expect(kExpectedFailure));
471 ASSERT_TRUE(confirmation_requested);
472 ASSERT_EQ(1, listener()->pairing_error_count());
473 }
474
475 // Each of the pairing methods has its own user input callback, and thus correct
476 // behavior under destruction of the Phase needs to be checked for each method.
TEST_F(Phase2LegacyTest,PhaseDestroyedWhileWaitingForJustWorksTk)477 TEST_F(Phase2LegacyTest, PhaseDestroyedWhileWaitingForJustWorksTk) {
478 Phase2LegacyArgs args;
479 args.features.method = PairingMethod::kJustWorks;
480 NewPhase2Legacy(args);
481 FakeListener::ConfirmCallback respond = nullptr;
482 listener()->set_confirm_delegate([&](auto rsp) { respond = std::move(rsp); });
483 phase_2_legacy()->Start();
484
485 ASSERT_TRUE(respond);
486
487 DestroyPhase2();
488 respond(true);
489 RunUntilIdle();
490 SUCCEED();
491 }
492
TEST_F(Phase2LegacyTest,PhaseDestroyedWhileWaitingForPasskeyInputTk)493 TEST_F(Phase2LegacyTest, PhaseDestroyedWhileWaitingForPasskeyInputTk) {
494 Phase2LegacyArgs args;
495 args.features.method = PairingMethod::kPasskeyEntryInput;
496 NewPhase2Legacy(args);
497 FakeListener::PasskeyResponseCallback respond = nullptr;
498 listener()->set_request_passkey_delegate(
499 [&](auto rsp) { respond = std::move(rsp); });
500 phase_2_legacy()->Start();
501
502 ASSERT_TRUE(respond);
503
504 DestroyPhase2();
505 respond(1234);
506 RunUntilIdle();
507 SUCCEED();
508 }
509
TEST_F(Phase2LegacyTest,PhaseDestroyedWaitingForPasskeyDisplayTk)510 TEST_F(Phase2LegacyTest, PhaseDestroyedWaitingForPasskeyDisplayTk) {
511 Phase2LegacyArgs args;
512 args.features.method = PairingMethod::kPasskeyEntryDisplay;
513 NewPhase2Legacy(args);
514 FakeListener::ConfirmCallback respond = nullptr;
515 listener()->set_display_delegate(
516 [&](uint32_t /*unused*/, bool, FakeListener::ConfirmCallback rsp) {
517 respond = std::move(rsp);
518 });
519 phase_2_legacy()->Start();
520
521 ASSERT_TRUE(respond);
522
523 DestroyPhase2();
524 respond(true);
525 RunUntilIdle();
526 SUCCEED();
527 }
528
TEST_F(Phase2LegacyTest,ReceiveRandomBeforeTkFails)529 TEST_F(Phase2LegacyTest, ReceiveRandomBeforeTkFails) {
530 // This test assumes initiator flow, but the behavior verified is the same for
531 // responder flow.
532 FakeListener::ConfirmCallback confirm_cb = nullptr;
533 listener()->set_confirm_delegate(
534 [&](FakeListener::ConfirmCallback cb) { confirm_cb = std::move(cb); });
535
536 phase_2_legacy()->Start();
537 // We should have made the pairing delegate request, which will not be
538 // responded to.
539 ASSERT_TRUE(confirm_cb);
540
541 MatchingPair values =
542 GenerateMatchingConfirmAndRandom(0); // Just Works TK is 0
543 const auto kPairingRandomCmd = Make128BitCmd(kPairingRandom, values.random);
544 const StaticByteBuffer<PacketSize<ErrorCode>()> kExpectedFailure{
545 kPairingFailed, ErrorCode::kUnspecifiedReason};
546 ASSERT_TRUE(ReceiveAndExpect(kPairingRandomCmd, kExpectedFailure));
547 ASSERT_EQ(1, listener()->pairing_error_count());
548 }
549
TEST_F(Phase2LegacyTest,ReceiveRandomBeforeConfirmFails)550 TEST_F(Phase2LegacyTest, ReceiveRandomBeforeConfirmFails) {
551 // This test assumes initiator flow, but the behavior verified is the same for
552 // responder flow.
553 bool requested_confirmation = false;
554 // We automatically confirm the TK to check the case where we have a TK, but
555 // no peer confirm.
556 listener()->set_confirm_delegate([&](FakeListener::ConfirmCallback cb) {
557 requested_confirmation = true;
558 cb(true);
559 });
560 phase_2_legacy()->Start();
561 ASSERT_TRUE(requested_confirmation);
562 MatchingPair values =
563 GenerateMatchingConfirmAndRandom(0); // Just Works TK is 0
564 const auto kPairingRandomCmd = Make128BitCmd(kPairingRandom, values.random);
565 const StaticByteBuffer<PacketSize<ErrorCode>()> kExpectedFailure{
566 kPairingFailed, ErrorCode::kUnspecifiedReason};
567 ASSERT_TRUE(ReceiveAndExpect(kPairingRandomCmd, kExpectedFailure));
568 ASSERT_EQ(1, listener()->pairing_error_count());
569 }
570
TEST_F(Phase2LegacyTest,ReceivePairingFailed)571 TEST_F(Phase2LegacyTest, ReceivePairingFailed) {
572 phase_2_legacy()->Start();
573 fake_chan()->Receive(StaticByteBuffer<PacketSize<ErrorCode>()>{
574 kPairingFailed, ErrorCode::kPairingNotSupported});
575 RunUntilIdle();
576
577 EXPECT_EQ(1, listener()->pairing_error_count());
578 EXPECT_EQ(Error(ErrorCode::kPairingNotSupported), listener()->last_error());
579 }
580
TEST_F(Phase2LegacyTest,UnsupportedCommandDuringPairing)581 TEST_F(Phase2LegacyTest, UnsupportedCommandDuringPairing) {
582 // Don't confirm the TK so that the confirm value is not sent;
583 listener()->set_confirm_delegate([](auto) {});
584 phase_2_legacy()->Start();
585
586 const StaticByteBuffer<PacketSize<ErrorCode>()> kExpected{
587 kPairingFailed, ErrorCode::kCommandNotSupported};
588 ASSERT_TRUE(ReceiveAndExpect(StaticByteBuffer<1>(0xFF),
589 kExpected)); // 0xFF is not an SMP code.
590 EXPECT_EQ(1, listener()->pairing_error_count());
591 EXPECT_EQ(Error(ErrorCode::kCommandNotSupported), listener()->last_error());
592 }
593
TEST_F(Phase2LegacyTest,ReceiveMalformedPacket)594 TEST_F(Phase2LegacyTest, ReceiveMalformedPacket) {
595 phase_2_legacy()->Start();
596 // clang-format off
597 const StaticByteBuffer<PacketSize<PairingRandomValue>() - 1> kMalformedPairingRandom {
598 kPairingRandom,
599 // Random value (1 octet too short)
600 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15
601 };
602 const StaticByteBuffer<PacketSize<ErrorCode>()> kExpectedFailure {
603 kPairingFailed, ErrorCode::kInvalidParameters
604 };
605 // clang-format on
606
607 EXPECT_TRUE(ReceiveAndExpect(kMalformedPairingRandom, kExpectedFailure));
608 }
609
TEST_F(Phase2LegacyTest,ResponderJustWorksStkSucceeds)610 TEST_F(Phase2LegacyTest, ResponderJustWorksStkSucceeds) {
611 Phase2LegacyArgs args;
612 args.features.initiator = false;
613 args.features.method = PairingMethod::kJustWorks;
614 NewPhase2Legacy(args);
615 // Using Just Works, pairing should request user confirmation
616 FakeListener::ConfirmCallback confirm_cb = nullptr;
617 listener()->set_confirm_delegate(
618 [&](FakeListener::ConfirmCallback cb) { confirm_cb = std::move(cb); });
619
620 Code sent_code = kInvalidCode;
621 std::optional<UInt128> sent_payload = std::nullopt;
622 fake_chan()->SetSendCallback(
623 [&](ByteBufferPtr sdu) {
624 std::tie(sent_code, sent_payload) =
625 ExtractCodeAnd128BitCmd(std::move(sdu));
626 },
627 dispatcher());
628 phase_2_legacy()->Start();
629 // We should not send a message until we receive the requested user input AND
630 // the peer confirm.
631 ASSERT_TRUE(confirm_cb);
632 ASSERT_EQ(kInvalidCode, sent_code);
633 confirm_cb(true);
634 RunUntilIdle();
635 ASSERT_EQ(kInvalidCode, sent_code);
636
637 // Now we receive the peer confirm & should send ours.
638 MatchingPair values =
639 GenerateMatchingConfirmAndRandom(0); // Just Works TK is 0
640 Receive128BitCmd(kPairingConfirm, values.confirm);
641 RunUntilIdle();
642 ASSERT_EQ(kPairingConfirm, sent_code);
643
644 // Reset |sent_payload| to be able to detect that the FakeChannel's
645 // |send_callback| is notified.
646 sent_payload = std::nullopt;
647 // Receive the peer pairing random & verify we send our random & pairing
648 // completes.
649 Receive128BitCmd(kPairingRandom, values.random);
650 RunUntilIdle();
651 ASSERT_EQ(kPairingRandom, sent_code);
652 ASSERT_TRUE(sent_payload.has_value());
653 ASSERT_EQ(1, phase_2_complete_count());
654 UInt128 generated_stk;
655 util::S1({0}, *sent_payload, values.random, &generated_stk);
656 ASSERT_EQ(generated_stk, stk());
657 }
658
TEST_F(Phase2LegacyTest,ResponderPasskeyInputStkSucceeds)659 TEST_F(Phase2LegacyTest, ResponderPasskeyInputStkSucceeds) {
660 Phase2LegacyArgs args;
661 args.features.initiator = false;
662 args.features.method = PairingMethod::kPasskeyEntryInput;
663 // preq & pres are set for consistency w/ args.features - not necessary for
664 // the test to pass.
665 args.preq.io_capability = IOCapability::kDisplayOnly;
666 args.preq.auth_req |= AuthReq::kMITM;
667 args.pres.io_capability = IOCapability::kKeyboardOnly;
668 NewPhase2Legacy(args);
669 FakeListener::PasskeyResponseCallback passkey_responder = nullptr;
670 listener()->set_request_passkey_delegate(
671 [&](FakeListener::PasskeyResponseCallback cb) {
672 passkey_responder = std::move(cb);
673 });
674
675 Code sent_code = kInvalidCode;
676 std::optional<UInt128> sent_payload = std::nullopt;
677 fake_chan()->SetSendCallback(
678 [&](ByteBufferPtr sdu) {
679 std::tie(sent_code, sent_payload) =
680 ExtractCodeAnd128BitCmd(std::move(sdu));
681 },
682 dispatcher());
683
684 phase_2_legacy()->Start();
685
686 // We should not send a message until we receive the requested user input AND
687 // the peer confirm.
688 ASSERT_TRUE(passkey_responder);
689 ASSERT_EQ(kInvalidCode, sent_code);
690 const int32_t kTk = 0x1234;
691 const UInt128 kTk128 = {0x34, 0x12};
692 passkey_responder(kTk);
693 RunUntilIdle();
694 ASSERT_EQ(kInvalidCode, sent_code);
695 // Now we receive the peer confirm & should send ours.
696 MatchingPair values = GenerateMatchingConfirmAndRandom(kTk);
697 Receive128BitCmd(kPairingConfirm, values.confirm);
698 RunUntilIdle();
699 ASSERT_EQ(kPairingConfirm, sent_code);
700
701 // Reset |sent_payload| to be able to detect that the FakeChannel's
702 // |send_callback| is notified.
703 sent_payload = std::nullopt;
704 // Receive the peer pairing random & verify we send our random & pairing
705 // completes.
706 Receive128BitCmd(kPairingRandom, values.random);
707 RunUntilIdle();
708 ASSERT_EQ(kPairingRandom, sent_code);
709 ASSERT_TRUE(sent_payload.has_value());
710 ASSERT_EQ(1, phase_2_complete_count());
711 UInt128 generated_stk;
712 util::S1(kTk128, *sent_payload, values.random, &generated_stk);
713 ASSERT_EQ(generated_stk, stk());
714 }
715
716 // This test is shorter than ResponderPasskeyInputStkSucceeds because it only
717 // tests the code paths that differ for PasskeyDisplay, which all take place
718 // before sending the Confirm value.
TEST_F(Phase2LegacyTest,ResponderPasskeyDisplaySucceeds)719 TEST_F(Phase2LegacyTest, ResponderPasskeyDisplaySucceeds) {
720 Phase2LegacyArgs args;
721 args.features.initiator = false;
722 args.features.method = PairingMethod::kPasskeyEntryDisplay;
723 // preq & pres are set for consistency w/ args.features - not necessary for
724 // the test to pass.
725 args.preq.io_capability = IOCapability::kKeyboardOnly;
726 args.preq.auth_req |= AuthReq::kMITM;
727 args.pres.io_capability = IOCapability::kDisplayOnly;
728 NewPhase2Legacy(args);
729
730 FakeListener::ConfirmCallback display_confirmer = nullptr;
731 uint32_t passkey = 0;
732 listener()->set_display_delegate(
733 [&](uint32_t key, bool, FakeListener::ConfirmCallback cb) {
734 passkey = key;
735 display_confirmer = std::move(cb);
736 });
737
738 Code sent_code = kInvalidCode;
739 std::optional<UInt128> sent_payload = std::nullopt;
740 fake_chan()->SetSendCallback(
741 [&](ByteBufferPtr sdu) {
742 std::tie(sent_code, sent_payload) =
743 ExtractCodeAnd128BitCmd(std::move(sdu));
744 },
745 dispatcher());
746
747 phase_2_legacy()->Start();
748 // We should not send a message until we receive the requested user input AND
749 // the peer confirm.
750 ASSERT_TRUE(display_confirmer);
751 ASSERT_EQ(kInvalidCode, sent_code);
752 display_confirmer(true);
753 RunUntilIdle();
754 ASSERT_EQ(kInvalidCode, sent_code);
755
756 // Now we receive the peer confirm & should send ours.
757 MatchingPair values = GenerateMatchingConfirmAndRandom(passkey);
758 Receive128BitCmd(kPairingConfirm, values.confirm);
759 RunUntilIdle();
760 ASSERT_EQ(kPairingConfirm, sent_code);
761 ASSERT_TRUE(sent_payload.has_value());
762 }
763
TEST_F(Phase2LegacyTest,ResponderReceivesConfirmBeforeTkSucceeds)764 TEST_F(Phase2LegacyTest, ResponderReceivesConfirmBeforeTkSucceeds) {
765 Phase2LegacyArgs args;
766 args.features.initiator = false;
767 NewPhase2Legacy(args);
768 // Using Just Works, pairing should request user confirmation
769 FakeListener::ConfirmCallback confirm_cb = nullptr;
770 listener()->set_confirm_delegate(
771 [&](FakeListener::ConfirmCallback cb) { confirm_cb = std::move(cb); });
772
773 Code sent_code = kInvalidCode;
774 std::optional<UInt128> sent_payload = std::nullopt;
775 fake_chan()->SetSendCallback(
776 [&](ByteBufferPtr sdu) {
777 std::tie(sent_code, sent_payload) =
778 ExtractCodeAnd128BitCmd(std::move(sdu));
779 },
780 dispatcher());
781 phase_2_legacy()->Start();
782
783 // We should not send a message until we receive the requested user input AND
784 // the peer confirm.
785 ASSERT_TRUE(confirm_cb);
786 ASSERT_EQ(kInvalidCode, sent_code);
787 MatchingPair values =
788 GenerateMatchingConfirmAndRandom(0); // Just Works TK is 0
789 Receive128BitCmd(kPairingConfirm, values.confirm);
790 RunUntilIdle();
791 ASSERT_EQ(kInvalidCode, sent_code);
792
793 // Now we received the user input & should send the peer our confirmation.
794 confirm_cb(true);
795 RunUntilIdle();
796 ASSERT_EQ(kPairingConfirm, sent_code);
797 // Reset |sent_payload| to be able to detect that the FakeChannel's
798 // |send_callback| is notified.
799 sent_payload = std::nullopt;
800 // Receive the peer pairing random & verify we send our random & pairing
801 // completes.
802 Receive128BitCmd(kPairingRandom, values.random);
803 RunUntilIdle();
804 ASSERT_EQ(kPairingRandom, sent_code);
805 ASSERT_TRUE(sent_payload.has_value());
806 ASSERT_EQ(1, phase_2_complete_count());
807 UInt128 generated_stk;
808 util::S1({0}, *sent_payload, values.random, &generated_stk);
809 ASSERT_EQ(generated_stk, stk());
810 }
811
TEST_F(Phase2LegacyTest,ReceiveConfirmValueTwiceFails)812 TEST_F(Phase2LegacyTest, ReceiveConfirmValueTwiceFails) {
813 // This test uses the responder flow, but the behavior verified is the same
814 // for initiator flow.
815 Phase2LegacyArgs args;
816 args.features.initiator = false;
817 NewPhase2Legacy(args);
818
819 Code code = kInvalidCode;
820 fake_chan()->SetSendCallback(
821 [&](ByteBufferPtr sdu) {
822 std::tie(code, std::ignore) = ExtractCodeAnd128BitCmd(std::move(sdu));
823 },
824 dispatcher());
825 phase_2_legacy()->Start();
826
827 MatchingPair values =
828 GenerateMatchingConfirmAndRandom(0); // Just Works TK is 0
829 Receive128BitCmd(kPairingConfirm, values.confirm);
830 RunUntilIdle();
831 ASSERT_EQ(kPairingConfirm, code);
832 const auto kPairingConfirmCmd =
833 Make128BitCmd(kPairingConfirm, values.confirm);
834 // Pairing should fail after receiving 2 confirm values with
835 // kUnspecifiedReason
836 const StaticByteBuffer<PacketSize<ErrorCode>()> kExpectedFailure{
837 kPairingFailed, ErrorCode::kUnspecifiedReason};
838 ASSERT_TRUE(ReceiveAndExpect(kPairingConfirmCmd, kExpectedFailure));
839 ASSERT_EQ(1, listener()->pairing_error_count());
840 }
841
842 // Phase 2 ends after receiving the second random value & subsequently sending
843 // its own, but if the Phase 2 object is kept around and receives a second
844 // random value, pairing will fail.
TEST_F(Phase2LegacyTest,ReceiveRandomValueTwiceFails)845 TEST_F(Phase2LegacyTest, ReceiveRandomValueTwiceFails) {
846 // This test uses the responder flow, but the behavior verified is the same
847 // for initiator flow.
848 Phase2LegacyArgs args;
849 args.features.initiator = false;
850 NewPhase2Legacy(args);
851
852 phase_2_legacy()->Start();
853
854 MatchingPair values =
855 GenerateMatchingConfirmAndRandom(0); // Just Works TK is 0
856 Receive128BitCmd(kPairingConfirm, values.confirm);
857 RunUntilIdle();
858 Receive128BitCmd(kPairingRandom, values.random);
859 RunUntilIdle();
860 // We've completed Phase 2, and should've notified the callback
861 ASSERT_EQ(1, phase_2_complete_count());
862 const auto kPairingRandomCmd = Make128BitCmd(kPairingRandom, values.random);
863 // Pairing should fail after receiving a second random value with
864 // kUnspecifiedReason
865 const StaticByteBuffer<PacketSize<ErrorCode>()> kExpectedFailure{
866 kPairingFailed, ErrorCode::kUnspecifiedReason};
867 ASSERT_TRUE(ReceiveAndExpect(kPairingRandomCmd, kExpectedFailure));
868 ASSERT_EQ(1, listener()->pairing_error_count());
869 }
870 } // namespace
871 } // namespace bt::sm
872