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