xref: /aosp_15_r20/external/pigweed/pw_bluetooth_sapphire/host/sm/phase_2_legacy.cc (revision 61c4878ac05f98d0ceed94b57d316916de578985)
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 #include "pw_bluetooth_sapphire/internal/host/sm/phase_2_legacy.h"
16 
17 #include <pw_bytes/endian.h>
18 
19 #include <optional>
20 
21 #include "pw_bluetooth_sapphire/internal/host/common/assert.h"
22 #include "pw_bluetooth_sapphire/internal/host/common/log.h"
23 #include "pw_bluetooth_sapphire/internal/host/common/random.h"
24 #include "pw_bluetooth_sapphire/internal/host/common/uint128.h"
25 #include "pw_bluetooth_sapphire/internal/host/hci/connection.h"
26 #include "pw_bluetooth_sapphire/internal/host/sm/delegate.h"
27 #include "pw_bluetooth_sapphire/internal/host/sm/packet.h"
28 #include "pw_bluetooth_sapphire/internal/host/sm/pairing_phase.h"
29 #include "pw_bluetooth_sapphire/internal/host/sm/smp.h"
30 #include "pw_bluetooth_sapphire/internal/host/sm/types.h"
31 #include "pw_bluetooth_sapphire/internal/host/sm/util.h"
32 
33 namespace bt::sm {
34 namespace {
35 // We do not support OOB pairing & Legacy pairing does not permit Numeric
36 // Comparison.
IsSupportedLegacyMethod(PairingMethod method)37 bool IsSupportedLegacyMethod(PairingMethod method) {
38   return (method == PairingMethod::kJustWorks ||
39           method == PairingMethod::kPasskeyEntryDisplay ||
40           method == PairingMethod::kPasskeyEntryInput);
41 }
42 }  // namespace
43 
Phase2Legacy(PairingChannel::WeakPtr chan,Listener::WeakPtr listener,Role role,PairingFeatures features,const ByteBuffer & preq,const ByteBuffer & pres,const DeviceAddress & initiator_add,const DeviceAddress & responder_add,OnPhase2KeyGeneratedCallback cb)44 Phase2Legacy::Phase2Legacy(PairingChannel::WeakPtr chan,
45                            Listener::WeakPtr listener,
46                            Role role,
47                            PairingFeatures features,
48                            const ByteBuffer& preq,
49                            const ByteBuffer& pres,
50                            const DeviceAddress& initiator_add,
51                            const DeviceAddress& responder_add,
52                            OnPhase2KeyGeneratedCallback cb)
53     : PairingPhase(std::move(chan), std::move(listener), role),
54       sent_local_confirm_(false),
55       sent_local_rand_(false),
56       tk_(std::nullopt),
57       local_confirm_(std::nullopt),
58       peer_confirm_(std::nullopt),
59       local_rand_(std::nullopt),
60       peer_rand_(std::nullopt),
61       features_(features),
62       initiator_addr_(initiator_add),
63       responder_addr_(responder_add),
64       on_stk_ready_(std::move(cb)),
65       weak_self_(this) {
66   // Cache |preq| and |pres|. These are used for confirm value generation.
67   PW_CHECK(preq.size() == preq_.size());
68   PW_CHECK(pres.size() == pres_.size());
69   PW_CHECK(IsSupportedLegacyMethod(features.method),
70            "unsupported legacy pairing method!");
71   preq.Copy(&preq_);
72   pres.Copy(&pres_);
73   SetPairingChannelHandler(*this);
74 }
75 
Start()76 void Phase2Legacy::Start() {
77   PW_CHECK(!has_failed());
78   PW_CHECK(!features_.secure_connections);
79   PW_CHECK(!tk_.has_value());
80   PW_CHECK(!peer_confirm_.has_value());
81   PW_CHECK(!peer_rand_.has_value());
82   PW_CHECK(!sent_local_confirm_);
83   PW_CHECK(!sent_local_rand_);
84   MakeTemporaryKeyRequest();
85 }
86 
MakeTemporaryKeyRequest()87 void Phase2Legacy::MakeTemporaryKeyRequest() {
88   bt_log(DEBUG,
89          "sm",
90          "TK request - method: %s",
91          sm::util::PairingMethodToString(features_.method).c_str());
92   PW_CHECK(listener().is_alive());
93   auto self = weak_self_.GetWeakPtr();
94   if (features_.method == sm::PairingMethod::kPasskeyEntryInput) {
95     // The TK will be provided by the user.
96     listener()->RequestPasskey([self](int64_t passkey) {
97       if (!self.is_alive()) {
98         return;
99       }
100       bool success = passkey >= 0;
101       self->HandleTemporaryKey(success ? std::optional<uint32_t>(passkey)
102                                        : std::nullopt);
103     });
104     return;
105   }
106 
107   if (features_.method == sm::PairingMethod::kPasskeyEntryDisplay) {
108     // Randomly generate a 6 digit passkey.
109     uint32_t passkey;
110     random_generator()->GetInt<uint32_t>(passkey,
111                                          /*exclusive_upper_bound=*/1'000'000);
112     listener()->DisplayPasskey(
113         passkey,
114         Delegate::DisplayMethod::kPeerEntry,
115         [passkey, self](bool confirm) {
116           if (!self.is_alive()) {
117             return;
118           }
119           self->HandleTemporaryKey(confirm ? std::optional<uint32_t>(passkey)
120                                            : std::nullopt);
121         });
122     return;
123   }
124 
125   // TODO(fxbug.dev/42138242): Support providing a TK out of band.
126   PW_CHECK(features_.method == sm::PairingMethod::kJustWorks);
127   listener()->ConfirmPairing([self](bool confirm) {
128     if (!self.is_alive()) {
129       return;
130     }
131     self->HandleTemporaryKey(confirm ? std::optional<uint32_t>(0)
132                                      : std::nullopt);
133   });
134 }
135 
HandleTemporaryKey(std::optional<uint32_t> maybe_tk)136 void Phase2Legacy::HandleTemporaryKey(std::optional<uint32_t> maybe_tk) {
137   if (!maybe_tk.has_value()) {
138     bt_log(INFO, "sm", "temporary key listener responded with error; aborting");
139     if (features_.method == PairingMethod::kPasskeyEntryInput) {
140       Abort(ErrorCode::kPasskeyEntryFailed);
141     } else {
142       Abort(ErrorCode::kUnspecifiedReason);
143     }
144     return;
145   }
146   uint32_t tk = *maybe_tk;
147   tk_ = UInt128{0};
148   // Set the lower bits to |tk|.
149   tk = pw::bytes::ConvertOrderTo(cpp20::endian::little, tk);
150   std::memcpy(tk_.value().data(), &tk, sizeof(tk));
151 
152   // We have TK so we can generate the confirm value now.
153   local_rand_ = Random<UInt128>();
154   local_confirm_ = UInt128();
155   util::C1(tk_.value(),
156            local_rand_.value(),
157            preq_,
158            pres_,
159            initiator_addr_,
160            responder_addr_,
161            &(local_confirm_.value()));
162 
163   // If we are the initiator then we just generated the "Mconfirm" value. We
164   // start the exchange by sending this value to the peer. Otherwise this is the
165   // "Sconfirm" value and we either:
166   //    a. send it now if the peer has sent us its confirm value while we were
167   //    waiting for the TK.
168   //    b. send it later when we receive Mconfirm.
169   if (role() == Role::kInitiator || peer_confirm_.has_value()) {
170     SendConfirmValue();
171   }
172 }
173 
SendConfirmValue()174 void Phase2Legacy::SendConfirmValue() {
175   PW_CHECK(!sent_local_confirm_);
176   PW_CHECK(local_confirm_.has_value());
177   // Only allowed on the LE transport.
178   if (sm_chan().link_type() != bt::LinkType::kLE) {
179     bt_log(DEBUG,
180            "sm",
181            "attempted to send confirm value over BR/EDR, not sending");
182     return;
183   }
184 
185   sm_chan().SendMessage(kPairingConfirm, *local_confirm_);
186   sent_local_confirm_ = true;
187 }
188 
OnPairingConfirm(PairingConfirmValue confirm)189 void Phase2Legacy::OnPairingConfirm(PairingConfirmValue confirm) {
190   if (fit::result result = CanReceivePairingConfirm(); result.is_error()) {
191     Abort(result.error_value());
192     return;
193   }
194 
195   peer_confirm_ = confirm;
196 
197   if (role() == Role::kInitiator) {
198     // We MUST have a TK and have previously generated an Mconfirm - this was
199     // implicitly checked in CanReceivePairingConfirm by checking whether we've
200     // sent the confirm value.
201     PW_CHECK(tk_.has_value());
202     PW_CHECK(sent_local_confirm_);
203 
204     // We have sent Mconfirm and just received Sconfirm. We now send Mrand for
205     // the peer to compare.
206     SendRandomValue();
207   } else if (tk_.has_value()) {
208     // We are the responder and have just received Mconfirm. If we already have
209     // a TK, we now send the local confirm to the peer. If not,
210     // HandleTemporaryKey will take care of that.
211     SendConfirmValue();
212   }
213 }
214 
SendRandomValue()215 void Phase2Legacy::SendRandomValue() {
216   PW_CHECK(!sent_local_rand_);
217   // This is always generated in the TK callback, which must have been called by
218   // now as the random are sent after the confirm values, and the TK must exist
219   // in order to send the confirm.
220   PW_CHECK(local_rand_.has_value());
221 
222   // Only allowed on the LE transport.
223   if (sm_chan().link_type() != bt::LinkType::kLE) {
224     bt_log(
225         WARN, "sm", "attempted to send confirm value over BR/EDR, not sending");
226     return;
227   }
228 
229   sm_chan().SendMessage(kPairingRandom, *local_rand_);
230   sent_local_rand_ = true;
231 }
232 
OnPairingRandom(PairingRandomValue rand)233 void Phase2Legacy::OnPairingRandom(PairingRandomValue rand) {
234   if (fit::result result = CanReceivePairingRandom(); result.is_error()) {
235     Abort(result.error_value());
236     return;
237   }
238   // These should have been checked in CanReceivePairingRandom
239   PW_CHECK(local_rand_.has_value());
240   PW_CHECK(tk_.has_value());
241   PW_CHECK(peer_confirm_.has_value());
242 
243   peer_rand_ = rand;
244 
245   // We have the peer's confirm and rand. Verify the peer confirm to validate
246   // the authentication.
247   UInt128 peer_confirm_check;
248   util::C1(tk_.value(),
249            peer_rand_.value(),
250            preq_,
251            pres_,
252            initiator_addr_,
253            responder_addr_,
254            &peer_confirm_check);
255   if (peer_confirm_check != peer_confirm_) {
256     bt_log(WARN,
257            "sm",
258            "%sconfirm value does not match!",
259            role() == Role::kInitiator ? "S" : "M");
260     Abort(ErrorCode::kConfirmValueFailed);
261     return;
262   }
263 
264   // Generate the STK.
265   UInt128 stk;
266   auto [initiator_rand, responder_rand] =
267       util::MapToRoles(*local_rand_, *peer_rand_, role());
268   util::S1(tk_.value(), responder_rand, initiator_rand, &stk);
269 
270   // Mask the key based on the requested encryption key size.
271   uint8_t key_size = features_.encryption_key_size;
272   if (key_size < kMaxEncryptionKeySize) {
273     MutableBufferView view(stk.data() + key_size,
274                            kMaxEncryptionKeySize - key_size);
275     view.SetToZeros();
276   }
277 
278   // We've generated the STK, so Phase 2 is now over if we're the initiator.
279   on_stk_ready_(stk);
280 
281   // As responder, we choose to notify the STK to the higher layer before
282   // sending our SRand. We expect the peer initiator to request encryption
283   // immediately after receiving SRand, and we want to ensure the STK is
284   // available at the hci::Connection layer when this occurs.
285   if (role() == Role::kResponder) {
286     SendRandomValue();
287   }
288 }
289 
CanReceivePairingConfirm() const290 fit::result<ErrorCode> Phase2Legacy::CanReceivePairingConfirm() const {
291   // Only allowed on the LE transport.
292   if (sm_chan().link_type() != bt::LinkType::kLE) {
293     bt_log(DEBUG, "sm", "\"Confirm value\" over BR/EDR not supported!");
294     return fit::error(ErrorCode::kCommandNotSupported);
295   }
296 
297   // Per the message sequence charts in V5.1 Vol. 3 Part H Appendix C.2.1,
298   // reject the pairing confirm value and abort if
299   //    a. we are the initiator, and have not yet sent our confirm value.
300   //    b. we are the responder, and have already sent our confirm value.
301   if ((role() == Role::kInitiator && !sent_local_confirm_) ||
302       (role() == Role::kResponder && sent_local_confirm_)) {
303     bt_log(
304         WARN, "sm", "abort pairing due to confirm value received out of order");
305     return fit::error(ErrorCode::kUnspecifiedReason);
306   }
307 
308   // Legacy pairing only allows for one confirm/random exchange per pairing.
309   if (peer_confirm_.has_value()) {
310     bt_log(WARN, "sm", "already received confirm value! aborting");
311     return fit::error(ErrorCode::kUnspecifiedReason);
312   }
313 
314   // The confirm value shouldn't be sent after the random value. (See spec V5.0
315   // Vol 3, Part H, 2.3.5.5 and Appendix C.2.1.1 for the specific order of
316   // events).
317   if (peer_rand_.has_value() || sent_local_rand_) {
318     bt_log(
319         WARN, "sm", "\"Pairing Confirm\" must come before \"Pairing Random\"");
320     return fit::error(ErrorCode::kUnspecifiedReason);
321   }
322 
323   return fit::ok();
324 }
325 
CanReceivePairingRandom() const326 fit::result<ErrorCode> Phase2Legacy::CanReceivePairingRandom() const {
327   // Only allowed on the LE transport.
328   if (sm_chan().link_type() != bt::LinkType::kLE) {
329     bt_log(DEBUG, "sm", "\"Random value\" over BR/EDR not supported!");
330     return fit::error(ErrorCode::kCommandNotSupported);
331   }
332 
333   if (!tk_.has_value()) {
334     bt_log(
335         WARN, "sm", "abort pairing, random value received before user input");
336     return fit::error(ErrorCode::kUnspecifiedReason);
337   }
338 
339   // V5.0 Vol 3, Part H, 2.3.5.5 dictates that there should be exactly one
340   // pairing random value received by each peer in Legacy Pairing Phase 2.
341   if (peer_rand_.has_value()) {
342     bt_log(WARN, "sm", "already received random value! aborting");
343     return fit::error(ErrorCode::kUnspecifiedReason);
344   }
345 
346   // The random value shouldn't be sent before the confirm value. See V5.0 Vol
347   // 3, Part H, 2.3.5.5 and Appendix C.2.1.1 for the specific order of events.
348   if (!peer_confirm_.has_value()) {
349     bt_log(WARN, "sm", "\"Pairing Rand\" expected after \"Pairing Confirm\"");
350     return fit::error(ErrorCode::kUnspecifiedReason);
351   }
352 
353   if (role() == Role::kInitiator) {
354     // The initiator distributes both values before the responder sends Srandom.
355     if (!sent_local_rand_ || !sent_local_confirm_) {
356       bt_log(WARN, "sm", "\"Pairing Random\" received in wrong order!");
357       return fit::error(ErrorCode::kUnspecifiedReason);
358     }
359   } else {
360     // We know we have not received Mrand, and should not have sent Srand
361     // without receiving Mrand.
362     PW_CHECK(!sent_local_rand_);
363 
364     // We need to send Sconfirm before the initiator sends Mrand.
365     if (!sent_local_confirm_) {
366       bt_log(WARN, "sm", "\"Pairing Random\" received in wrong order!");
367       return fit::error(ErrorCode::kUnspecifiedReason);
368     }
369   }
370 
371   return fit::ok();
372 }
373 
OnRxBFrame(ByteBufferPtr sdu)374 void Phase2Legacy::OnRxBFrame(ByteBufferPtr sdu) {
375   fit::result<ErrorCode, ValidPacketReader> maybe_reader =
376       ValidPacketReader::ParseSdu(sdu);
377   if (maybe_reader.is_error()) {
378     Abort(maybe_reader.error_value());
379     return;
380   }
381   ValidPacketReader reader = maybe_reader.value();
382   Code smp_code = reader.code();
383 
384   if (smp_code == kPairingFailed) {
385     OnFailure(Error(reader.payload<ErrorCode>()));
386   } else if (smp_code == kPairingConfirm) {
387     OnPairingConfirm(reader.payload<PairingConfirmValue>());
388   } else if (smp_code == kPairingRandom) {
389     OnPairingRandom(reader.payload<PairingRandomValue>());
390   } else {
391     bt_log(INFO,
392            "sm",
393            "received unexpected code %#.2X when in Pairing Legacy Phase 2",
394            smp_code);
395     Abort(ErrorCode::kUnspecifiedReason);
396   }
397 }
398 
399 }  // namespace bt::sm
400