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