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 #pragma once
16 #include <lib/fit/function.h>
17 
18 #include "pw_bluetooth_sapphire/internal/host/common/device_address.h"
19 #include "pw_bluetooth_sapphire/internal/host/common/weak_self.h"
20 #include "pw_bluetooth_sapphire/internal/host/sm/pairing_phase.h"
21 #include "pw_bluetooth_sapphire/internal/host/sm/smp.h"
22 #include "pw_bluetooth_sapphire/internal/host/sm/util.h"
23 
24 namespace bt::sm {
25 
26 // Phase2Legacy encapsulates Phase 2 of LE Legacy Pairing, which takes care of
27 // authentication and shared encryption key generation using the Legacy Protocol
28 // (see V5.1 Vol. 3 Part H Section 2.3.5.2-2.3.5.5)
29 //
30 // This class is not thread safe and is meant to be accessed on the thread it
31 // was created on. All callbacks will be run by the default dispatcher of a
32 // Phase2Legacy's creation thread.
33 class Phase2Legacy final : public PairingPhase, public PairingChannelHandler {
34  public:
35   // |chan|, |listener|, and |role|: used to construct the base PairingPhase
36   // |id|: unique id of this pairing instance for differentiating between
37   // Pairing Delegate responses |features|: features negotiated in Phase 1 of
38   // pairing |preq|, |pres|: Byte representation of Pairing Request/Response
39   // exchanged in Phase 1, used for
40   //                 for cryptographic hashing
41   // |initiator_addr|, |responder_addr|: 48-bit bd-address of the initiator and
42   // responder, used
43   //                                     used for cryptographic hashing
44   // |cb|: Callback that is notified when the Phase2 has negotiated a new
45   // encryption key.
46   Phase2Legacy(PairingChannel::WeakPtr chan,
47                Listener::WeakPtr listener,
48                Role role,
49                PairingFeatures features,
50                const ByteBuffer& preq,
51                const ByteBuffer& pres,
52                const DeviceAddress& initiator_addr,
53                const DeviceAddress& responder_addr,
54                OnPhase2KeyGeneratedCallback cb);
~Phase2Legacy()55   ~Phase2Legacy() override { InvalidatePairingChannelHandler(); }
56 
57   // Begin Phase 2 of LE legacy pairing. This is called after LE pairing
58   // features are exchanged and results (asynchronously) in the generation and
59   // encryption of a link using the STK. Follows (roughly) the following steps:
60   //    1. Asynchronously obtain the TK.
61   //    2. Generate the local confirm/rand values.
62   //    3. If initiator, start the exchange, otherwise wait for the peer to send
63   //    its confirm value.
64   void Start() final;
65 
66  private:
67   // Ask the listener for user input to verify the TK used in Legacy pairing.
68   // The type of user input requested depends on the PairingMethod in
69   // |features_|.
70   void MakeTemporaryKeyRequest();
71   // Callback passed to request the temporary key which handles the Listener's
72   // response.
73   void HandleTemporaryKey(std::optional<uint32_t> maybe_tk);
74 
75   void SendConfirmValue();
76   // Called for SMP commands sent by the peer.
77   void OnPairingConfirm(PairingConfirmValue confirm);
78 
79   void SendRandomValue();
80   // Called for SMP commands sent by the peer.
81   void OnPairingRandom(PairingRandomValue rand);
82 
83   // Check the preconditions for being able to receive a pairing confirm/random
84   // value according to the current state.
85   fit::result<ErrorCode> CanReceivePairingConfirm() const;
86   fit::result<ErrorCode> CanReceivePairingRandom() const;
87 
88   // l2cap::Channel callbacks
89   void OnRxBFrame(ByteBufferPtr sdu) final;
OnChannelClosed()90   void OnChannelClosed() final { PairingPhase::HandleChannelClosed(); }
91 
92   // PairingPhase overrides
ToStringInternal()93   std::string ToStringInternal() override {
94     return bt_lib_cpp_string::StringPrintf(
95         "Legacy Pairing Phase 2 (encryption key agreement) - pairing with %s "
96         "method",
97         util::PairingMethodToString(features_.method).c_str());
98   }
99 
100   bool sent_local_confirm_;
101   bool sent_local_rand_;
102   std::optional<UInt128> tk_;
103   std::optional<UInt128> local_confirm_;
104   std::optional<UInt128> peer_confirm_;
105   std::optional<UInt128> local_rand_;
106   std::optional<UInt128> peer_rand_;
107   StaticByteBuffer<util::PacketSize<PairingRequestParams>()> preq_;
108   StaticByteBuffer<util::PacketSize<PairingRequestParams>()> pres_;
109 
110   const PairingFeatures features_;
111   const DeviceAddress initiator_addr_;
112   const DeviceAddress responder_addr_;
113 
114   const OnPhase2KeyGeneratedCallback on_stk_ready_;
115 
116   WeakSelf<Phase2Legacy> weak_self_;
117   BT_DISALLOW_COPY_AND_ASSIGN_ALLOW_MOVE(Phase2Legacy);
118 };
119 
120 }  // namespace bt::sm
121