| // Copyright 2018 The Fuchsia Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #ifndef SRC_CONNECTIVITY_BLUETOOTH_CORE_BT_HOST_SM_TYPES_H_ |
| #define SRC_CONNECTIVITY_BLUETOOTH_CORE_BT_HOST_SM_TYPES_H_ |
| |
| #include <lib/fit/function.h> |
| |
| #include <optional> |
| #include <string> |
| #include <unordered_map> |
| |
| #include "src/connectivity/bluetooth/core/bt-host/common/uint128.h" |
| #include "src/connectivity/bluetooth/core/bt-host/hci-spec/constants.h" |
| #include "src/connectivity/bluetooth/core/bt-host/hci-spec/link_key.h" |
| #include "src/connectivity/bluetooth/core/bt-host/sm/smp.h" |
| |
| namespace bt::sm { |
| |
| const std::unordered_map<Code, size_t> kCodeToPayloadSize{ |
| {kSecurityRequest, sizeof(AuthReqField)}, |
| {kPairingRequest, sizeof(PairingRequestParams)}, |
| {kPairingResponse, sizeof(PairingResponseParams)}, |
| {kPairingConfirm, sizeof(PairingConfirmValue)}, |
| {kPairingRandom, sizeof(PairingRandomValue)}, |
| {kPairingFailed, sizeof(PairingFailedParams)}, |
| {kEncryptionInformation, sizeof(EncryptionInformationParams)}, |
| {kMasterIdentification, sizeof(MasterIdentificationParams)}, |
| {kIdentityInformation, sizeof(IRK)}, |
| {kIdentityAddressInformation, sizeof(IdentityAddressInformationParams)}, |
| {kPairingPublicKey, sizeof(PairingPublicKeyParams)}, |
| {kPairingDHKeyCheck, sizeof(PairingDHKeyCheckValueE)}, |
| }; |
| |
| // The available algorithms used to generate the cross-transport key during pairing. |
| enum CrossTransportKeyAlgo { |
| // Use only the H6 function during cross-transport derivation (v5.2 Vol. 3 Part H 2.2.10). |
| kUseH6, |
| |
| // Use the H7 function during cross-transport derivation (v5.2 Vol. 3 Part H 2.2.11). |
| kUseH7 |
| }; |
| |
| // Represents the features exchanged during Pairing Phase 1. |
| struct PairingFeatures final { |
| PairingFeatures(); |
| PairingFeatures(bool initiator, bool sc, bool will_bond, |
| std::optional<CrossTransportKeyAlgo> algo, PairingMethod method, |
| uint8_t enc_key_size, KeyDistGenField local_kd, KeyDistGenField remote_kd); |
| |
| // True if the local device is in the "initiator" role. |
| bool initiator; |
| |
| // True if LE Secure Connections pairing should be used. Otherwise, LE Legacy |
| // Pairing should be used. |
| bool secure_connections; |
| |
| // True if pairing is to be performed with bonding, false if not |
| bool will_bond; |
| |
| // If present, prescribes the algorithm to use during cross-transport key derivation. If not |
| // present, cross-transport key derivation should not take place. |
| std::optional<CrossTransportKeyAlgo> generate_ct_key; |
| |
| // Indicates the key generation model used for Phase 2. |
| PairingMethod method; |
| |
| // The negotiated encryption key size. |
| uint8_t encryption_key_size; |
| |
| // The keys that we must distribute to the peer. |
| KeyDistGenField local_key_distribution; |
| |
| // The keys that will be distributed to us by the peer. |
| KeyDistGenField remote_key_distribution; |
| }; |
| |
| constexpr KeyDistGenField DistributableKeys(KeyDistGenField keys) { |
| // The link key field never affects the distributed keys. It only has meaning when the devices use |
| // LE Secure Connections, where it means the devices should generate the BR/EDR Link Key locally. |
| return keys & ~KeyDistGen::kLinkKey; |
| } |
| |
| // Returns a bool indicating whether `features` calls for the devices to exchange key information |
| // during the Key Distribution/Generation Phase 3. |
| bool HasKeysToDistribute(PairingFeatures features); |
| |
| // Each enum variant corresponds to an LE security mode 1 level in v5.2 Vol. Part C 10.2.1. Fuchsia |
| // only supports encryption based security (Security Mode 1 and Secure Connections Only mode). |
| enum class SecurityLevel { |
| // No encryption |
| kNoSecurity = 1, |
| |
| // Encrypted without MITM protection (unauthenticated) |
| kEncrypted = 2, |
| |
| // Encrypted with MITM protection (authenticated) |
| kAuthenticated = 3, |
| |
| // Encrypted with MITM protection, Secure Connections, and a 128-bit encryption key. |
| kSecureAuthenticated = 4, |
| }; |
| |
| // Returns a string representation of |level| for debug messages. |
| const char* LevelToString(SecurityLevel level); |
| |
| // Represents the security properties of a key. The security properties of a |
| // connection's LTK defines the security properties of the connection. |
| class SecurityProperties final { |
| public: |
| SecurityProperties(); |
| SecurityProperties(SecurityLevel level, size_t enc_key_size, bool secure_connections); |
| SecurityProperties(bool encrypted, bool authenticated, bool secure_connections, |
| size_t enc_key_size); |
| // Build from a BR/EDR Link Key that resulted from pairing. |lk_type| should not be |
| // kChangedCombination, because that means that the link key is the same type as before it was |
| // changed, which this has no knowledge of. |
| // |
| // Legacy pairing keys will be considered to have security level kNoSecurity because legacy |
| // pairing is superceded by Secure Simple Pairing in Core Spec v2.1 + EDR in 2007. Backwards |
| // compatiblity is optional per v5.0, Vol 3, Part C, Section 5. Furthermore, the last Core Spec |
| // with only legacy pairing (v2.0 + EDR) was withdrawn by Bluetooth SIG on 2019-01-28. |
| // |
| // TODO(fxbug.dev/36360): SecurityProperties will treat kDebugCombination keys as "encrypted, |
| // unauthenticated, and no Secure Connections" to potentially allow their use as valid link keys, |
| // but does not store the fact that they originate from a controller in pairing debug mode, a |
| // potential hazard. Care should be taken at the controller interface to enforce particular |
| // policies regarding debug keys. |
| explicit SecurityProperties(hci::LinkKeyType lk_type); |
| |
| SecurityLevel level() const; |
| size_t enc_key_size() const { return enc_key_size_; } |
| bool encrypted() const { return properties_ & Property::kEncrypted; } |
| bool secure_connections() const { return properties_ & Property::kSecureConnections; } |
| bool authenticated() const { return properties_ & Property::kAuthenticated; } |
| |
| // Returns the BR/EDR link key type that produces the current security properties. Returns |
| // std::nullopt if the current security level is kNoSecurity. |
| // |
| // SecurityProperties does not encode the use of LinkKeyType::kDebugCombination keys (see Core |
| // Spec v5.0 Vol 2, Part E Section 7.6.4), produced when a controller is in debug mode, so |
| // SecurityProperties constructed from LinkKeyType::kDebugCombination returns |
| // LinkKeyType::kUnauthenticatedCombination192 from this method. |
| std::optional<hci::LinkKeyType> GetLinkKeyType() const; |
| |
| // Returns a string representation of these properties. |
| std::string ToString() const; |
| |
| // Returns whether `this` SecurityProperties is at least as secure as |other|. This checks the |
| // encryption/authentication level of `this` vs. other, that `this` used secure connections if |
| // |other| did, and that `this` encryption key size is at least as large as |others|. |
| bool IsAsSecureAs(const SecurityProperties& other) const; |
| |
| // Compare two properties for equality. |
| bool operator==(const SecurityProperties& other) const { |
| return properties_ == other.properties_ && enc_key_size_ == other.enc_key_size_; |
| } |
| |
| bool operator!=(const SecurityProperties& other) const { return !(*this == other); } |
| |
| private: |
| // Possible security properties for a link. |
| enum Property : uint8_t { |
| kEncrypted = (1 << 0), |
| kAuthenticated = (1 << 1), |
| kSecureConnections = (1 << 2) |
| }; |
| using PropertiesField = uint8_t; |
| PropertiesField properties_; |
| size_t enc_key_size_; |
| }; |
| |
| // Represents a reusable long term key for a specific transport. |
| class LTK final { |
| public: |
| LTK() = default; |
| LTK(const SecurityProperties& security, const hci::LinkKey& key); |
| |
| const SecurityProperties& security() const { return security_; } |
| const hci::LinkKey& key() const { return key_; } |
| |
| bool operator==(const LTK& other) const { |
| return security() == other.security() && key() == other.key(); |
| } |
| |
| bool operator!=(const LTK& other) const { return !(*this == other); } |
| |
| private: |
| SecurityProperties security_; |
| hci::LinkKey key_; |
| }; |
| |
| // Represents a 128-bit key. |
| class Key final { |
| public: |
| Key() = default; |
| Key(const SecurityProperties& security, const UInt128& value); |
| |
| const SecurityProperties& security() const { return security_; } |
| const UInt128& value() const { return value_; } |
| |
| bool operator==(const Key& other) const { |
| return security() == other.security() && value() == other.value(); |
| } |
| |
| private: |
| SecurityProperties security_; |
| UInt128 value_; |
| }; |
| |
| // Container for LE pairing data. |
| struct PairingData final { |
| // The identity address. |
| std::optional<DeviceAddress> identity_address; |
| |
| // The long term link encryption key generated by the local device. For LTKs generated by Secure |
| // Connections, this will be the same as peer_ltk. |
| std::optional<sm::LTK> local_ltk; |
| |
| // The long term link encryption key generated by the peer device. For LTKs generated by Secure |
| // Connections, this will be the same as local_ltk. |
| std::optional<sm::LTK> peer_ltk; |
| |
| // The cross-transport key for pairing-free encryption on the other transport. |
| std::optional<sm::LTK> cross_transport_key; |
| |
| // The identity resolving key used to resolve RPAs to |identity|. |
| std::optional<sm::Key> irk; |
| |
| // The connection signature resolving key used in LE security mode 2. |
| std::optional<sm::Key> csrk; |
| |
| bool operator==(const PairingData& other) const { |
| return identity_address == other.identity_address && local_ltk == other.local_ltk && |
| peer_ltk == other.peer_ltk && irk == other.irk && csrk == other.csrk; |
| } |
| }; |
| |
| // Container for identity information for distribution. |
| struct IdentityInfo { |
| UInt128 irk; |
| DeviceAddress address; |
| }; |
| |
| // Enum for the possible values of the SM Bondable Mode as defined in spec V5.1 Vol 3 Part C |
| // Section 9.4 |
| enum class BondableMode { |
| // Allows pairing which results in bonding, as well as pairing which does not |
| Bondable, |
| // Does not allow pairing which results in bonding |
| NonBondable, |
| }; |
| |
| // Represents the local device's settings for easy mapping to Pairing(Request|Response)Parameters. |
| struct LocalPairingParams { |
| // The local I/O capability. |
| IOCapability io_capability; |
| // Whether or not OOB authentication data is available locally. Defaults to no OOB data. |
| OOBDataFlag oob_data_flag = OOBDataFlag::kNotPresent; |
| // The local requested security properties (Vol 3, Part H, 2.3.1). Defaults to no Authentication |
| // Requirements. |
| AuthReqField auth_req = 0u; |
| // Maximum encryption key size supported by the local device. Valid values are 7-16. Defaults |
| // to maximum allowed encryption key size. |
| uint8_t max_encryption_key_size = kMaxEncryptionKeySize; |
| // The keys that the local system is able to distribute. Defaults to distributing no keys. |
| KeyDistGenField local_keys = 0u; |
| // The keys that are desired from the peer. Defaults to distributing no keys. |
| KeyDistGenField remote_keys = 0u; |
| }; |
| |
| // These roles correspond to the device which starts pairing. |
| enum class Role { |
| // The LMP Master device is always kInitiator (V5.0 Vol. 3 Part H Appendix C.1). |
| kInitiator, |
| |
| // The LMP Slave device is always kResponder (V5.0 Vol. 3 Part H Appendix C.1). |
| kResponder |
| }; |
| |
| using PairingProcedureId = uint64_t; |
| |
| // Used by Phase 2 classes to notify their owner that a new encryption key is ready. For Legacy |
| // Pairing, this is the STK which may only be used for the current session. For Secure Connections, |
| // this is the LTK which may be persisted. |
| using OnPhase2KeyGeneratedCallback = fit::function<void(const UInt128&)>; |
| |
| // Used to notify classes of peer Pairing Requests. |
| using PairingRequestCallback = fit::function<void(PairingRequestParams)>; |
| |
| } // namespace bt::sm |
| |
| #endif // SRC_CONNECTIVITY_BLUETOOTH_CORE_BT_HOST_SM_TYPES_H_ |