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 <lib/fit/function.h>
17
18 #include <optional>
19 #include <string>
20 #include <unordered_map>
21
22 #include "pw_bluetooth_sapphire/internal/host/common/inspect.h"
23 #include "pw_bluetooth_sapphire/internal/host/common/uint128.h"
24 #include "pw_bluetooth_sapphire/internal/host/hci-spec/constants.h"
25 #include "pw_bluetooth_sapphire/internal/host/hci-spec/link_key.h"
26 #include "pw_bluetooth_sapphire/internal/host/sm/smp.h"
27
28 namespace bt::sm {
29
30 const std::unordered_map<Code, size_t> kCodeToPayloadSize{
31 {kSecurityRequest, sizeof(AuthReqField)},
32 {kPairingRequest, sizeof(PairingRequestParams)},
33 {kPairingResponse, sizeof(PairingResponseParams)},
34 {kPairingConfirm, sizeof(PairingConfirmValue)},
35 {kPairingRandom, sizeof(PairingRandomValue)},
36 {kPairingFailed, sizeof(PairingFailedParams)},
37 {kEncryptionInformation, sizeof(EncryptionInformationParams)},
38 {kCentralIdentification, sizeof(CentralIdentificationParams)},
39 {kIdentityInformation, sizeof(IRK)},
40 {kIdentityAddressInformation, sizeof(IdentityAddressInformationParams)},
41 {kPairingPublicKey, sizeof(PairingPublicKeyParams)},
42 {kPairingDHKeyCheck, sizeof(PairingDHKeyCheckValueE)},
43 };
44
45 // The available algorithms used to generate the cross-transport key during
46 // pairing.
47 enum CrossTransportKeyAlgo {
48 // Use only the H6 function during cross-transport derivation (v5.2 Vol. 3
49 // Part H 2.2.10).
50 kUseH6,
51
52 // Use the H7 function during cross-transport derivation (v5.2 Vol. 3 Part
53 // H 2.2.11).
54 kUseH7
55 };
56
57 // Represents the features exchanged during Pairing Phase 1.
58 struct PairingFeatures final {
59 // True if the local device is in the "initiator" role.
60 bool initiator = false;
61
62 // True if LE Secure Connections pairing should be used. Otherwise, LE Legacy
63 // Pairing should be used.
64 bool secure_connections = false;
65
66 // True if pairing is to be performed with bonding, false if not
67 bool will_bond = false;
68
69 // If present, prescribes the algorithm to use during cross-transport key
70 // derivation. If not present, cross-transport key derivation should not take
71 // place.
72 std::optional<CrossTransportKeyAlgo> generate_ct_key;
73
74 // Indicates the key generation model used for Phase 2.
75 PairingMethod method = PairingMethod::kJustWorks;
76
77 // The negotiated encryption key size.
78 uint8_t encryption_key_size = 0;
79
80 // The keys that we must distribute to the peer.
81 KeyDistGenField local_key_distribution = 0;
82
83 // The keys that will be distributed to us by the peer.
84 KeyDistGenField remote_key_distribution = 0;
85 };
86
DistributableKeys(KeyDistGenField keys)87 constexpr KeyDistGenField DistributableKeys(KeyDistGenField keys) {
88 // The link key field never affects the distributed keys. It only has meaning
89 // when the devices use LE Secure Connections, where it means the devices
90 // should generate the BR/EDR Link Key locally.
91 return keys & ~KeyDistGen::kLinkKey;
92 }
93
94 // Returns a bool indicating whether `features` calls for the devices to
95 // exchange key information during the Key Distribution/Generation Phase 3.
96 bool HasKeysToDistribute(PairingFeatures features);
97
98 // Each enum variant corresponds to either:
99 // 1) a LE security mode 1 level (Core Spec v5.4, Vol 3, Part C 10.2.1)
100 // 2) a BR/EDR security mode 4 level (Core Spec v5.4, Vol 3, Part C, 5.2.2.8)
101 // Fuchsia only supports encryption based security
102 enum class SecurityLevel {
103 // No encryption
104 kNoSecurity = 1,
105
106 // inclusive-language: ignore
107 // Encrypted without MITM protection (unauthenticated)
108 kEncrypted = 2,
109
110 // inclusive-language: ignore
111 // Encrypted with MITM protection (authenticated)
112 kAuthenticated = 3,
113
114 // inclusive-language: ignore
115 // Encrypted with MITM protection, Secure Connections, and a 128-bit
116 // encryption key.
117 kSecureAuthenticated = 4,
118 };
119
120 // Returns a string representation of |level| for debug messages.
121 const char* LevelToString(SecurityLevel level);
122
123 // Represents the security properties of a key. The security properties of a
124 // connection's LTK defines the security properties of the connection.
125 class SecurityProperties final {
126 public:
127 SecurityProperties();
128 SecurityProperties(SecurityLevel level,
129 size_t enc_key_size,
130 bool secure_connections);
131 SecurityProperties(bool encrypted,
132 bool authenticated,
133 bool secure_connections,
134 size_t enc_key_size);
135 // Build from a BR/EDR Link Key that resulted from pairing. |lk_type| should
136 // not be kChangedCombination, because that means that the link key is the
137 // same type as before it was changed, which this has no knowledge of.
138 //
139 // Legacy pairing keys will be considered to have security level kNoSecurity
140 // because legacy pairing is superceded by Secure Simple Pairing in Core Spec
141 // v2.1 + EDR in 2007. Backwards compatiblity is optional per v5.0, Vol 3,
142 // Part C, Section 5. Furthermore, the last Core Spec with only legacy pairing
143 // (v2.0 + EDR) was withdrawn by Bluetooth SIG on 2019-01-28.
144 //
145 // TODO(fxbug.dev/42111880): SecurityProperties will treat kDebugCombination
146 // keys as "encrypted, unauthenticated, and no Secure Connections" to
147 // potentially allow their use as valid link keys, but does not store the fact
148 // that they originate from a controller in pairing debug mode, a potential
149 // hazard. Care should be taken at the controller interface to enforce
150 // particular policies regarding debug keys.
151 explicit SecurityProperties(hci_spec::LinkKeyType lk_type);
152
153 ~SecurityProperties() = default;
154
155 // Copy constructors that ignore InspectProperties
156 SecurityProperties(const SecurityProperties& other);
157 SecurityProperties& operator=(const SecurityProperties& other);
158
159 SecurityLevel level() const;
enc_key_size()160 size_t enc_key_size() const { return enc_key_size_; }
encrypted()161 bool encrypted() const { return properties_ & Property::kEncrypted; }
secure_connections()162 bool secure_connections() const {
163 return properties_ & Property::kSecureConnections;
164 }
authenticated()165 bool authenticated() const { return properties_ & Property::kAuthenticated; }
166
167 // Returns the BR/EDR link key type that produces the current security
168 // properties. Returns std::nullopt if the current security level is
169 // kNoSecurity.
170 //
171 // SecurityProperties does not encode the use of
172 // LinkKeyType::kDebugCombination keys (see Core Spec v5.0 Vol 2, Part E
173 // Section 7.6.4), produced when a controller is in debug mode, so
174 // SecurityProperties constructed from LinkKeyType::kDebugCombination returns
175 // LinkKeyType::kUnauthenticatedCombination192 from this method.
176 std::optional<hci_spec::LinkKeyType> GetLinkKeyType() const;
177
178 // Returns a string representation of these properties.
179 std::string ToString() const;
180
181 // Returns whether `this` SecurityProperties is at least as secure as |other|.
182 // This checks the encryption/authentication level of `this` vs. other, that
183 // `this` used secure connections if |other| did, and that `this` encryption
184 // key size is at least as large as |others|.
185 bool IsAsSecureAs(const SecurityProperties& other) const;
186
187 // Attach pairing state inspect node named |name| as a child of |parent|.
188 void AttachInspect(inspect::Node& parent, std::string name);
189
190 // Compare two properties for equality.
191 bool operator==(const SecurityProperties& other) const {
192 return properties_ == other.properties_ &&
193 enc_key_size_ == other.enc_key_size_;
194 }
195
196 bool operator!=(const SecurityProperties& other) const {
197 return !(*this == other);
198 }
199
200 private:
201 struct InspectProperties {
202 inspect::StringProperty level;
203 inspect::BoolProperty encrypted;
204 inspect::BoolProperty secure_connections;
205 inspect::BoolProperty authenticated;
206 inspect::StringProperty key_type;
207 };
208 InspectProperties inspect_properties_;
209 inspect::Node inspect_node_;
210
211 // Possible security properties for a link.
212 enum Property : uint8_t {
213 kEncrypted = (1 << 0),
214 kAuthenticated = (1 << 1),
215 kSecureConnections = (1 << 2)
216 };
217 using PropertiesField = uint8_t;
218 PropertiesField properties_;
219 size_t enc_key_size_;
220 };
221
222 // Represents a reusable long term key for a specific transport.
223 class LTK final {
224 public:
225 LTK() = default;
226 LTK(const SecurityProperties& security, const hci_spec::LinkKey& key);
227
security()228 const SecurityProperties& security() const { return security_; }
key()229 const hci_spec::LinkKey& key() const { return key_; }
230
231 bool operator==(const LTK& other) const {
232 return security() == other.security() && key() == other.key();
233 }
234
235 bool operator!=(const LTK& other) const { return !(*this == other); }
236
237 // Attach |security_| as child node of |parent| with specified |name|.
238 void AttachInspect(inspect::Node& parent, std::string name);
239
240 private:
241 SecurityProperties security_;
242 hci_spec::LinkKey key_;
243 };
244
245 // Represents a 128-bit key.
246 class Key final {
247 public:
248 Key() = default;
249 Key(const SecurityProperties& security, const UInt128& value);
250
security()251 const SecurityProperties& security() const { return security_; }
value()252 const UInt128& value() const { return value_; }
253
254 bool operator==(const Key& other) const {
255 return security() == other.security() && value() == other.value();
256 }
257
258 private:
259 SecurityProperties security_;
260 UInt128 value_;
261 };
262
263 // Container for LE pairing data.
264 struct PairingData final {
265 // The identity address.
266 std::optional<DeviceAddress> identity_address;
267
268 // The long term link encryption key generated by the local device. For LTKs
269 // generated by Secure Connections, this will be the same as peer_ltk.
270 std::optional<sm::LTK> local_ltk;
271
272 // The long term link encryption key generated by the peer device. For LTKs
273 // generated by Secure Connections, this will be the same as local_ltk.
274 std::optional<sm::LTK> peer_ltk;
275
276 // The cross-transport key for pairing-free encryption on the other transport.
277 std::optional<sm::LTK> cross_transport_key;
278
279 // The identity resolving key used to resolve RPAs to |identity|.
280 std::optional<sm::Key> irk;
281
282 // The connection signature resolving key used in LE security mode 2.
283 std::optional<sm::Key> csrk;
284
285 bool operator==(const PairingData& other) const {
286 return identity_address == other.identity_address &&
287 local_ltk == other.local_ltk && peer_ltk == other.peer_ltk &&
288 irk == other.irk && csrk == other.csrk;
289 }
290 };
291
292 // Container for identity information for distribution.
293 struct IdentityInfo {
294 UInt128 irk;
295 DeviceAddress address;
296 };
297
298 // Enum for the possible values of the SM Bondable Mode as defined in spec V5.1
299 // Vol 3 Part C Section 9.4
300 enum class BondableMode {
301 // Allows pairing which results in bonding, as well as pairing which does not
302 Bondable,
303 // Does not allow pairing which results in bonding
304 NonBondable,
305 };
306
307 // Represents the local device's settings for easy mapping to
308 // Pairing(Request|Response)Parameters.
309 struct LocalPairingParams {
310 // The local I/O capability.
311 IOCapability io_capability;
312 // Whether or not OOB authentication data is available locally. Defaults to no
313 // OOB data.
314 OOBDataFlag oob_data_flag = OOBDataFlag::kNotPresent;
315 // The local requested security properties (Vol 3, Part H, 2.3.1). Defaults to
316 // no Authentication Requirements.
317 AuthReqField auth_req = 0u;
318 // Maximum encryption key size supported by the local device. Valid values are
319 // 7-16. Defaults to maximum allowed encryption key size.
320 uint8_t max_encryption_key_size = kMaxEncryptionKeySize;
321 // The keys that the local system is able to distribute. Defaults to
322 // distributing no keys.
323 KeyDistGenField local_keys = 0u;
324 // The keys that are desired from the peer. Defaults to distributing no keys.
325 KeyDistGenField remote_keys = 0u;
326 };
327
328 // These roles correspond to the device which starts pairing.
329 enum class Role {
330 // The LMP Central device is always kInitiator (V5.0 Vol. 3 Part H Appendix
331 // C.1).
332 kInitiator,
333
334 // The LMP Peripheral device is always kResponder (V5.0 Vol. 3 Part H Appendix
335 // C.1).
336 kResponder
337 };
338
339 using PairingProcedureId = uint64_t;
340
341 // Used by Phase 2 classes to notify their owner that a new encryption key is
342 // ready. For Legacy Pairing, this is the STK which may only be used for the
343 // current session. For Secure Connections, this is the LTK which may be
344 // persisted.
345 using OnPhase2KeyGeneratedCallback = fit::function<void(const UInt128&)>;
346
347 // Used to notify classes of peer Pairing Requests.
348 using PairingRequestCallback = fit::function<void(PairingRequestParams)>;
349
350 } // namespace bt::sm
351