• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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,bool is_bredr)87 constexpr KeyDistGenField DistributableKeys(KeyDistGenField keys,
88                                             bool is_bredr) {
89   // The link key field never affects the distributed keys. It only has meaning
90   // when the devices use LE Secure Connections, where it means the devices
91   // should generate the BR/EDR Link Key locally.
92   keys &= ~KeyDistGen::kLinkKey;
93   if (is_bredr) {
94     // In BR/EDR, EncKey is repurposed to mean the devices should generate the
95     // LE LTK locally.
96     keys &= ~KeyDistGen::kEncKey;
97   }
98   return keys;
99 }
100 
101 // Returns a bool indicating whether `features` calls for the devices to
102 // exchange key information during the Key Distribution/Generation Phase 3.
103 bool HasKeysToDistribute(PairingFeatures features, bool is_bredr);
104 
105 // Each enum variant corresponds to either:
106 // 1) a LE security mode 1 level (Core Spec v5.4, Vol 3, Part C 10.2.1)
107 // 2) a BR/EDR security mode 4 level (Core Spec v5.4, Vol 3, Part C, 5.2.2.8)
108 // Fuchsia only supports encryption based security
109 // TODO(fxbug.dev/42113587): Implement BR/EDR security database
110 enum class SecurityLevel {
111   // No encryption
112   kNoSecurity = 1,
113 
114   // inclusive-language: ignore
115   // Encrypted without MITM protection (unauthenticated)
116   kEncrypted = 2,
117 
118   // inclusive-language: ignore
119   // Encrypted with MITM protection (authenticated)
120   kAuthenticated = 3,
121 
122   // inclusive-language: ignore
123   // Encrypted with MITM protection, Secure Connections, and a 128-bit
124   // encryption key.
125   kSecureAuthenticated = 4,
126 };
127 
128 // Returns a string representation of |level| for debug messages.
129 const char* LevelToString(SecurityLevel level);
130 
131 // Represents the security properties of a key. The security properties of a
132 // connection's LTK defines the security properties of the connection.
133 class SecurityProperties final {
134  public:
135   SecurityProperties();
136   SecurityProperties(SecurityLevel level,
137                      size_t enc_key_size,
138                      bool secure_connections);
139   SecurityProperties(bool encrypted,
140                      bool authenticated,
141                      bool secure_connections,
142                      size_t enc_key_size);
143   // Build from a BR/EDR Link Key that resulted from pairing. |lk_type| should
144   // not be kChangedCombination, because that means that the link key is the
145   // same type as before it was changed, which this has no knowledge of.
146   //
147   // Legacy pairing keys will be considered to have security level kNoSecurity
148   // because legacy pairing is superseded by Secure Simple Pairing in Core Spec
149   // v2.1 + EDR in 2007. Backwards compatiblity is optional per v5.0, Vol 3,
150   // Part C, Section 5. Furthermore, the last Core Spec with only legacy pairing
151   // (v2.0 + EDR) was withdrawn by Bluetooth SIG on 2019-01-28.
152   //
153   // TODO(fxbug.dev/42111880): SecurityProperties will treat kDebugCombination
154   // keys as "encrypted, unauthenticated, and no Secure Connections" to
155   // potentially allow their use as valid link keys, but does not store the fact
156   // that they originate from a controller in pairing debug mode, a potential
157   // hazard. Care should be taken at the controller interface to enforce
158   // particular policies regarding debug keys.
159   explicit SecurityProperties(hci_spec::LinkKeyType lk_type);
160 
161   ~SecurityProperties() = default;
162 
163   // Copy constructors that ignore InspectProperties
164   SecurityProperties(const SecurityProperties& other);
165   SecurityProperties& operator=(const SecurityProperties& other);
166 
167   SecurityLevel level() const;
enc_key_size()168   size_t enc_key_size() const { return enc_key_size_; }
encrypted()169   bool encrypted() const { return properties_ & Property::kEncrypted; }
secure_connections()170   bool secure_connections() const {
171     return properties_ & Property::kSecureConnections;
172   }
authenticated()173   bool authenticated() const { return properties_ & Property::kAuthenticated; }
174 
175   // Returns the BR/EDR link key type that produces the current security
176   // properties. Returns kCombination if the current security level is
177   // kNoSecurity since it is the key type generated by legacy pairing.
178   //
179   // SecurityProperties does not encode the use of
180   // LinkKeyType::kDebugCombination keys (see Core Spec v5.0 Vol 2, Part E
181   // Section 7.6.4), produced when a controller is in debug mode, so
182   // SecurityProperties constructed from LinkKeyType::kDebugCombination returns
183   // LinkKeyType::kUnauthenticatedCombination192 from this method.
184   hci_spec::LinkKeyType GetLinkKeyType() const;
185 
186   // Returns a string representation of these properties.
187   std::string ToString() const;
188 
189   // Returns whether `this` SecurityProperties is at least as secure as |other|.
190   // This checks the encryption/authentication level of `this` vs. other, that
191   // `this` used secure connections if |other| did, and that `this` encryption
192   // key size is at least as large as |others|.
193   bool IsAsSecureAs(const SecurityProperties& other) const;
194 
195   // Attach pairing state inspect node named |name| as a child of |parent|.
196   void AttachInspect(inspect::Node& parent, std::string name);
197 
198   // Compare two properties for equality.
199   bool operator==(const SecurityProperties& other) const {
200     return properties_ == other.properties_ &&
201            enc_key_size_ == other.enc_key_size_;
202   }
203 
204   bool operator!=(const SecurityProperties& other) const {
205     return !(*this == other);
206   }
207 
208  private:
209   struct InspectProperties {
210     inspect::StringProperty level;
211     inspect::BoolProperty encrypted;
212     inspect::BoolProperty secure_connections;
213     inspect::BoolProperty authenticated;
214     inspect::StringProperty key_type;
215   };
216   InspectProperties inspect_properties_;
217   inspect::Node inspect_node_;
218 
219   // Possible security properties for a link.
220   enum Property : uint8_t {
221     kEncrypted = (1 << 0),
222     kAuthenticated = (1 << 1),
223     kSecureConnections = (1 << 2)
224   };
225   using PropertiesField = uint8_t;
226   PropertiesField properties_;
227   size_t enc_key_size_;
228 };
229 
230 // Represents a reusable long term key for a specific transport.
231 class LTK final {
232  public:
233   LTK() = default;
234   LTK(const SecurityProperties& security, const hci_spec::LinkKey& key);
235 
security()236   const SecurityProperties& security() const { return security_; }
key()237   const hci_spec::LinkKey& key() const { return key_; }
238 
239   bool operator==(const LTK& other) const {
240     return security() == other.security() && key() == other.key();
241   }
242 
243   bool operator!=(const LTK& other) const { return !(*this == other); }
244 
245   // Attach |security_| as child node of |parent| with specified |name|.
246   void AttachInspect(inspect::Node& parent, std::string name);
247 
248  private:
249   SecurityProperties security_;
250   hci_spec::LinkKey key_;
251 };
252 
253 // Represents a 128-bit key.
254 class Key final {
255  public:
256   Key() = default;
257   Key(const SecurityProperties& security, const UInt128& value);
258 
security()259   const SecurityProperties& security() const { return security_; }
value()260   const UInt128& value() const { return value_; }
261 
262   bool operator==(const Key& other) const {
263     return security() == other.security() && value() == other.value();
264   }
265 
266  private:
267   SecurityProperties security_;
268   UInt128 value_;
269 };
270 
271 // Container for LE pairing data.
272 struct PairingData final {
273   // The identity address.
274   std::optional<DeviceAddress> identity_address;
275 
276   // The long term link encryption key generated by the local device. For LTKs
277   // generated by Secure Connections, this will be the same as peer_ltk.
278   std::optional<sm::LTK> local_ltk;
279 
280   // The long term link encryption key generated by the peer device. For LTKs
281   // generated by Secure Connections, this will be the same as local_ltk.
282   std::optional<sm::LTK> peer_ltk;
283 
284   // The cross-transport key for pairing-free encryption on the other transport.
285   std::optional<sm::LTK> cross_transport_key;
286 
287   // The identity resolving key used to resolve RPAs to |identity|.
288   std::optional<sm::Key> irk;
289 
290   // The connection signature resolving key used in LE security mode 2.
291   std::optional<sm::Key> csrk;
292 
293   bool operator==(const PairingData& other) const {
294     return identity_address == other.identity_address &&
295            local_ltk == other.local_ltk && peer_ltk == other.peer_ltk &&
296            irk == other.irk && csrk == other.csrk;
297   }
298 };
299 
300 // Container for identity information for distribution.
301 struct IdentityInfo {
302   UInt128 irk;
303   DeviceAddress address;
304 };
305 
306 // Enum for the possible values of the SM Bondable Mode as defined in spec V5.1
307 // Vol 3 Part C Section 9.4
308 enum class BondableMode {
309   // Allows pairing which results in bonding, as well as pairing which does not
310   Bondable,
311   // Does not allow pairing which results in bonding
312   NonBondable,
313 };
314 
315 // Represents the local device's settings for easy mapping to
316 // Pairing(Request|Response)Parameters.
317 struct LocalPairingParams {
318   // The local I/O capability.
319   IOCapability io_capability;
320   // Whether or not OOB authentication data is available locally. Defaults to no
321   // OOB data.
322   OOBDataFlag oob_data_flag = OOBDataFlag::kNotPresent;
323   // The local requested security properties (Vol 3, Part H, 2.3.1). Defaults to
324   // no Authentication Requirements.
325   AuthReqField auth_req = 0u;
326   // Maximum encryption key size supported by the local device. Valid values are
327   // 7-16. Defaults to maximum allowed encryption key size.
328   uint8_t max_encryption_key_size = kMaxEncryptionKeySize;
329   // The keys that the local system is able to distribute. Defaults to
330   // distributing no keys.
331   KeyDistGenField local_keys = 0u;
332   // The keys that are desired from the peer. Defaults to distributing no keys.
333   KeyDistGenField remote_keys = 0u;
334 };
335 
336 // These roles correspond to the device which starts pairing.
337 enum class Role {
338   // The LMP Central device is always kInitiator (V5.0 Vol. 3 Part H Appendix
339   // C.1).
340   kInitiator,
341 
342   // The LMP Peripheral device is always kResponder (V5.0 Vol. 3 Part H Appendix
343   // C.1).
344   kResponder
345 };
346 
347 using PairingProcedureId = uint64_t;
348 
349 // Used by Phase 2 classes to notify their owner that a new encryption key is
350 // ready. For Legacy Pairing, this is the STK which may only be used for the
351 // current session. For Secure Connections, this is the LTK which may be
352 // persisted.
353 using OnPhase2KeyGeneratedCallback = fit::function<void(const UInt128&)>;
354 
355 // Used to notify classes of peer Pairing Requests.
356 using PairingRequestCallback = fit::function<void(PairingRequestParams)>;
357 
358 }  // namespace bt::sm
359