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 #include <list> 17 #include <optional> 18 #include <vector> 19 20 #include "pw_bluetooth_sapphire/internal/host/common/identifier.h" 21 #include "pw_bluetooth_sapphire/internal/host/common/macros.h" 22 #include "pw_bluetooth_sapphire/internal/host/gap/gap.h" 23 #include "pw_bluetooth_sapphire/internal/host/gap/pairing_delegate.h" 24 #include "pw_bluetooth_sapphire/internal/host/gap/peer_cache.h" 25 #include "pw_bluetooth_sapphire/internal/host/gap/types.h" 26 #include "pw_bluetooth_sapphire/internal/host/hci-spec/protocol.h" 27 #include "pw_bluetooth_sapphire/internal/host/hci/bredr_connection.h" 28 #include "pw_bluetooth_sapphire/internal/host/sm/smp.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 PairingState 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 PairingState for the ACL connection |link| to |peer_id|. 178 // |link_initiated| should be true if this device connected, and false if it 179 // was an incoming connection. 180 // This object will receive "encryption change" callbacks associate with 181 // |peer_id|. Successful pairing is reported through |status_cb| after 182 // encryption is enabled. When errors occur, this object will be put in a 183 // "failed" state and the owner shall disconnect the link and destroy its 184 // PairingState. When destroyed, status callbacks for any waiting pairings 185 // are called. |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 PairingState(Peer::WeakPtr peer, 192 hci::BrEdrConnection* link, 193 bool link_initiated, 194 fit::closure auth_cb, 195 StatusCallback status_cb); 196 PairingState(PairingState&&) = default; 197 PairingState& operator=(PairingState&&) = default; 198 ~PairingState(); 199 200 // True if there is currently a pairing procedure in progress that the local 201 // device initiated. initiator()202 bool initiator() const { 203 return is_pairing() ? current_pairing_->initiator : false; 204 } 205 206 // Set a handler for user-interactive authentication challenges. If not set or 207 // set to nullptr, all pairing requests will be rejected, but this does not 208 // cause a fatal error and should not result in link disconnection. 209 // 210 // If the delegate indicates passkey display capabilities, then it will always 211 // be asked to confirm pairing, even when Core Spec v5.0, Vol 3, Part C, 212 // Section 5.2.2.6 indicates "automatic confirmation." SetPairingDelegate(PairingDelegate::WeakPtr pairing_delegate)213 void SetPairingDelegate(PairingDelegate::WeakPtr pairing_delegate) { 214 pairing_delegate_ = std::move(pairing_delegate); 215 } 216 217 // Starts pairing against the peer, if pairing is not already in progress. 218 // If not, this device becomes the pairing initiator. If pairing is in 219 // progress, the request will be queued until the current pairing completes or 220 // an additional pairing that upgrades the link key succeeds or fails. 221 // 222 // If no PairingDelegate is available, |status_cb| is immediately called with 223 // HostError::kNotReady, but the PairingState status callback (provided in the 224 // ctor) is not called. 225 // 226 // When pairing completes or errors out, the |status_cb| of each call to this 227 // function will be invoked with the result. 228 void InitiatePairing(BrEdrSecurityRequirements security_requirements, 229 StatusCallback status_cb); 230 231 // Event handlers. Caller must ensure that the event is addressed to the link 232 // for this PairingState. 233 234 // Returns value for IO Capability Request Reply, else std::nullopt for IO 235 // Capability Negative Reply. 236 // 237 // TODO(fxbug.dev/42138242): Indicate presence of out-of-band (OOB) data. 238 [[nodiscard]] std::optional<pw::bluetooth::emboss::IoCapability> 239 OnIoCapabilityRequest(); 240 241 // Caller is not expected to send a response. 242 void OnIoCapabilityResponse(pw::bluetooth::emboss::IoCapability peer_iocap); 243 244 // |cb| is called with: true to send User Confirmation Request Reply, else 245 // for to send User Confirmation Request Negative Reply. It may be called from 246 // a different thread than the one that called OnUserConfirmationRequest. 247 using UserConfirmationCallback = fit::callback<void(bool confirm)>; 248 void OnUserConfirmationRequest(uint32_t numeric_value, 249 UserConfirmationCallback cb); 250 251 // |cb| is called with: passkey value to send User Passkey Request Reply, else 252 // std::nullopt to send User Passkey Request Negative Reply. It may not be 253 // called from the same thread that called OnUserPasskeyRequest. 254 using UserPasskeyCallback = 255 fit::callback<void(std::optional<uint32_t> passkey)>; 256 void OnUserPasskeyRequest(UserPasskeyCallback cb); 257 258 // Caller is not expected to send a response. 259 void OnUserPasskeyNotification(uint32_t numeric_value); 260 261 // Caller is not expected to send a response. 262 void OnSimplePairingComplete(pw::bluetooth::emboss::StatusCode status_code); 263 264 // Caller should send the returned link key in a Link Key Request Reply (or 265 // Link Key Request Negative Reply if the returned value is null). 266 [[nodiscard]] std::optional<hci_spec::LinkKey> OnLinkKeyRequest(); 267 268 // Caller is not expected to send a response. 269 void OnLinkKeyNotification(const UInt128& link_key, 270 hci_spec::LinkKeyType key_type, 271 bool local_secure_connections_supported = false); 272 273 // Caller is not expected to send a response. 274 void OnAuthenticationComplete(pw::bluetooth::emboss::StatusCode status_code); 275 276 // Handler for hci::Connection::set_encryption_change_callback. 277 void OnEncryptionChange(hci::Result<bool> result); 278 set_security_properties(sm::SecurityProperties & security)279 void set_security_properties(sm::SecurityProperties& security) { 280 bredr_security_ = security; 281 } security_properties()282 sm::SecurityProperties& security_properties() { return bredr_security_; } 283 284 // Sets the BR/EDR Security Mode of the pairing state - see enum definition 285 // for details of each mode. If a security upgrade is in-progress, only takes 286 // effect on the next security upgrade. set_security_mode(gap::BrEdrSecurityMode mode)287 void set_security_mode(gap::BrEdrSecurityMode mode) { security_mode_ = mode; } security_mode()288 gap::BrEdrSecurityMode security_mode() const { return security_mode_; } 289 290 // Attach pairing state inspect node named |name| as a child of |parent|. 291 void AttachInspect(inspect::Node& parent, std::string name); 292 293 private: 294 // Current security properties of the ACL-U link. 295 sm::SecurityProperties bredr_security_; 296 297 enum class State { 298 // Wait for initiator's IO Capability Response, Link Key Request, or for 299 // locally-initiated 300 // pairing. 301 kIdle, 302 303 // As initiator, wait for Link Key Request. 304 kInitiatorWaitLinkKeyRequest, 305 306 // As initiator, wait for IO Capability Request. 307 kInitiatorWaitIoCapRequest, 308 309 // As initiator, wait for IO Capability Response. 310 kInitiatorWaitIoCapResponse, 311 312 // As responder, wait for IO Capability Request. 313 kResponderWaitIoCapRequest, 314 315 // Wait for controller event for pairing action. Only one of these will 316 // occur in a given pairing 317 // (see class documentation for pairing flow). 318 kWaitUserConfirmationRequest, 319 kWaitUserPasskeyRequest, 320 kWaitUserPasskeyNotification, 321 322 // Wait for Simple Pairing Complete. 323 kWaitPairingComplete, 324 325 // Wait for Link Key Notification. 326 kWaitLinkKey, 327 328 // As initiator, wait for Authentication Complete. 329 kInitiatorWaitAuthComplete, 330 331 // Wait for Encryption Change. 332 kWaitEncryption, 333 334 // Error occurred; wait for link closure and ignore events. 335 kFailed, 336 }; 337 338 // Extra information for pairing constructed when a pairing procedure begins 339 // and destroyed when the pairing procedure is reset or errors out. 340 // 341 // Instances must be heap allocated so that they can be moved without 342 // destruction, preserving their WeakPtr holders. WeakPtrs are vended to 343 // PairingDelegate callbacks to uniquely identify each attempt to pair because 344 // |current_pairing_| is not synchronized to the user's actions through 345 // PairingDelegate. 346 class Pairing final { 347 public: 348 static std::unique_ptr<Pairing> MakeInitiator( 349 BrEdrSecurityRequirements security_requirements, bool link_initiated); 350 static std::unique_ptr<Pairing> MakeResponder( 351 pw::bluetooth::emboss::IoCapability peer_iocap, bool link_inititated); 352 // Make a responder for a peer that has initiated a pairing (asked for our 353 // key while in idle) 354 static std::unique_ptr<Pairing> MakeResponderForBonded(); 355 356 // For a Pairing whose |initiator|, |local_iocap|, and |peer_iocap| are 357 // already set, compute and set |action|, |expected_event|, |authenticated|, 358 // and |security_properties| for the pairing procedure and bonding data that 359 // we expect. 360 void ComputePairingData(); 361 362 // Used to prevent PairingDelegate callbacks from using captured stale 363 // pointers. 364 using WeakPtr = WeakSelf<Pairing>::WeakPtr; GetWeakPtr()365 Pairing::WeakPtr GetWeakPtr() { return weak_self_.GetWeakPtr(); } 366 367 // True if the local device initiated pairing. 368 bool initiator; 369 370 // True if we allow automatic pairing. (when outgoing connection and not 371 // re-pairing) 372 bool allow_automatic; 373 374 // IO Capability obtained from the pairing delegate. 375 pw::bluetooth::emboss::IoCapability local_iocap; 376 377 // IO Capability from peer through IO Capability Response. 378 pw::bluetooth::emboss::IoCapability peer_iocap; 379 380 // User interaction to perform after receiving HCI user event. 381 PairingAction action; 382 383 // HCI event to respond to in order to complete or reject pairing. 384 hci_spec::EventCode expected_event; 385 386 // inclusive-language: ignore 387 // True if this pairing is expected to be resistant to MITM attacks. 388 bool authenticated; 389 390 // Security properties of the link key received from the controller. 391 std::optional<sm::SecurityProperties> security_properties; 392 393 // If the preferred security is greater than the existing link key, a new 394 // link key will be negotiated (which may still have insufficient security 395 // properties). 396 BrEdrSecurityRequirements preferred_security; 397 398 private: Pairing(bool automatic)399 explicit Pairing(bool automatic) 400 : allow_automatic(automatic), weak_self_(this) {} 401 402 WeakSelf<Pairing> weak_self_; 403 }; 404 405 static const char* ToString(State state); 406 407 // Returns state for the three pairing action events, kFailed otherwise. 408 static State GetStateForPairingEvent(hci_spec::EventCode event_code); 409 410 // Peer for this pairing. peer_id()411 PeerId peer_id() const { return peer_id_; } 412 state()413 State state() const { return state_; } 414 is_pairing()415 bool is_pairing() const { return current_pairing_ != nullptr; } 416 handle()417 hci_spec::ConnectionHandle handle() const { return link_->handle(); } 418 419 // Returns nullptr if the delegate is not set or no longer alive. pairing_delegate()420 const PairingDelegate::WeakPtr& pairing_delegate() const { 421 return pairing_delegate_; 422 } 423 424 // Call the permanent status callback this object was created with as well as 425 // any completed request callbacks from local initiators. Resets the current 426 // pairing and may initiate a new pairing if any requests have not been 427 // completed. |caller| is used for logging. 428 void SignalStatus(hci::Result<> status, const char* caller); 429 430 // Determines which pairing requests have been completed by the current link 431 // key and/or status and removes them from the queue. If any pairing requests 432 // were not completed, starts a new pairing procedure. Returns a list of 433 // closures that call the status callbacks of completed pairing requests. 434 std::vector<fit::closure> CompletePairingRequests(hci::Result<> status); 435 436 // Starts the pairing procedure for the next queued pairing request, if any. 437 void InitiateNextPairingRequest(); 438 439 // Called to enable encryption on the link for this peer. Sets |state_| to 440 // kWaitEncryption. 441 void EnableEncryption(); 442 443 // Called when an event is received while in a state that doesn't expect that 444 // event. Invokes |status_callback_| with HostError::kNotSupported and sets 445 // |state_| to kFailed. Logs an error using |handler_name| for identification. 446 void FailWithUnexpectedEvent(const char* handler_name); 447 448 // Compute the expected pairing event and state to occur after receiving the 449 // peer IO Capability and write it to |current_pairing_| (which must exist). 450 void WritePairingData(); 451 452 // Returns true when the peer's host and peer's controller support Secure 453 // Connections 454 bool IsPeerSecureConnectionsSupported() const; 455 456 PeerId peer_id_; 457 Peer::WeakPtr peer_; 458 459 // The current GAP security mode of the device (v5.2 Vol. 3 Part C 460 // Section 5.2.2) 461 gap::BrEdrSecurityMode security_mode_; 462 463 // The BR/EDR link whose pairing is being driven by this object. 464 hci::BrEdrConnection* link_; 465 466 // True when the BR/EDR |link_| was locally requested. 467 bool outgoing_connection_; 468 469 // True when the remote device has reported it doesn't have a link key. 470 bool peer_missing_key_; 471 472 PairingDelegate::WeakPtr pairing_delegate_; 473 474 // State machine representation. 475 State state_; 476 477 std::unique_ptr<Pairing> current_pairing_; 478 479 struct PairingRequest { 480 // Security properties required by the pairing initiator for pairing to be 481 // considered a success. 482 BrEdrSecurityRequirements security_requirements; 483 484 // Callback called when the pairing procedure is complete. 485 StatusCallback status_callback; 486 }; 487 // Represents ongoing and queued pairing requests. Will contain a value when 488 // the state isn't kIdle or kFailed. Requests may be completed out-of-order as 489 // their security requirements are satisfied. 490 std::list<PairingRequest> request_queue_; 491 492 // Callback used to indicate an Authentication Request for this peer should be 493 // sent. 494 fit::closure send_auth_request_callback_; 495 496 // Callback that status of this pairing is reported back through. 497 StatusCallback status_callback_; 498 499 // Cleanup work that should occur only once per connection; uniqueness is 500 // guaranteed by being moved with PairingState. |self| shall be a pointer to 501 // the moved-to instance being cleaned up. 502 fit::callback<void(PairingState* self)> cleanup_cb_; 503 504 struct InspectProperties { 505 inspect::StringProperty encryption_status; 506 }; 507 InspectProperties inspect_properties_; 508 inspect::Node inspect_node_; 509 510 BT_DISALLOW_COPY_AND_ASSIGN_ALLOW_MOVE(PairingState); 511 }; 512 513 PairingAction GetInitiatorPairingAction( 514 pw::bluetooth::emboss::IoCapability initiator_cap, 515 pw::bluetooth::emboss::IoCapability responder_cap); 516 PairingAction GetResponderPairingAction( 517 pw::bluetooth::emboss::IoCapability initiator_cap, 518 pw::bluetooth::emboss::IoCapability responder_cap); 519 hci_spec::EventCode GetExpectedEvent( 520 pw::bluetooth::emboss::IoCapability local_cap, 521 pw::bluetooth::emboss::IoCapability peer_cap); 522 bool IsPairingAuthenticated(pw::bluetooth::emboss::IoCapability local_cap, 523 pw::bluetooth::emboss::IoCapability peer_cap); 524 525 // Get the Authentication Requirements for a locally-initiated pairing according 526 // to Core Spec v5.0, Vol 2, Part E, Sec 7.1.29. 527 // 528 // Non-Bondable Mode and Dedicated Bonding over BR/EDR are not supported and 529 // this always returns kMITMGeneralBonding if |local_cap| is not 530 // kNoInputNoOutput, kGeneralBonding otherwise. This requests authentication 531 // when possible (based on IO Capabilities), as we don't know the peer's 532 // authentication requirements yet. 533 pw::bluetooth::emboss::AuthenticationRequirements 534 GetInitiatorAuthenticationRequirements( 535 pw::bluetooth::emboss::IoCapability local_cap); 536 537 // Get the Authentication Requirements for a peer-initiated pairing. This will 538 // inclusive-language: ignore 539 // request MITM protection whenever possible to obtain an "authenticated" link 540 // encryption key. 541 // 542 // Local service requirements and peer authentication bonding type should be 543 // available by the time this is called, but Non-Bondable Mode and Dedicated 544 // Bonding over BR/EDR are not supported, so this always returns 545 // kMITMGeneralBonding if this pairing can result in an authenticated link key, 546 // kGeneralBonding otherwise. 547 pw::bluetooth::emboss::AuthenticationRequirements 548 GetResponderAuthenticationRequirements( 549 pw::bluetooth::emboss::IoCapability local_cap, 550 pw::bluetooth::emboss::IoCapability remote_cap); 551 552 } // namespace bt::gap 553