• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2024 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 #include "pw_bluetooth_sapphire/internal/host/gap/pairing_state_manager.h"
16 
17 #include <pw_assert/check.h>
18 
19 #include <memory>
20 #include <utility>
21 
22 #include "pw_bluetooth_sapphire/internal/host/common/log.h"
23 #include "pw_bluetooth_sapphire/internal/host/gap/legacy_pairing_state.h"
24 #include "pw_bluetooth_sapphire/internal/host/hci-spec/constants.h"
25 
26 namespace bt::gap {
27 
28 namespace {
29 
30 const char* const kInspectPairingStateTypePropertyName = "pairing_state_type";
31 const char* const kInspectSecureSimplePairingStateNodeName =
32     "secure_simple_pairing_state";
33 const char* const kInspectLegacyPairingStateNodeName = "legacy_pairing_state";
34 
35 }  // namespace
36 
PairingStateManager(Peer::WeakPtr peer,WeakPtr<hci::BrEdrConnection> link,std::unique_ptr<LegacyPairingState> legacy_pairing_state,bool outgoing_connection,fit::closure auth_cb,StatusCallback status_cb,hci::LocalAddressDelegate * low_energy_address_delegate,bool controller_remote_public_key_validation_supported,sm::BrEdrSecurityManagerFactory security_manager_factory,pw::async::Dispatcher & dispatcher)37 PairingStateManager::PairingStateManager(
38     Peer::WeakPtr peer,
39     WeakPtr<hci::BrEdrConnection> link,
40     std::unique_ptr<LegacyPairingState> legacy_pairing_state,
41     bool outgoing_connection,
42     fit::closure auth_cb,
43     StatusCallback status_cb,
44     hci::LocalAddressDelegate* low_energy_address_delegate,
45     bool controller_remote_public_key_validation_supported,
46     sm::BrEdrSecurityManagerFactory security_manager_factory,
47     pw::async::Dispatcher& dispatcher)
48     : peer_(std::move(peer)),
49       link_(std::move(link)),
50       outgoing_connection_(outgoing_connection),
51       auth_cb_(std::move(auth_cb)),
52       status_cb_(std::move(status_cb)),
53       dispatcher_(&dispatcher),
54       low_energy_address_delegate_(low_energy_address_delegate),
55       controller_remote_public_key_validation_supported_(
56           controller_remote_public_key_validation_supported),
57       security_manager_factory_(std::move(security_manager_factory)) {
58   // If |legacy_pairing_state| is non-null, this means we were responding to
59   // Legacy Pairing before the ACL connection between the two devices was
60   // complete
61   if (legacy_pairing_state) {
62     pairing_state_type_ = PairingStateType::kLegacyPairing;
63 
64     // Use |legacy_pairing_state| because it already contains information and
65     // state we want to keep
66     legacy_pairing_state_ = std::move(legacy_pairing_state);
67 
68     // Since PairingStateManager is created when the ACL connection is complete,
69     // we need to initialize |legacy_pairing_state_| with information that we
70     // didn't have until after the connection was complete (e.g. link, auth_cb,
71     // status_cb) and set the connection's link key.
72     legacy_pairing_state_->BuildEstablishedLink(
73         link_, auth_cb_.share(), status_cb_.share());
74 
75     // We should also check that |peer| and |outgoing_connection| are unchanged
76     // before and after connection is complete
77     PW_CHECK(legacy_pairing_state_->peer()->identifier() ==
78              peer_->identifier());
79     PW_CHECK(legacy_pairing_state_->outgoing_connection() ==
80              outgoing_connection);
81   }
82 }
83 
InitiatePairing(BrEdrSecurityRequirements security_requirements,StatusCallback status_cb)84 void PairingStateManager::InitiatePairing(
85     BrEdrSecurityRequirements security_requirements, StatusCallback status_cb) {
86   if (pairing_state_type_ == PairingStateType::kSecureSimplePairing) {
87     secure_simple_pairing_state_->InitiatePairing(security_requirements,
88                                                   std::move(status_cb));
89     return;
90   }
91   if (pairing_state_type_ == PairingStateType::kLegacyPairing) {
92     legacy_pairing_state_->InitiatePairing(std::move(status_cb));
93     return;
94   }
95   bt_log(WARN,
96          "gap",
97          "Trying to initiate pairing without knowing SSP or Legacy. Will not "
98          "initiate.");
99 }
100 
101 std::optional<pw::bluetooth::emboss::IoCapability>
OnIoCapabilityRequest()102 PairingStateManager::OnIoCapabilityRequest() {
103   if (pairing_state_type_ == PairingStateType::kLegacyPairing) {
104     LogSspEventInLegacyPairing(__func__);
105     return std::nullopt;
106   }
107   return secure_simple_pairing_state_->OnIoCapabilityRequest();
108 }
109 
OnIoCapabilityResponse(pw::bluetooth::emboss::IoCapability peer_iocap)110 void PairingStateManager::OnIoCapabilityResponse(
111     pw::bluetooth::emboss::IoCapability peer_iocap) {
112   if (pairing_state_type_ == PairingStateType::kLegacyPairing) {
113     LogSspEventInLegacyPairing(__func__);
114     return;
115   }
116   secure_simple_pairing_state_->OnIoCapabilityResponse(peer_iocap);
117 }
118 
OnUserConfirmationRequest(uint32_t numeric_value,UserConfirmationCallback cb)119 void PairingStateManager::OnUserConfirmationRequest(
120     uint32_t numeric_value, UserConfirmationCallback cb) {
121   if (pairing_state_type_ == PairingStateType::kLegacyPairing) {
122     LogSspEventInLegacyPairing(__func__);
123     return;
124   }
125   secure_simple_pairing_state_->OnUserConfirmationRequest(numeric_value,
126                                                           std::move(cb));
127 }
128 
OnUserPasskeyRequest(UserPasskeyCallback cb)129 void PairingStateManager::OnUserPasskeyRequest(UserPasskeyCallback cb) {
130   if (pairing_state_type_ == PairingStateType::kLegacyPairing) {
131     LogSspEventInLegacyPairing(__func__);
132     return;
133   }
134   secure_simple_pairing_state_->OnUserPasskeyRequest(std::move(cb));
135 }
136 
OnUserPasskeyNotification(uint32_t numeric_value)137 void PairingStateManager::OnUserPasskeyNotification(uint32_t numeric_value) {
138   if (pairing_state_type_ == PairingStateType::kLegacyPairing) {
139     LogSspEventInLegacyPairing(__func__);
140     return;
141   }
142   secure_simple_pairing_state_->OnUserPasskeyNotification(numeric_value);
143 }
144 
OnSimplePairingComplete(pw::bluetooth::emboss::StatusCode status_code)145 void PairingStateManager::OnSimplePairingComplete(
146     pw::bluetooth::emboss::StatusCode status_code) {
147   if (pairing_state_type_ == PairingStateType::kLegacyPairing) {
148     LogSspEventInLegacyPairing(__func__);
149     return;
150   }
151   secure_simple_pairing_state_->OnSimplePairingComplete(status_code);
152 }
153 
OnLinkKeyRequest()154 std::optional<hci_spec::LinkKey> PairingStateManager::OnLinkKeyRequest() {
155   if (pairing_state_type_ == PairingStateType::kSecureSimplePairing) {
156     return secure_simple_pairing_state_->OnLinkKeyRequest();
157   }
158   if (pairing_state_type_ == PairingStateType::kLegacyPairing) {
159     return legacy_pairing_state_->OnLinkKeyRequest();
160   }
161   return std::nullopt;
162 }
163 
OnPinCodeRequest(UserPinCodeCallback cb)164 void PairingStateManager::OnPinCodeRequest(UserPinCodeCallback cb) {
165   if (pairing_state_type_ == PairingStateType::kSecureSimplePairing) {
166     bt_log(WARN,
167            "gap",
168            "Received a Legacy Pairing event for a %u pairing type",
169            static_cast<uint8_t>(pairing_state_type_));
170     cb(std::nullopt);
171     return;
172   }
173   legacy_pairing_state_->OnPinCodeRequest(std::move(cb));
174 }
175 
OnLinkKeyNotification(const UInt128 & link_key,hci_spec::LinkKeyType key_type,bool local_secure_connections_supported)176 void PairingStateManager::OnLinkKeyNotification(
177     const UInt128& link_key,
178     hci_spec::LinkKeyType key_type,
179     bool local_secure_connections_supported) {
180   if (pairing_state_type_ == PairingStateType::kSecureSimplePairing) {
181     secure_simple_pairing_state_->OnLinkKeyNotification(
182         link_key, key_type, local_secure_connections_supported);
183   } else if (pairing_state_type_ == PairingStateType::kLegacyPairing) {
184     legacy_pairing_state_->OnLinkKeyNotification(link_key, key_type);
185   }
186 }
187 
OnAuthenticationComplete(pw::bluetooth::emboss::StatusCode status_code)188 void PairingStateManager::OnAuthenticationComplete(
189     pw::bluetooth::emboss::StatusCode status_code) {
190   if (pairing_state_type_ == PairingStateType::kSecureSimplePairing) {
191     secure_simple_pairing_state_->OnAuthenticationComplete(status_code);
192   } else if (pairing_state_type_ == PairingStateType::kLegacyPairing) {
193     legacy_pairing_state_->OnAuthenticationComplete(status_code);
194   }
195 }
196 
OnEncryptionChange(hci::Result<bool> result)197 void PairingStateManager::OnEncryptionChange(hci::Result<bool> result) {
198   if (pairing_state_type_ == PairingStateType::kSecureSimplePairing) {
199     secure_simple_pairing_state_->OnEncryptionChange(result);
200   } else if (pairing_state_type_ == PairingStateType::kLegacyPairing) {
201     legacy_pairing_state_->OnEncryptionChange(result);
202   }
203 }
204 
CreateOrUpdatePairingState(PairingStateType type,PairingDelegate::WeakPtr pairing_delegate)205 void PairingStateManager::CreateOrUpdatePairingState(
206     PairingStateType type, PairingDelegate::WeakPtr pairing_delegate) {
207   if (type == PairingStateType::kSecureSimplePairing &&
208       !secure_simple_pairing_state_) {
209     secure_simple_pairing_state_ = std::make_unique<SecureSimplePairingState>(
210         peer_,
211         std::move(pairing_delegate),
212         link_,
213         outgoing_connection_,
214         auth_cb_.share(),
215         status_cb_.share(),
216         low_energy_address_delegate_,
217         controller_remote_public_key_validation_supported_,
218         security_manager_factory_,
219         *dispatcher_);
220 
221     secure_simple_pairing_state_->AttachInspect(
222         inspect_node_, kInspectSecureSimplePairingStateNodeName);
223   } else if (type == PairingStateType::kLegacyPairing &&
224              !legacy_pairing_state_) {
225     legacy_pairing_state_ =
226         std::make_unique<LegacyPairingState>(peer_,
227                                              std::move(pairing_delegate),
228                                              link_,
229                                              outgoing_connection_,
230                                              auth_cb_.share(),
231                                              status_cb_.share());
232 
233     legacy_pairing_state_->AttachInspect(inspect_node_,
234                                          kInspectLegacyPairingStateNodeName);
235   }
236   pairing_state_type_ = type;
237   inspect_properties_.pairing_state_type.Set(PairingStateTypeToString(type));
238 }
239 
AttachInspect(inspect::Node & parent,std::string name)240 void PairingStateManager::AttachInspect(inspect::Node& parent,
241                                         std::string name) {
242   inspect_node_ = parent.CreateChild(name);
243   inspect_properties_.pairing_state_type =
244       inspect_node_.CreateString(kInspectPairingStateTypePropertyName,
245                                  PairingStateTypeToString(pairing_state_type_));
246 }
247 
248 }  // namespace bt::gap
249