| // Copyright 2020 The Fuchsia Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #ifndef SRC_CONNECTIVITY_BLUETOOTH_CORE_BT_HOST_SM_PHASE_3_H_ |
| #define SRC_CONNECTIVITY_BLUETOOTH_CORE_BT_HOST_SM_PHASE_3_H_ |
| |
| #include <lib/async/cpp/task.h> |
| #include <lib/fit/function.h> |
| |
| #include "src/connectivity/bluetooth/core/bt-host/common/device_address.h" |
| #include "src/connectivity/bluetooth/core/bt-host/hci/connection.h" |
| #include "src/connectivity/bluetooth/core/bt-host/sm/pairing_channel.h" |
| #include "src/connectivity/bluetooth/core/bt-host/sm/pairing_phase.h" |
| #include "src/connectivity/bluetooth/core/bt-host/sm/smp.h" |
| #include "src/connectivity/bluetooth/core/bt-host/sm/types.h" |
| #include "src/lib/fxl/memory/weak_ptr.h" |
| |
| namespace bt::sm { |
| |
| // Represents Phase 3 of SM pairing. In this phase, the keys the devices agreed to distribute |
| // during Phase 1 are exchanged. Phase 3 must take place on an already-encrypted link. |
| // |
| // THREAD SAFETY |
| // |
| // This class is not thread safe and is meant to be accessed on the thread it |
| // was created on. All callbacks will be run by the default dispatcher of a |
| // Phase3's creation thread. |
| |
| using Phase3CompleteCallback = fit::function<void(PairingData)>; |
| |
| class Phase3 final : public PairingPhase, public PairingChannelHandler { |
| public: |
| // Initializes Phase3 with the following parameters: |
| // - |chan|: The L2CAP SMP fixed channel. |
| // - |role|: The local device's HCI role. |
| // - |listener|: The current Phase's listener. |
| // - |io_capability|: The local I/O capability. |
| // - |features|: The features that determine pairing, negotiated during Phase 1. There must be |
| // some keys to distribute if Phase3 exists - construction will panic if both the local & |
| // remote key_distribution fields of features are 0. |
| // - |le_sec|: The current security properties of key encrypting the link. |
| Phase3(fxl::WeakPtr<PairingChannel> chan, fxl::WeakPtr<Listener> listener, Role role, |
| PairingFeatures features, SecurityProperties le_sec, Phase3CompleteCallback on_complete); |
| ~Phase3() override = default; |
| |
| // Performs the key distribution phase of pairing. |
| void Start() final; |
| |
| private: |
| // Called when the Encryption Info (i.e. the LTK) is received from the peer. |
| void OnEncryptionInformation(const EncryptionInformationParams& ltk); |
| |
| // Called when EDiv and Rand values are received from the peer. |
| void OnMasterIdentification(const MasterIdentificationParams& params); |
| |
| // Called when the "Identity Resolving Key" is received from the peer. |
| void OnIdentityInformation(const IRK& irk); |
| |
| // Called when the "Identity Address" is received from the peer. |
| void OnIdentityAddressInformation(const IdentityAddressInformationParams& params); |
| |
| // Called whenever a complete key is received from the peer. |
| void OnExpectedKeyReceived(); |
| |
| // Called to send all agreed upon keys to the peer during Phase 3. Returns false if an error |
| // occurs and pairing should be aborted. |
| bool SendLocalKeys(); |
| |
| // Only used during legacy pairing. Returns false if the command cannot be sent. |
| bool SendEncryptionKey(); |
| |
| // Sends the identity information. Returns false if the command cannot be sent. |
| bool SendIdentityInfo(); |
| |
| // Called to collect all pairing keys and notify the callback that we are complete |
| void SignalComplete(); |
| |
| // l2cap::Channel callbacks: |
| void OnChannelClosed() final { PairingPhase::HandleChannelClosed(); }; |
| void OnRxBFrame(ByteBufferPtr sdu) final; |
| |
| // True if all keys that are expected from the remote have been received. |
| bool RequestedKeysObtained() const; |
| |
| // True if all local keys that were agreed to be distributed have been sent to the peer. |
| bool LocalKeysSent() const; |
| |
| bool KeyExchangeComplete() const { return RequestedKeysObtained() && LocalKeysSent(); } |
| bool ShouldReceiveLtk() const; // True if peer should send the LTK |
| bool ShouldReceiveIdentity() const; // True if peer should send identity |
| bool ShouldSendLtk() const; // True if we should send the LTK |
| bool ShouldSendIdentity() const; // True if we should send identity info |
| |
| // PairingPhase override |
| fxl::WeakPtr<PairingChannelHandler> AsChannelHandler() final { |
| return weak_ptr_factory_.GetWeakPtr(); |
| } |
| |
| std::string ToStringInternal() override { |
| return fxl::StringPrintf( |
| "Pairing Phase 3 (security key distribution) - paired with %s security properties, sending " |
| "0x%02X local key distribution value and expecting 0x%02X as peer key distribution value", |
| le_sec_.ToString().c_str(), features_.local_key_distribution, |
| features_.remote_key_distribution); |
| } |
| |
| const PairingFeatures features_; |
| |
| // Current security properties of the LE-U link. |
| const SecurityProperties le_sec_; |
| |
| // The remote keys that have been obtained so far. |
| KeyDistGenField obtained_remote_keys_; |
| |
| // True if all the local keys in features_ have been sent to the peer. |
| bool sent_local_keys_; |
| |
| // Generated and distributed if the EncKey bit of the local device's KeyDistGenField is set. |
| std::optional<LTK> local_ltk_; |
| |
| // Data from the peer tracked during Phase 3. Parts of the LTK are received in separate events. |
| // The LTK is only received in Legacy pairing. |
| std::optional<UInt128> peer_ltk_bytes_; // LTK without ediv/rand. |
| std::optional<LTK> peer_ltk_; // Full LTK with ediv/rand |
| std::optional<IRK> irk_; |
| std::optional<DeviceAddress> identity_address_; |
| |
| const Phase3CompleteCallback on_complete_; |
| |
| fxl::WeakPtrFactory<Phase3> weak_ptr_factory_; |
| |
| DISALLOW_COPY_AND_ASSIGN_ALLOW_MOVE(Phase3); |
| }; |
| |
| } // namespace bt::sm |
| |
| #endif // SRC_CONNECTIVITY_BLUETOOTH_CORE_BT_HOST_SM_PHASE_3_H_ |