• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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