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 <cstdint> 19 20 #include "pw_bluetooth_sapphire/internal/host/common/device_address.h" 21 #include "pw_bluetooth_sapphire/internal/host/common/uint128.h" 22 #include "pw_bluetooth_sapphire/internal/host/hci/connection.h" 23 #include "pw_bluetooth_sapphire/internal/host/sm/ecdh_key.h" 24 #include "pw_bluetooth_sapphire/internal/host/sm/pairing_channel.h" 25 #include "pw_bluetooth_sapphire/internal/host/sm/pairing_phase.h" 26 #include "pw_bluetooth_sapphire/internal/host/sm/sc_stage_1.h" 27 #include "pw_bluetooth_sapphire/internal/host/sm/smp.h" 28 #include "pw_bluetooth_sapphire/internal/host/sm/types.h" 29 30 namespace bt::sm { 31 // Phase2SecureConnections encapsulates Phase 2 of LE Secure Connections 32 // Pairing, which takes care of authentication and shared encryption key 33 // generation using FIPS approved ECDH key protocols (see V5.1 Vol. 3 Part H 34 // Section 2.3.5.6). Each Phase2SecureConnections instance generates a new 35 // public-private ECDH key pair, i.e. each Secure Connections pairing uses a 36 // unique ECDH key pair. 37 // 38 // This class is not thread safe and is meant to be accessed on the thread it 39 // was created on. All callbacks will be run by the default dispatcher of a 40 // Phase2SecureConnections's creation thread. 41 class Phase2SecureConnections final : public PairingPhase, 42 public PairingChannelHandler { 43 public: 44 // |chan|, |listener|, and |role|: used to construct the base PairingPhase 45 // |features|: features negotiated in Phase 1 of pairing 46 // |preq, pres|: Exchanged in Phase 1, these are used to generate the DHKey 47 // Check value E. |initiator_addr|, |responder_addr|: 48-bit bd-address of the 48 // initiator and responder, used 49 // used for cryptographic hashing 50 // |cb|: Callback used to notify when the Phase2 has negotiated a new 51 // encryption key. 52 Phase2SecureConnections(PairingChannel::WeakPtr chan, 53 Listener::WeakPtr listener, 54 Role role, 55 PairingFeatures features, 56 PairingRequestParams preq, 57 PairingResponseParams pres, 58 const DeviceAddress& initiator_addr, 59 const DeviceAddress& responder_addr, 60 OnPhase2KeyGeneratedCallback cb); ~Phase2SecureConnections()61 ~Phase2SecureConnections() override { InvalidatePairingChannelHandler(); } 62 63 // Begin Phase 2 of LE Secure Connections pairing. This is called after LE 64 // pairing features are exchanged and results (asynchronously) in the 65 // generation and encryption of a link using the STK. Follows (roughly) the 66 // following steps: 67 // 1. ECDH key exchange to prevent passive eavesdropping attacks. 68 // 2. Generate local random->confirm values, and then exchange 69 // confirm->random values (in the 70 // order written). The random/confirm value generation depends on the 71 // pairing method used. 72 // 3. Generate ECDH key check, and exchange/compare them with the peer to 73 // validate pairing. 74 void Start() final; 75 76 private: 77 // The devices exchange ECDH Public Keys using the below methods (SMP 78 // Section 2.3.5.6.1). 79 void SendLocalPublicKey(); 80 fit::result<ErrorCode> CanReceivePeerPublicKey() const; 81 void OnPeerPublicKey(PairingPublicKeyParams peer_pub_key); 82 83 // After exchanging ECDH Public Keys, the devices perform one of four possible 84 // authentication protocols to prove who they are to each other in Stage 1. 85 // (SMP Section 2.3.5.6.2-3). 86 // TODO(fxbug.dev/42138242): Implement Stage 1 OOB pairing (SMP 87 // Section 2.3.6.5.4). 88 void StartAuthenticationStage1(); 89 void OnAuthenticationStage1Complete( 90 fit::result<ErrorCode, ScStage1::Output> result); 91 92 void OnPairingConfirm(PairingConfirmValue confirm); 93 void OnPairingRandom(PairingRandomValue rand); 94 95 // If Stage 1 completes successfully, this uses the results to perform Stage 2 96 // (i.e. computing the LTK and exchanging DHKey, SMP Section 2.3.5.6.5). 97 void StartAuthenticationStage2(); 98 void SendDhKeyCheckE(); 99 // Receives and stores the peer DH Key check 100 void OnDhKeyCheck(PairingDHKeyCheckValueE dh_key_check); 101 fit::result<ErrorCode> CanReceiveDhKeyCheck() const; 102 // Checks that the received DH key check matches what we calculate locally. 103 void ValidatePeerDhKeyCheck(); 104 105 // l2cap::Channel callback 106 void OnRxBFrame(ByteBufferPtr sdu) final; OnChannelClosed()107 void OnChannelClosed() final { PairingPhase::HandleChannelClosed(); } 108 109 // PairingPhase overrides. ToStringInternal()110 std::string ToStringInternal() override { 111 return bt_lib_cpp_string::StringPrintf( 112 "Secure Connections Pairing Phase 2 (encryption key agreement) - " 113 "pairing with %s method", 114 util::PairingMethodToString(features_.method).c_str()); 115 } 116 is_just_works_or_numeric_comparison()117 bool is_just_works_or_numeric_comparison() const { 118 return features_.method == PairingMethod::kJustWorks || 119 features_.method == PairingMethod::kNumericComparison; 120 } 121 is_passkey_entry()122 bool is_passkey_entry() const { 123 return features_.method == PairingMethod::kPasskeyEntryDisplay || 124 features_.method == PairingMethod::kPasskeyEntryInput; 125 } 126 ecdh_exchange_complete()127 bool ecdh_exchange_complete() const { 128 return sent_local_ecdh_ && peer_ecdh_.has_value(); 129 } stage_1_complete()130 bool stage_1_complete() const { return stage_1_results_.has_value(); } 131 132 bool sent_local_ecdh_; 133 std::optional<LocalEcdhKey> local_ecdh_; 134 std::optional<EcdhKey> peer_ecdh_; 135 136 // Stage 1 of Secure Connections pairing depends on the method used (Just 137 // Works/Numeric Comparison, Passkey Entry, or Out-Of-Band). Each possible 138 // method is implemented as a separate class and takes responsibility for the 139 // entirety of authentication stage 1. 140 std::unique_ptr<ScStage1> stage_1_; 141 std::optional<ScStage1::Output> stage_1_results_; 142 143 bool sent_local_dhkey_check_; 144 std::optional<PairingDHKeyCheckValueE> local_dhkey_check_ = std::nullopt; 145 std::optional<PairingDHKeyCheckValueE> expected_peer_dhkey_check_ = 146 std::nullopt; 147 std::optional<PairingDHKeyCheckValueE> actual_peer_dhkey_check_ = 148 std::nullopt; 149 150 PairingFeatures features_; 151 PairingRequestParams preq_; 152 PairingResponseParams pres_; 153 const DeviceAddress initiator_addr_; 154 const DeviceAddress responder_addr_; 155 std::optional<UInt128> ltk_; 156 157 WeakSelf<Phase2SecureConnections> weak_self_; 158 159 OnPhase2KeyGeneratedCallback on_ltk_ready_; 160 161 BT_DISALLOW_COPY_AND_ASSIGN_ALLOW_MOVE(Phase2SecureConnections); 162 }; 163 164 } // namespace bt::sm 165