blob: 3ffccd88ab5fbd3d87d00a8566c350ba532746b7 [file] [log] [blame]
// 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_2_SECURE_CONNECTIONS_H_
#define SRC_CONNECTIVITY_BLUETOOTH_CORE_BT_HOST_SM_PHASE_2_SECURE_CONNECTIONS_H_
#include <lib/async/cpp/task.h>
#include <lib/fit/function.h>
#include <cstdint>
#include "src/connectivity/bluetooth/core/bt-host/common/device_address.h"
#include "src/connectivity/bluetooth/core/bt-host/common/uint128.h"
#include "src/connectivity/bluetooth/core/bt-host/hci/connection.h"
#include "src/connectivity/bluetooth/core/bt-host/sm/ecdh_key.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/sc_stage_1.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 {
// Phase2SecureConnections encapsulates Phase 2 of LE Secure Connections Pairing, which takes care
// of authentication and shared encryption key generation using FIPS approved ECDH key protocols
// (see V5.1 Vol. 3 Part H Section 2.3.5.6). Each Phase2SecureConnections instance generates a new
// public-private ECDH key pair, i.e. each Secure Connections pairing uses a unique ECDH key pair.
//
// 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 Phase2SecureConnections's creation thread.
class Phase2SecureConnections final : public PairingPhase, public PairingChannelHandler {
public:
// |chan|, |listener|, and |role|: used to construct the base PairingPhase
// |features|: features negotiated in Phase 1 of pairing
// |preq, pres|: Exchanged in Phase 1, these are used to generate the DHKey Check value E.
// |initiator_addr|, |responder_addr|: 48-bit bd-address of the initiator and responder, used
// used for cryptographic hashing
// |cb|: Callback used to notify when the Phase2 has negotiated a new encryption key.
Phase2SecureConnections(fxl::WeakPtr<PairingChannel> chan, fxl::WeakPtr<Listener> listener,
Role role, PairingFeatures features, PairingRequestParams preq,
PairingResponseParams pres, const DeviceAddress& initiator_addr,
const DeviceAddress& responder_addr, OnPhase2KeyGeneratedCallback cb);
~Phase2SecureConnections() override = default;
// Begin Phase 2 of LE Secure Connections pairing. This is called after LE pairing features are
// exchanged and results (asynchronously) in the generation and encryption of a link using the
// STK. Follows (roughly) the following steps:
// 1. ECDH key exchange to prevent passive eavesdropping attacks.
// 2. Generate local random->confirm values, and then exchange confirm->random values (in the
// order written). The random/confirm value generation depends on the pairing method used.
// 3. Generate ECDH key check, and exchange/compare them with the peer to validate pairing.
void Start() final;
private:
// The devices exchange ECDH Public Keys using the below methods (SMP Section 2.3.5.6.1).
void SendLocalPublicKey();
ErrorCode CanReceivePeerPublicKey() const;
void OnPeerPublicKey(PairingPublicKeyParams peer_pub_key);
// After exchanging ECDH Public Keys, the devices perform one of four possible authentication
// protocols to prove who they are to each other in Stage 1. (SMP Section 2.3.5.6.2-3).
// TODO(fxbug.dev/601): Implement Stage 1 OOB pairing (SMP Section 2.3.6.5.4).
void StartAuthenticationStage1();
void OnAuthenticationStage1Complete(fit::result<ScStage1::Output, ErrorCode> result);
void OnPairingConfirm(PairingConfirmValue confirm);
void OnPairingRandom(PairingRandomValue rand);
// If Stage 1 completes successfully, this uses the results to perform Stage 2 (i.e. computing
// the LTK and exchanging DHKey, SMP Section 2.3.5.6.5).
void StartAuthenticationStage2();
void SendDhKeyCheckE();
// Receives and stores the peer DH Key check
void OnDhKeyCheck(PairingDHKeyCheckValueE dh_key_check);
ErrorCode CanReceiveDhKeyCheck() const;
// Checks that the received DH key check matches what we calculate locally.
void ValidatePeerDhKeyCheck();
// l2cap::Channel callback
void OnRxBFrame(ByteBufferPtr sdu) final;
void OnChannelClosed() final { PairingPhase::HandleChannelClosed(); }
// PairingPhase overrides.
fxl::WeakPtr<PairingChannelHandler> AsChannelHandler() final {
return weak_ptr_factory_.GetWeakPtr();
}
std::string ToStringInternal() override {
return fxl::StringPrintf(
"Secure Connections Pairing Phase 2 (encryption key agreement) - pairing with %s method",
util::PairingMethodToString(features_.method).c_str());
}
bool is_just_works_or_numeric_comparison() const {
return features_.method == PairingMethod::kJustWorks ||
features_.method == PairingMethod::kNumericComparison;
}
bool is_passkey_entry() const {
return features_.method == PairingMethod::kPasskeyEntryDisplay ||
features_.method == PairingMethod::kPasskeyEntryInput;
}
bool ecdh_exchange_complete() const { return sent_local_ecdh_ && peer_ecdh_.has_value(); }
bool stage_1_complete() const { return stage_1_results_.has_value(); }
bool sent_local_ecdh_;
std::optional<LocalEcdhKey> local_ecdh_;
std::optional<EcdhKey> peer_ecdh_;
// Stage 1 of Secure Connections pairing depends on the method used (Just Works/Numeric
// Comparison, Passkey Entry, or Out-Of-Band). Each possible method is implemented as a separate
// class and takes responsibility for the entirety of authentication stage 1.
std::unique_ptr<ScStage1> stage_1_;
std::optional<ScStage1::Output> stage_1_results_;
bool sent_local_dhkey_check_;
std::optional<PairingDHKeyCheckValueE> local_dhkey_check_ = std::nullopt;
std::optional<PairingDHKeyCheckValueE> expected_peer_dhkey_check_ = std::nullopt;
std::optional<PairingDHKeyCheckValueE> actual_peer_dhkey_check_ = std::nullopt;
PairingFeatures features_;
PairingRequestParams preq_;
PairingResponseParams pres_;
const DeviceAddress initiator_addr_;
const DeviceAddress responder_addr_;
std::optional<UInt128> ltk_;
fxl::WeakPtrFactory<Phase2SecureConnections> weak_ptr_factory_;
OnPhase2KeyGeneratedCallback on_ltk_ready_;
DISALLOW_COPY_AND_ASSIGN_ALLOW_MOVE(Phase2SecureConnections);
};
} // namespace bt::sm
#endif // SRC_CONNECTIVITY_BLUETOOTH_CORE_BT_HOST_SM_PHASE_2_SECURE_CONNECTIONS_H_