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