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