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 
17 #include <list>
18 #include <optional>
19 #include <vector>
20 
21 #include "pw_bluetooth_sapphire/internal/host/common/identifier.h"
22 #include "pw_bluetooth_sapphire/internal/host/common/macros.h"
23 #include "pw_bluetooth_sapphire/internal/host/gap/gap.h"
24 #include "pw_bluetooth_sapphire/internal/host/gap/pairing_delegate.h"
25 #include "pw_bluetooth_sapphire/internal/host/gap/peer.h"
26 #include "pw_bluetooth_sapphire/internal/host/gap/types.h"
27 #include "pw_bluetooth_sapphire/internal/host/hci-spec/protocol.h"
28 #include "pw_bluetooth_sapphire/internal/host/hci/bredr_connection.h"
29 #include "pw_bluetooth_sapphire/internal/host/sm/types.h"
30 #include "pw_bluetooth_sapphire/internal/host/transport/error.h"
31 
32 namespace bt::gap {
33 
34 // Represents the local user interaction that will occur, as inferred from Core
35 // Spec v5.0 Vol 3, Part C, Sec 5.2.2.6 (Table 5.7). This is not directly
36 // coupled to the reply action for the HCI "User" event for pairing; e.g.
37 // kDisplayPasskey may mean automatically confirming User Confirmation Request
38 // or displaying the value from User Passkey Notification.
39 enum class PairingAction {
40   // Don't involve the user.
41   kAutomatic,
42 
43   // Request yes/no consent.
44   kGetConsent,
45 
46   // Display 6-digit value with "cancel."
47   kDisplayPasskey,
48 
49   // Display 6-digit value with "yes/no."
50   kComparePasskey,
51 
52   // Request a 6-digit value entry.
53   kRequestPasskey,
54 };
55 
56 // Tracks the pairing state of a peer's BR/EDR link. This drives HCI
57 // transactions and user interactions for pairing in order to obtain the highest
58 // possible level of link security given the capabilities of the controllers
59 // and hosts participating in the pairing.
60 //
61 // This implements Core Spec v5.0 Vol 2, Part F, Sec 4.2 through Sec 4.4, per
62 // logic requirements in Vol 3, Part C, Sec 5.2.2.
63 //
64 // This tracks both the bonded case (both hosts furnish their Link Keys to their
65 // controllers) and the unbonded case (both controllers perform Secure Simple
66 // Pairing and deliver the resulting Link Keys to their hosts).
67 //
68 // Pairing is considered complete when the Link Keys have been used to
69 // successfully encrypt the link, at which time pairing may be restarted (e.g.
70 // with different capabilities).
71 //
72 // This state machine navigates the following HCI message sequences, in which
73 // both the host subsystem and the Link Manager use knowledge of both peers' IO
74 // Capabilities and Authentication Requirements to decide on the same
75 // association model.
76 // ▶ means command.
77 // ◀ means event.
78 //
79 // Initiator flow
80 // --------------
81 // Authentication Requested▶
82 // (◀ Authentication Complete with an error is possible at any time after this)
83 //     ◀ Link Key Request
84 // Link Key Request Reply▶ (skip to "Authentication Complete")
85 //     or
86 // Link Key Request Negative Reply▶ (continue with pairing)
87 //     ◀ Command Complete
88 //     ◀ IO Capability Request
89 // (◀ Simple Pairing Complete with an error is possible at any time after this)
90 // IO Capability Request Reply▶
91 //     or
92 // IO Capability Request Negative Reply▶ (reject pairing)
93 //     ◀ Command Complete
94 //     ◀ IO Capability Response
95 //     ◀ User Confirmation Request
96 //         or
97 //     ◀ User Passkey Request
98 //         or
99 //     ◀ User Passkey Notification
100 //         or
101 //     ◀ Remote OOB Data Request
102 // User Confirmation Request Reply▶
103 //     or
104 // User Confirmation Request Negative Reply▶ (reject pairing)
105 //     or
106 // User Passkey Request Reply▶
107 //     or
108 // User Passkey Request Negative Reply▶ (reject pairing)
109 //     or
110 // Remote OOB Data Request Reply▶
111 //     or
112 // Remote OOB Extended Data Request Reply▶
113 //     or
114 // Remote OOB Data Request Negative Reply▶ (reject pairing)
115 //     ◀ Simple Pairing Complete (status may be error)
116 //     ◀ Link Key Notification (key may be insufficient)
117 //     ◀ Authentication Complete (status may be error)
118 //       If status is PIN or Key missing, return to:
119 //         Authentication Requested▶ (use Link Key Request Negative Reply)
120 // Set Connection Encryption▶
121 //     ◀ Command Status
122 //     ◀ Encryption Change (status may be error or encryption may be disabled)
123 //
124 // Responder flow
125 // --------------
126 // If initiator has key:
127 //     ◀ Link Key Request
128 // Link Key Request Reply▶ (skip to "Encryption Change")
129 //     or
130 // Link Key Request Negative Reply▶ (Authentication failed, skip pairing)
131 //
132 // If initiator doesn't have key:
133 //     ◀ IO Capability Response
134 //     ◀ IO Capability Request
135 // (◀ Simple Pairing Complete with an error is possible at any time after this)
136 // IO Capability Request Reply▶
137 //     or
138 // IO Capability Request Negative Reply▶ (reject pairing)
139 //     ◀ Command Complete
140 // Pairing
141 //     ◀ User Confirmation Request
142 //         or
143 //     ◀ User Passkey Request
144 //         or
145 //     ◀ User Passkey Notification
146 //         or
147 //     ◀ Remote OOB Data Request
148 // User Confirmation Request Reply▶
149 //     or
150 // User Confirmation Request Negative Reply▶ (reject pairing)
151 //     or
152 // User Passkey Request Reply▶
153 //     or
154 // User Passkey Request Negative Reply▶ (reject pairing)
155 //     or
156 // Remote OOB Data Request Reply▶
157 //     or
158 // Remote OOB Extended Data Request Reply▶
159 //     or
160 // Remote OOB Data Request Negative Reply▶ (reject pairing)
161 //     ◀ Simple Pairing Complete (status may contain error)
162 //     ◀ Link Key Notification (key may be insufficient)
163 // Set Connection Encryption▶
164 //     ◀ Command Status
165 //     ◀ Encryption Change (status may be error or encryption may be disabled)
166 //
167 // This class is not thread-safe and should only be called on the thread on
168 // which it was created.
169 class SecureSimplePairingState final {
170  public:
171   // Used to report the status of each pairing procedure on this link. |status|
172   // will contain HostError::kNotSupported if the pairing procedure does not
173   // proceed in the order of events expected.
174   using StatusCallback =
175       fit::function<void(hci_spec::ConnectionHandle, hci::Result<>)>;
176 
177   // Constructs a SecureSimplePairingState for the ACL connection |link| to
178   // |peer_id|. |outgoing_connection| should be true if this device connected,
179   // and false if it was an incoming connection. This object will receive
180   // "encryption change" callbacks associate with |peer_id|. Successful pairing
181   // is reported through |status_cb| after encryption is enabled. When errors
182   // occur, this object will be put in a "failed" state and the owner shall
183   // disconnect the link and destroy its SecureSimplePairingState.  When
184   // destroyed, status callbacks for any waiting pairings are called.
185   // |status_cb| is not called on destruction.
186   //
187   // |auth_cb| will be called to indicate that the caller should send an
188   // Authentication Request for this peer.
189   //
190   // |link| must be valid for the lifetime of this object.
191   SecureSimplePairingState(Peer::WeakPtr peer,
192                            PairingDelegate::WeakPtr pairing_delegate,
193                            WeakPtr<hci::BrEdrConnection> link,
194                            bool outgoing_connection,
195                            fit::closure auth_cb,
196                            StatusCallback status_cb);
197   SecureSimplePairingState(SecureSimplePairingState&&) = default;
198   SecureSimplePairingState& operator=(SecureSimplePairingState&&) = default;
199   ~SecureSimplePairingState();
200 
201   // True if there is currently a pairing procedure in progress that the local
202   // device initiated.
initiator()203   bool initiator() const {
204     return is_pairing() ? current_pairing_->initiator : false;
205   }
206 
207   // Set a handler for user-interactive authentication challenges. If not set or
208   // set to nullptr, all pairing requests will be rejected, but this does not
209   // cause a fatal error and should not result in link disconnection.
210   //
211   // If the delegate indicates passkey display capabilities, then it will always
212   // be asked to confirm pairing, even when Core Spec v5.0, Vol 3, Part C,
213   // Section 5.2.2.6 indicates "automatic confirmation."
SetPairingDelegate(PairingDelegate::WeakPtr pairing_delegate)214   void SetPairingDelegate(PairingDelegate::WeakPtr pairing_delegate) {
215     pairing_delegate_ = std::move(pairing_delegate);
216   }
217 
218   // Starts pairing against the peer, if pairing is not already in progress.
219   // If not, this device becomes the pairing initiator. If pairing is in
220   // progress, the request will be queued until the current pairing completes or
221   // an additional pairing that upgrades the link key succeeds or fails.
222   //
223   // If no PairingDelegate is available, |status_cb| is immediately called with
224   // HostError::kNotReady, but the SecureSimplePairingState status callback
225   // (provided in the ctor) is not called.
226   //
227   // When pairing completes or errors out, the |status_cb| of each call to this
228   // function will be invoked with the result.
229   void InitiatePairing(BrEdrSecurityRequirements security_requirements,
230                        StatusCallback status_cb);
231 
232   // Event handlers. Caller must ensure that the event is addressed to the link
233   // for this SecureSimplePairingState.
234 
235   // Returns value for IO Capability Request Reply, else std::nullopt for IO
236   // Capability Negative Reply.
237   //
238   // TODO(fxbug.dev/42138242): Indicate presence of out-of-band (OOB) data.
239   [[nodiscard]] std::optional<pw::bluetooth::emboss::IoCapability>
240   OnIoCapabilityRequest();
241 
242   // Caller is not expected to send a response.
243   void OnIoCapabilityResponse(pw::bluetooth::emboss::IoCapability peer_iocap);
244 
245   // |cb| is called with: true to send User Confirmation Request Reply, else
246   // for to send User Confirmation Request Negative Reply. It may be called from
247   // a different thread than the one that called OnUserConfirmationRequest.
248   using UserConfirmationCallback = fit::callback<void(bool confirm)>;
249   void OnUserConfirmationRequest(uint32_t numeric_value,
250                                  UserConfirmationCallback cb);
251 
252   // |cb| is called with: passkey value to send User Passkey Request Reply, else
253   // std::nullopt to send User Passkey Request Negative Reply. It may not be
254   // called from the same thread that called OnUserPasskeyRequest.
255   using UserPasskeyCallback =
256       fit::callback<void(std::optional<uint32_t> passkey)>;
257   void OnUserPasskeyRequest(UserPasskeyCallback cb);
258 
259   // Caller is not expected to send a response.
260   void OnUserPasskeyNotification(uint32_t numeric_value);
261 
262   // Caller is not expected to send a response.
263   void OnSimplePairingComplete(pw::bluetooth::emboss::StatusCode status_code);
264 
265   // Caller should send the returned link key in a Link Key Request Reply (or
266   // Link Key Request Negative Reply if the returned value is null).
267   [[nodiscard]] std::optional<hci_spec::LinkKey> OnLinkKeyRequest();
268 
269   // Caller is not expected to send a response.
270   void OnLinkKeyNotification(const UInt128& link_key,
271                              hci_spec::LinkKeyType key_type,
272                              bool local_secure_connections_supported = false);
273 
274   // Caller is not expected to send a response.
275   void OnAuthenticationComplete(pw::bluetooth::emboss::StatusCode status_code);
276 
277   // Handler for hci::Connection::set_encryption_change_callback.
278   void OnEncryptionChange(hci::Result<bool> result);
279 
security_properties()280   sm::SecurityProperties& security_properties() { return bredr_security_; }
281 
282   // Sets the BR/EDR Security Mode of the pairing state - see enum definition
283   // for details of each mode. If a security upgrade is in-progress, only takes
284   // effect on the next security upgrade.
set_security_mode(gap::BrEdrSecurityMode mode)285   void set_security_mode(gap::BrEdrSecurityMode mode) { security_mode_ = mode; }
286 
287   // Attach pairing state inspect node named |name| as a child of |parent|.
288   void AttachInspect(inspect::Node& parent, std::string name);
289 
290  private:
291   // Current security properties of the ACL-U link.
292   sm::SecurityProperties bredr_security_;
293 
294   enum class State {
295     // Wait for initiator's IO Capability Response, Link Key Request, or for
296     // locally-initiated
297     // pairing.
298     kIdle,
299 
300     // As initiator, wait for Link Key Request.
301     kInitiatorWaitLinkKeyRequest,
302 
303     // As initiator, wait for IO Capability Request.
304     kInitiatorWaitIoCapRequest,
305 
306     // As initiator, wait for IO Capability Response.
307     kInitiatorWaitIoCapResponse,
308 
309     // As responder, wait for IO Capability Request.
310     kResponderWaitIoCapRequest,
311 
312     // Wait for controller event for pairing action. Only one of these will
313     // occur in a given pairing
314     // (see class documentation for pairing flow).
315     kWaitUserConfirmationRequest,
316     kWaitUserPasskeyRequest,
317     kWaitUserPasskeyNotification,
318 
319     // Wait for Simple Pairing Complete.
320     kWaitPairingComplete,
321 
322     // Wait for Link Key Notification.
323     kWaitLinkKey,
324 
325     // As initiator, wait for Authentication Complete.
326     kInitiatorWaitAuthComplete,
327 
328     // Wait for Encryption Change.
329     kWaitEncryption,
330 
331     // Error occurred; wait for link closure and ignore events.
332     kFailed,
333   };
334 
335   // Extra information for pairing constructed when a pairing procedure begins
336   // and destroyed when the pairing procedure is reset or errors out.
337   //
338   // Instances must be heap allocated so that they can be moved without
339   // destruction, preserving their WeakPtr holders. WeakPtrs are vended to
340   // PairingDelegate callbacks to uniquely identify each attempt to pair because
341   // |current_pairing_| is not synchronized to the user's actions through
342   // PairingDelegate.
343   class Pairing final {
344    public:
345     static std::unique_ptr<Pairing> MakeInitiator(
346         BrEdrSecurityRequirements security_requirements,
347         bool outgoing_connection);
348     static std::unique_ptr<Pairing> MakeResponder(
349         pw::bluetooth::emboss::IoCapability peer_iocap, bool link_inititated);
350     // Make a responder for a peer that has initiated a pairing (asked for our
351     // key while in idle)
352     static std::unique_ptr<Pairing> MakeResponderForBonded();
353 
354     // For a Pairing whose |initiator|, |local_iocap|, and |peer_iocap| are
355     // already set, compute and set |action|, |expected_event|, |authenticated|,
356     // and |security_properties| for the pairing procedure and bonding data that
357     // we expect.
358     void ComputePairingData();
359 
360     // Used to prevent PairingDelegate callbacks from using captured stale
361     // pointers.
362     using WeakPtr = WeakSelf<Pairing>::WeakPtr;
GetWeakPtr()363     Pairing::WeakPtr GetWeakPtr() { return weak_self_.GetWeakPtr(); }
364 
365     // True if the local device initiated pairing.
366     bool initiator;
367 
368     // True if we allow automatic pairing. (when outgoing connection and not
369     // re-pairing)
370     bool allow_automatic;
371 
372     // IO Capability obtained from the pairing delegate.
373     pw::bluetooth::emboss::IoCapability local_iocap;
374 
375     // IO Capability from peer through IO Capability Response.
376     pw::bluetooth::emboss::IoCapability peer_iocap;
377 
378     // User interaction to perform after receiving HCI user event.
379     PairingAction action;
380 
381     // HCI event to respond to in order to complete or reject pairing.
382     hci_spec::EventCode expected_event;
383 
384     // inclusive-language: ignore
385     // True if this pairing is expected to be resistant to MITM attacks.
386     bool authenticated;
387 
388     // Security properties of the link key received from the controller.
389     std::optional<sm::SecurityProperties> security_properties;
390 
391     // If the preferred security is greater than the existing link key, a new
392     // link key will be negotiated (which may still have insufficient security
393     // properties).
394     BrEdrSecurityRequirements preferred_security;
395 
396    private:
Pairing(bool automatic)397     explicit Pairing(bool automatic)
398         : allow_automatic(automatic), weak_self_(this) {}
399 
400     WeakSelf<Pairing> weak_self_;
401   };
402 
403   static const char* ToString(State state);
404 
405   // Returns state for the three pairing action events, kFailed otherwise.
406   static State GetStateForPairingEvent(hci_spec::EventCode event_code);
407 
408   // Peer for this pairing.
peer_id()409   PeerId peer_id() const { return peer_id_; }
410 
state()411   State state() const { return state_; }
412 
is_pairing()413   bool is_pairing() const { return current_pairing_ != nullptr; }
414 
handle()415   hci_spec::ConnectionHandle handle() const { return link_->handle(); }
416 
417   // Returns nullptr if the delegate is not set or no longer alive.
pairing_delegate()418   const PairingDelegate::WeakPtr& pairing_delegate() const {
419     return pairing_delegate_;
420   }
421 
422   // Call the permanent status callback this object was created with as well as
423   // any completed request callbacks from local initiators. Resets the current
424   // pairing and may initiate a new pairing if any requests have not been
425   // completed. |caller| is used for logging.
426   void SignalStatus(hci::Result<> status, const char* caller);
427 
428   // Determines which pairing requests have been completed by the current link
429   // key and/or status and removes them from the queue. If any pairing requests
430   // were not completed, starts a new pairing procedure. Returns a list of
431   // closures that call the status callbacks of completed pairing requests.
432   std::vector<fit::closure> CompletePairingRequests(hci::Result<> status);
433 
434   // Starts the pairing procedure for the next queued pairing request, if any.
435   void InitiateNextPairingRequest();
436 
437   // Called to enable encryption on the link for this peer. Sets |state_| to
438   // kWaitEncryption.
439   void EnableEncryption();
440 
441   // Called when an event is received while in a state that doesn't expect that
442   // event. Invokes |status_callback_| with HostError::kNotSupported and sets
443   // |state_| to kFailed. Logs an error using |handler_name| for identification.
444   void FailWithUnexpectedEvent(const char* handler_name);
445 
446   // Returns true when the peer's host and peer's controller support Secure
447   // Connections
448   bool IsPeerSecureConnectionsSupported() const;
449 
450   PeerId peer_id_;
451   Peer::WeakPtr peer_;
452 
453   // The current GAP security mode of the device (v5.2 Vol. 3 Part C
454   // Section 5.2.2)
455   gap::BrEdrSecurityMode security_mode_;
456 
457   // The BR/EDR link whose pairing is being driven by this object.
458   WeakPtr<hci::BrEdrConnection> link_;
459 
460   // True when the BR/EDR |link_| was locally requested.
461   bool outgoing_connection_;
462 
463   // True when the remote device has reported it doesn't have a link key.
464   bool peer_missing_key_;
465 
466   PairingDelegate::WeakPtr pairing_delegate_;
467 
468   // State machine representation.
469   State state_;
470 
471   std::unique_ptr<Pairing> current_pairing_;
472 
473   struct PairingRequest {
474     // Security properties required by the pairing initiator for pairing to be
475     // considered a success.
476     BrEdrSecurityRequirements security_requirements;
477 
478     // Callback called when the pairing procedure is complete.
479     StatusCallback status_callback;
480   };
481   // Represents ongoing and queued pairing requests. Will contain a value when
482   // the state isn't kIdle or kFailed. Requests may be completed out-of-order as
483   // their security requirements are satisfied.
484   std::list<PairingRequest> request_queue_;
485 
486   // Callback used to indicate an Authentication Request for this peer should be
487   // sent.
488   fit::closure send_auth_request_callback_;
489 
490   // Callback that status of this pairing is reported back through.
491   StatusCallback status_callback_;
492 
493   // Cleanup work that should occur only once per connection; uniqueness is
494   // guaranteed by being moved with SecureSimplePairingState. |self| shall be a
495   // pointer to the moved-to instance being cleaned up.
496   fit::callback<void(SecureSimplePairingState* self)> cleanup_cb_;
497 
498   struct InspectProperties {
499     inspect::StringProperty encryption_status;
500   };
501   InspectProperties inspect_properties_;
502   inspect::Node inspect_node_;
503 
504   BT_DISALLOW_COPY_AND_ASSIGN_ALLOW_MOVE(SecureSimplePairingState);
505 };
506 
507 PairingAction GetInitiatorPairingAction(
508     pw::bluetooth::emboss::IoCapability initiator_cap,
509     pw::bluetooth::emboss::IoCapability responder_cap);
510 PairingAction GetResponderPairingAction(
511     pw::bluetooth::emboss::IoCapability initiator_cap,
512     pw::bluetooth::emboss::IoCapability responder_cap);
513 hci_spec::EventCode GetExpectedEvent(
514     pw::bluetooth::emboss::IoCapability local_cap,
515     pw::bluetooth::emboss::IoCapability peer_cap);
516 bool IsPairingAuthenticated(pw::bluetooth::emboss::IoCapability local_cap,
517                             pw::bluetooth::emboss::IoCapability peer_cap);
518 
519 // Get the Authentication Requirements for a locally-initiated pairing according
520 // to Core Spec v5.0, Vol 2, Part E, Sec 7.1.29.
521 //
522 // Non-Bondable Mode and Dedicated Bonding over BR/EDR are not supported and
523 // this always returns kMITMGeneralBonding if |local_cap| is not
524 // kNoInputNoOutput, kGeneralBonding otherwise. This requests authentication
525 // when possible (based on IO Capabilities), as we don't know the peer's
526 // authentication requirements yet.
527 pw::bluetooth::emboss::AuthenticationRequirements
528 GetInitiatorAuthenticationRequirements(
529     pw::bluetooth::emboss::IoCapability local_cap);
530 
531 // Get the Authentication Requirements for a peer-initiated pairing. This will
532 // inclusive-language: ignore
533 // request MITM protection whenever possible to obtain an "authenticated" link
534 // encryption key.
535 //
536 // Local service requirements and peer authentication bonding type should be
537 // available by the time this is called, but Non-Bondable Mode and Dedicated
538 // Bonding over BR/EDR are not supported, so this always returns
539 // kMITMGeneralBonding if this pairing can result in an authenticated link key,
540 // kGeneralBonding otherwise.
541 pw::bluetooth::emboss::AuthenticationRequirements
542 GetResponderAuthenticationRequirements(
543     pw::bluetooth::emboss::IoCapability local_cap,
544     pw::bluetooth::emboss::IoCapability remote_cap);
545 
546 }  // namespace bt::gap
547