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/hci/connection.h" 19 #include "pw_bluetooth_sapphire/internal/host/l2cap/channel.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/types.h" 23 #include "pw_bluetooth_sapphire/internal/host/sm/util.h" 24 25 namespace bt::sm { 26 // Responsible for Phase 1 of SMP pairing, the feature exchange. Takes in the 27 // current SM settings and notifies a constructor-provided callback with the 28 // negotiated features upon completion. 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 // Phase1's creation thread. 33 class Phase1 final : public PairingPhase, public PairingChannelHandler { 34 public: 35 // Called when Phase 1 completes successfully. |features| are the negotiated 36 // features. |preq| and |pres| are the SMP "Pairing Request" and "Pairing 37 // Response" payloads exchanged by the devices, which are returned for use in 38 // Phase 2 crypto calculations. 39 using CompleteCallback = fit::function<void(PairingFeatures features, 40 PairingRequestParams preq, 41 PairingResponseParams pres)>; 42 43 // Returns a Phase 1 that starts pairing to |requested_level|. Note the lack 44 // of a `preq` parameter: Phase 1 builds & sends the Pairing Request as 45 // initiator. 46 static std::unique_ptr<Phase1> CreatePhase1Initiator( 47 PairingChannel::WeakPtr chan, 48 Listener::WeakPtr listener, 49 IOCapability io_capability, 50 BondableMode bondable_mode, 51 SecurityLevel requested_level, 52 CompleteCallback on_complete); 53 54 // Returns a Phase 1 in the responder role. Note the `preq` parameter: Phase 1 55 // is supplied the Pairing Request from the remote as responder. See private 56 // ctor for parameter descriptions. 57 static std::unique_ptr<Phase1> CreatePhase1Responder( 58 PairingChannel::WeakPtr chan, 59 Listener::WeakPtr listener, 60 PairingRequestParams preq, 61 IOCapability io_capability, 62 BondableMode bondable_mode, 63 SecurityLevel requested_level, 64 CompleteCallback on_complete); 65 ~Phase1()66 ~Phase1() override { InvalidatePairingChannelHandler(); } 67 68 // Runs the Phase 1 state machine, performing the feature exchange. 69 void Start() final; 70 71 private: 72 // |chan|, |listener|, and |role|: used to construct the base PairingPhase 73 // |preq|: If empty, the device is in the initiator role and starts the 74 // pairing. 75 // If present, the device is in the responder role, and will respond 76 // to |preq|, the peer initiator's pairing request. 77 // |bondable_mode|: the bondable mode of the local device (see V5.1 Vol. 3 78 // Part C Section 9.4). |requested_level|: The minimum security level 79 // required by the local device for this pairing. 80 // Must be at least SecurityLevel::kEncrypted. If 81 // authenticated, the ctor ASSERTs that |io_capabilities| 82 // can perform authenticated pairing. 83 // |on_complete|: called at the end of Phase 1 with the resulting features. 84 Phase1(PairingChannel::WeakPtr chan, 85 Listener::WeakPtr listener, 86 Role role, 87 std::optional<PairingRequestParams> preq, 88 IOCapability io_capability, 89 BondableMode bondable_mode, 90 SecurityLevel requested_level, 91 CompleteCallback on_complete); 92 93 // Start the feature exchange by sending the Pairing Request. The local device 94 // must be in the SMP initiator role (V5.1 Vol 3, Part H, 2.3). 95 void InitiateFeatureExchange(); 96 97 // Handle the peer-initiated feature exchange. The local device must be in the 98 // SMP responder role (V5.1 Vol 3, Part H, 2.3). 99 void RespondToPairingRequest(const PairingRequestParams& req_params); 100 101 // The returned `LocalPairingParams` contains the locally-preferred pairing 102 // parameters for the LE transport. The caller is responsible for making any 103 // adjustments necessary (e.g. due to peer preferences) before converting the 104 // `LocalPairingParams` to SMP Pairing(Response|Request) PDUs. 105 LocalPairingParams BuildPairingParameters(); 106 107 // Called to complete a feature exchange. Returns the resulting 108 // PairingFeatures if the parameters should be accepted, or an error code if 109 // the parameters are rejected and pairing should abort. 110 fit::result<ErrorCode, PairingFeatures> ResolveFeatures( 111 bool local_initiator, 112 const PairingRequestParams& preq, 113 const PairingResponseParams& pres); 114 115 // Called for SMP commands sent by the peer. 116 void OnPairingResponse(const PairingResponseParams& response_params); 117 118 // PairingChannelHandler callbacks: 119 void OnRxBFrame(ByteBufferPtr sdu) final; OnChannelClosed()120 void OnChannelClosed() final { PairingPhase::HandleChannelClosed(); } 121 122 // PairingPhase overrides ToStringInternal()123 std::string ToStringInternal() override { 124 return bt_lib_cpp_string::StringPrintf( 125 "Pairing Phase 1 (feature exchange) - pairing to %s security with " 126 "\"%s\" IOCapabilities", 127 LevelToString(requested_level_), 128 util::IOCapabilityToString(io_capability_).c_str()); 129 } 130 131 // If acting as the Responder to a peer-initiatied pairing, then |preq_| is 132 // the |preq| ctor parameter. Otherwise, these are generated and exchanged 133 // during Phase 1. 134 std::optional<PairingRequestParams> preq_; 135 std::optional<PairingResponseParams> pres_; 136 137 // Phase 1 ensures that the feature exchange results in a pairing that 138 // supports this level of security. If this is impossible, pairing will abort. 139 SecurityLevel requested_level_; 140 141 // Local feature flags that determine the feature exchange negotiation with 142 // the peer. 143 bool oob_available_; 144 IOCapability io_capability_; 145 BondableMode bondable_mode_; 146 147 CompleteCallback on_complete_; 148 149 BT_DISALLOW_COPY_AND_ASSIGN_ALLOW_MOVE(Phase1); 150 }; 151 152 } // namespace bt::sm 153