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