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 // inclusive-language: disable
16
17 #include "pw_bluetooth_sapphire/internal/host/sm/phase_1.h"
18
19 #include "pw_bluetooth_sapphire/internal/host/common/assert.h"
20 #include "pw_bluetooth_sapphire/internal/host/common/byte_buffer.h"
21 #include "pw_bluetooth_sapphire/internal/host/common/log.h"
22 #include "pw_bluetooth_sapphire/internal/host/hci-spec/constants.h"
23 #include "pw_bluetooth_sapphire/internal/host/hci-spec/protocol.h"
24 #include "pw_bluetooth_sapphire/internal/host/hci/connection.h"
25 #include "pw_bluetooth_sapphire/internal/host/l2cap/scoped_channel.h"
26 #include "pw_bluetooth_sapphire/internal/host/sm/packet.h"
27 #include "pw_bluetooth_sapphire/internal/host/sm/smp.h"
28 #include "pw_bluetooth_sapphire/internal/host/sm/types.h"
29 #include "pw_bluetooth_sapphire/internal/host/sm/util.h"
30
31 namespace bt::sm {
32
CreatePhase1Initiator(PairingChannel::WeakPtr chan,Listener::WeakPtr listener,IOCapability io_capability,BondableMode bondable_mode,SecurityLevel requested_level,CompleteCallback on_complete)33 std::unique_ptr<Phase1> Phase1::CreatePhase1Initiator(
34 PairingChannel::WeakPtr chan,
35 Listener::WeakPtr listener,
36 IOCapability io_capability,
37 BondableMode bondable_mode,
38 SecurityLevel requested_level,
39 CompleteCallback on_complete) {
40 // Use `new` & unique_ptr constructor here instead of `std::make_unique`
41 // because the private Phase1 constructor prevents std::make_unique from
42 // working (https://abseil.io/tips/134).
43 return std::unique_ptr<Phase1>(new Phase1(std::move(chan),
44 std::move(listener),
45 Role::kInitiator,
46 std::nullopt,
47 io_capability,
48 bondable_mode,
49 requested_level,
50 std::move(on_complete)));
51 }
52
CreatePhase1Responder(PairingChannel::WeakPtr chan,Listener::WeakPtr listener,PairingRequestParams preq,IOCapability io_capability,BondableMode bondable_mode,SecurityLevel minimum_allowed_level,CompleteCallback on_complete)53 std::unique_ptr<Phase1> Phase1::CreatePhase1Responder(
54 PairingChannel::WeakPtr chan,
55 Listener::WeakPtr listener,
56 PairingRequestParams preq,
57 IOCapability io_capability,
58 BondableMode bondable_mode,
59 SecurityLevel minimum_allowed_level,
60 CompleteCallback on_complete) {
61 // Use `new` & unique_ptr constructor here instead of `std::make_unique`
62 // because the private Phase1 constructor prevents std::make_unique from
63 // working (https://abseil.io/tips/134).
64 return std::unique_ptr<Phase1>(new Phase1(std::move(chan),
65 std::move(listener),
66 Role::kResponder,
67 preq,
68 io_capability,
69 bondable_mode,
70 minimum_allowed_level,
71 std::move(on_complete)));
72 }
73
Phase1(PairingChannel::WeakPtr chan,Listener::WeakPtr listener,Role role,std::optional<PairingRequestParams> preq,IOCapability io_capability,BondableMode bondable_mode,SecurityLevel requested_level,CompleteCallback on_complete)74 Phase1::Phase1(PairingChannel::WeakPtr chan,
75 Listener::WeakPtr listener,
76 Role role,
77 std::optional<PairingRequestParams> preq,
78 IOCapability io_capability,
79 BondableMode bondable_mode,
80 SecurityLevel requested_level,
81 CompleteCallback on_complete)
82 : PairingPhase(std::move(chan), std::move(listener), role),
83 preq_(preq),
84 requested_level_(requested_level),
85 oob_available_(false),
86 io_capability_(io_capability),
87 bondable_mode_(bondable_mode),
88 on_complete_(std::move(on_complete)) {
89 PW_CHECK(!(role == Role::kInitiator && preq_.has_value()));
90 PW_CHECK(!(role == Role::kResponder && !preq_.has_value()));
91 PW_CHECK(requested_level_ >= SecurityLevel::kEncrypted);
92 if (requested_level_ > SecurityLevel::kEncrypted) {
93 PW_CHECK(io_capability != IOCapability::kNoInputNoOutput);
94 }
95 SetPairingChannelHandler(*this);
96 }
97
Start()98 void Phase1::Start() {
99 PW_CHECK(!has_failed());
100 if (role() == Role::kResponder) {
101 PW_CHECK(preq_.has_value());
102 RespondToPairingRequest(*preq_);
103 return;
104 }
105 PW_CHECK(!preq_.has_value());
106 InitiateFeatureExchange();
107 }
108
InitiateFeatureExchange()109 void Phase1::InitiateFeatureExchange() {
110 // Only the initiator can initiate the feature exchange.
111 PW_CHECK(role() == Role::kInitiator);
112 LocalPairingParams preq_values = BuildPairingParameters();
113 preq_ = PairingRequestParams{
114 .io_capability = preq_values.io_capability,
115 .oob_data_flag = preq_values.oob_data_flag,
116 .auth_req = preq_values.auth_req,
117 .max_encryption_key_size = preq_values.max_encryption_key_size,
118 .initiator_key_dist_gen = preq_values.local_keys,
119 .responder_key_dist_gen = preq_values.remote_keys};
120 sm_chan().SendMessage(kPairingRequest, *preq_);
121 }
122
RespondToPairingRequest(const PairingRequestParams & req_params)123 void Phase1::RespondToPairingRequest(const PairingRequestParams& req_params) {
124 // We should only be in this state when pairing is initiated by the remote
125 // i.e. we are the responder.
126 PW_CHECK(role() == Role::kResponder);
127
128 LocalPairingParams pres_values = BuildPairingParameters();
129 pres_ = PairingResponseParams{
130 .io_capability = pres_values.io_capability,
131 .oob_data_flag = pres_values.oob_data_flag,
132 .auth_req = pres_values.auth_req,
133 .max_encryption_key_size = pres_values.max_encryption_key_size,
134 .initiator_key_dist_gen = 0,
135 .responder_key_dist_gen = 0};
136 // The keys that will be exchanged correspond to the intersection of what the
137 // initiator requests and we support.
138 pres_->initiator_key_dist_gen =
139 pres_values.remote_keys & req_params.initiator_key_dist_gen;
140 pres_->responder_key_dist_gen =
141 pres_values.local_keys & req_params.responder_key_dist_gen;
142
143 fit::result<ErrorCode, PairingFeatures> maybe_features =
144 ResolveFeatures(/*local_initiator=*/false, req_params, *pres_);
145 if (maybe_features.is_error()) {
146 bt_log(DEBUG, "sm", "rejecting pairing features");
147 Abort(maybe_features.error_value());
148 return;
149 }
150 PairingFeatures features = maybe_features.value();
151 // If we've accepted a non-bondable pairing request in bondable mode as
152 // indicated by setting features.will_bond false, we should reflect that in
153 // the rsp_params we send to the peer.
154 if (!features.will_bond && bondable_mode_ == BondableMode::Bondable) {
155 pres_->auth_req &= ~AuthReq::kBondingFlag;
156 }
157
158 sm_chan().SendMessage(kPairingResponse, *pres_);
159
160 on_complete_(features, *preq_, *pres_);
161 }
162
BuildPairingParameters()163 LocalPairingParams Phase1::BuildPairingParameters() {
164 // We build `local_params` to reflect the capabilities of this device over the
165 // LE transport.
166 LocalPairingParams local_params;
167 if (sm_chan().SupportsSecureConnections()) {
168 local_params.auth_req |= AuthReq::kSC;
169 }
170 if (requested_level_ >= SecurityLevel::kAuthenticated) {
171 local_params.auth_req |= AuthReq::kMITM;
172 }
173
174 // If we are in non-bondable mode there will be no key distribution per V5.1
175 // Vol 3 Part C Section 9.4.2.2, so we use the default "no keys" value for
176 // LocalPairingParams.
177 if (bondable_mode_ == BondableMode::Bondable) {
178 local_params.auth_req |= AuthReq::kBondingFlag;
179 // We always request identity information from the remote.
180 local_params.remote_keys = KeyDistGen::kIdKey;
181
182 PW_CHECK(listener().is_alive());
183 if (listener()->OnIdentityRequest().has_value()) {
184 local_params.local_keys |= KeyDistGen::kIdKey;
185 }
186
187 // For the current connection, the responder-generated encryption keys (LTK)
188 // is always used. As device roles may change in future connections, Fuchsia
189 // supports distribution and generation of LTKs by both the local and remote
190 // device (V5.0 Vol. 3 Part H 2.4.2.3).
191 local_params.remote_keys |= KeyDistGen::kEncKey;
192 local_params.local_keys |= KeyDistGen::kEncKey;
193
194 // If we support SC over LE, we always try to generate the cross-transport
195 // BR/EDR key by setting the link key bit (V5.0 Vol. 3 Part H 3.6.1).
196 if (local_params.auth_req & AuthReq::kSC) {
197 local_params.local_keys |= KeyDistGen::kLinkKey;
198 local_params.remote_keys |= KeyDistGen::kLinkKey;
199 }
200 }
201 // The CT2 bit indicates support for the 2nd Cross-Transport Key Derivation
202 // hashing function, a.k.a. H7 (v5.2 Vol. 3 Part H 3.5.1 and 2.4.2.4).
203 local_params.auth_req |= AuthReq::kCT2;
204 local_params.io_capability = io_capability_;
205 local_params.oob_data_flag =
206 oob_available_ ? OOBDataFlag::kPresent : OOBDataFlag::kNotPresent;
207 return local_params;
208 }
209
ResolveFeatures(bool local_initiator,const PairingRequestParams & preq,const PairingResponseParams & pres)210 fit::result<ErrorCode, PairingFeatures> Phase1::ResolveFeatures(
211 bool local_initiator,
212 const PairingRequestParams& preq,
213 const PairingResponseParams& pres) {
214 // Select the smaller of the initiator and responder max. encryption key size
215 // values (Vol 3, Part H, 2.3.4).
216 uint8_t enc_key_size =
217 std::min(preq.max_encryption_key_size, pres.max_encryption_key_size);
218 uint8_t min_allowed_enc_key_size =
219 (requested_level_ == SecurityLevel::kSecureAuthenticated)
220 ? kMaxEncryptionKeySize
221 : kMinEncryptionKeySize;
222 if (enc_key_size < min_allowed_enc_key_size) {
223 bt_log(DEBUG, "sm", "encryption key size too small! (%u)", enc_key_size);
224 return fit::error(ErrorCode::kEncryptionKeySize);
225 }
226
227 bool will_bond =
228 (preq.auth_req & kBondingFlag) && (pres.auth_req & kBondingFlag);
229 if (!will_bond) {
230 bt_log(
231 INFO,
232 "sm",
233 "negotiated non-bondable pairing (local mode: %s)",
234 bondable_mode_ == BondableMode::Bondable ? "bondable" : "non-bondable");
235 }
236 bool sc = (preq.auth_req & AuthReq::kSC) && (pres.auth_req & AuthReq::kSC);
237 bool mitm =
238 (preq.auth_req & AuthReq::kMITM) || (pres.auth_req & AuthReq::kMITM);
239 bool init_oob = preq.oob_data_flag == OOBDataFlag::kPresent;
240 bool rsp_oob = pres.oob_data_flag == OOBDataFlag::kPresent;
241
242 IOCapability local_ioc, peer_ioc;
243 if (local_initiator) {
244 local_ioc = preq.io_capability;
245 peer_ioc = pres.io_capability;
246 } else {
247 local_ioc = pres.io_capability;
248 peer_ioc = preq.io_capability;
249 }
250
251 PairingMethod method = util::SelectPairingMethod(
252 sc, init_oob, rsp_oob, mitm, local_ioc, peer_ioc, local_initiator);
253
254 // If MITM protection is required but the pairing method cannot provide MITM,
255 // then reject the pairing.
256 if (mitm && method == PairingMethod::kJustWorks) {
257 return fit::error(ErrorCode::kAuthenticationRequirements);
258 }
259
260 // The "Pairing Response" command (i.e. |pres|) determines the keys that shall
261 // be distributed. The keys that will be distributed by us and the peer
262 // depends on whichever one initiated the feature exchange by sending a
263 // "Pairing Request" command.
264 KeyDistGenField local_keys, remote_keys;
265 if (local_initiator) {
266 local_keys = pres.initiator_key_dist_gen;
267 remote_keys = pres.responder_key_dist_gen;
268
269 // v5.1, Vol 3, Part H Section 3.6.1 requires that the responder shall not
270 // set to one any flag in the key dist gen fields that the initiator has set
271 // to zero. Hence we reject the pairing if the responder requests keys that
272 // we don't support.
273 if ((preq.initiator_key_dist_gen & local_keys) != local_keys ||
274 (preq.responder_key_dist_gen & remote_keys) != remote_keys) {
275 return fit::error(ErrorCode::kInvalidParameters);
276 }
277 } else {
278 local_keys = pres.responder_key_dist_gen;
279 remote_keys = pres.initiator_key_dist_gen;
280
281 // When we are the responder we always respect the initiator's wishes.
282 PW_CHECK((preq.initiator_key_dist_gen & remote_keys) == remote_keys);
283 PW_CHECK((preq.responder_key_dist_gen & local_keys) == local_keys);
284 }
285 // v5.1 Vol 3 Part C Section 9.4.2.2 says that bonding information shall not
286 // be exchanged or stored in non-bondable mode. This check ensures that we
287 // avoid a situation where, if we were in bondable mode and a peer requested
288 // non-bondable mode with a non-zero keydistgen field, we pair in non-bondable
289 // mode but also attempt to distribute keys.
290 if (!will_bond && (local_keys || remote_keys)) {
291 return fit::error(ErrorCode::kInvalidParameters);
292 }
293
294 // "If both [...] devices support [LE] Secure Connections [...] the devices
295 // may optionally generate the BR/EDR key [..] as part of the LE pairing
296 // procedure" (v5.2 Vol. 3 Part C 14.1).
297 std::optional<CrossTransportKeyAlgo> generate_ct_key = std::nullopt;
298 if (sc) {
299 // "In LE Secure Connections pairing, when SMP is running on the LE
300 // transport, then the EncKey field is ignored" (V5.0 Vol. 3 Part H 3.6.1).
301 // We ignore the Encryption Key bit here to allow for uniform handling of it
302 // later.
303 local_keys &= ~KeyDistGen::kEncKey;
304 remote_keys &= ~KeyDistGen::kEncKey;
305
306 // "When hci_spec::LinkKey is set to 1 by both devices in the initiator and
307 // responder [KeyDistGen] fields, the procedures for calculating the BR/EDR
308 // link key from the LTK shall be used". The chosen procedure depends on the
309 // CT2 bit of the AuthReq (v5.2 Vol. 3 Part H 3.5.1 and 3.6.1).
310 if (local_keys & remote_keys & KeyDistGen::kLinkKey) {
311 generate_ct_key =
312 (preq.auth_req & AuthReq::kCT2) && (pres.auth_req & AuthReq::kCT2)
313 ? CrossTransportKeyAlgo::kUseH7
314 : CrossTransportKeyAlgo::kUseH6;
315 }
316
317 } else if (requested_level_ == SecurityLevel::kSecureAuthenticated) {
318 // SecureAuthenticated means Secure Connections is required, so if this
319 // pairing would not use Secure Connections it does not meet the
320 // requirements of `requested_level_`
321 return fit::error(ErrorCode::kAuthenticationRequirements);
322 }
323
324 return fit::ok(PairingFeatures{.initiator = local_initiator,
325 .secure_connections = sc,
326 .will_bond = will_bond,
327 .generate_ct_key = generate_ct_key,
328 .method = method,
329 .encryption_key_size = enc_key_size,
330 .local_key_distribution = local_keys,
331 .remote_key_distribution = remote_keys});
332 }
333
OnPairingResponse(const PairingResponseParams & response_params)334 void Phase1::OnPairingResponse(const PairingResponseParams& response_params) {
335 // Support receiving a pairing response only as the initiator.
336 if (role() == Role::kResponder) {
337 bt_log(DEBUG, "sm", "received pairing response when acting as responder");
338 Abort(ErrorCode::kCommandNotSupported);
339 return;
340 }
341
342 if (!preq_.has_value() || pres_.has_value()) {
343 bt_log(DEBUG, "sm", "ignoring unexpected \"Pairing Response\" packet");
344 Abort(ErrorCode::kUnspecifiedReason);
345 return;
346 }
347
348 fit::result<ErrorCode, PairingFeatures> maybe_features =
349 ResolveFeatures(/*local_initiator=*/true, *preq_, response_params);
350
351 if (maybe_features.is_error()) {
352 bt_log(DEBUG, "sm", "rejecting pairing features");
353 Abort(maybe_features.error_value());
354 return;
355 }
356 PairingFeatures features = maybe_features.value();
357 pres_ = response_params;
358 on_complete_(features, *preq_, *pres_);
359 }
360
OnRxBFrame(ByteBufferPtr sdu)361 void Phase1::OnRxBFrame(ByteBufferPtr sdu) {
362 fit::result<ErrorCode, ValidPacketReader> maybe_reader =
363 ValidPacketReader::ParseSdu(sdu);
364 if (maybe_reader.is_error()) {
365 Abort(maybe_reader.error_value());
366 return;
367 }
368 ValidPacketReader reader = maybe_reader.value();
369 Code smp_code = reader.code();
370
371 if (smp_code == kPairingFailed) {
372 OnFailure(Error(reader.payload<ErrorCode>()));
373 } else if (smp_code == kPairingResponse) {
374 OnPairingResponse(reader.payload<PairingResponseParams>());
375 } else {
376 bt_log(INFO,
377 "sm",
378 "received unexpected code %#.2X when in Pairing Phase 1",
379 smp_code);
380 Abort(ErrorCode::kUnspecifiedReason);
381 }
382 }
383
384 } // namespace bt::sm
385