• 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 #include "pw_bluetooth_sapphire/internal/host/sm/types.h"
16 
17 #include <cpp-string/string_printf.h>
18 #include <pw_assert/check.h>
19 #include <pw_preprocessor/compiler.h>
20 
21 #include <utility>
22 
23 #include "pw_bluetooth_sapphire/internal/host/hci-spec/constants.h"
24 #include "pw_bluetooth_sapphire/internal/host/hci-spec/util.h"
25 #include "pw_bluetooth_sapphire/internal/host/sm/smp.h"
26 
27 namespace bt::sm {
28 namespace {
29 const char* const kInspectLevelPropertyName = "level";
30 const char* const kInspectEncryptedPropertyName = "encrypted";
31 const char* const kInspectSecureConnectionsPropertyName = "secure_connections";
32 const char* const kInspectAuthenticatedPropertyName = "authenticated";
33 const char* const kInspectKeyTypePropertyName = "key_type";
34 
IsEncryptedKey(hci_spec::LinkKeyType lk_type)35 bool IsEncryptedKey(hci_spec::LinkKeyType lk_type) {
36   return (lk_type == hci_spec::LinkKeyType::kDebugCombination ||
37           lk_type == hci_spec::LinkKeyType::kUnauthenticatedCombination192 ||
38           lk_type == hci_spec::LinkKeyType::kUnauthenticatedCombination256 ||
39           lk_type == hci_spec::LinkKeyType::kAuthenticatedCombination192 ||
40           lk_type == hci_spec::LinkKeyType::kAuthenticatedCombination256);
41 }
42 
IsAuthenticatedKey(hci_spec::LinkKeyType lk_type)43 bool IsAuthenticatedKey(hci_spec::LinkKeyType lk_type) {
44   return (lk_type == hci_spec::LinkKeyType::kAuthenticatedCombination192 ||
45           lk_type == hci_spec::LinkKeyType::kAuthenticatedCombination256);
46 }
47 
IsSecureConnectionsKey(hci_spec::LinkKeyType lk_type)48 bool IsSecureConnectionsKey(hci_spec::LinkKeyType lk_type) {
49   return (lk_type == hci_spec::LinkKeyType::kUnauthenticatedCombination256 ||
50           lk_type == hci_spec::LinkKeyType::kAuthenticatedCombination256);
51 }
52 
53 }  // namespace
54 
HasKeysToDistribute(PairingFeatures features,bool is_bredr)55 bool HasKeysToDistribute(PairingFeatures features, bool is_bredr) {
56   return DistributableKeys(features.local_key_distribution, is_bredr) ||
57          DistributableKeys(features.remote_key_distribution, is_bredr);
58 }
59 
LevelToString(SecurityLevel level)60 const char* LevelToString(SecurityLevel level) {
61   PW_MODIFY_DIAGNOSTICS_PUSH();
62   PW_MODIFY_DIAGNOSTIC(ignored, "-Wswitch-enum");
63   switch (level) {
64     case SecurityLevel::kEncrypted:
65       return "encrypted";
66     case SecurityLevel::kAuthenticated:
67       return "Authenticated";
68     case SecurityLevel::kSecureAuthenticated:
69       return "Authenticated with Secure Connections and 128-bit key";
70     default:
71       break;
72   }
73   PW_MODIFY_DIAGNOSTICS_POP();
74   return "not secure";
75 }
76 
SecurityProperties()77 SecurityProperties::SecurityProperties()
78     : SecurityProperties(/*encrypted=*/false,
79                          /*authenticated=*/false,
80                          /*secure_connections=*/false,
81                          0u) {}
82 
SecurityProperties(bool encrypted,bool authenticated,bool secure_connections,size_t enc_key_size)83 SecurityProperties::SecurityProperties(bool encrypted,
84                                        bool authenticated,
85                                        bool secure_connections,
86                                        size_t enc_key_size)
87     : properties_(0u), enc_key_size_(enc_key_size) {
88   properties_ |= (encrypted ? Property::kEncrypted : 0u);
89   properties_ |= (authenticated ? Property::kAuthenticated : 0u);
90   properties_ |= (secure_connections ? Property::kSecureConnections : 0u);
91 }
92 
SecurityProperties(SecurityLevel level,size_t enc_key_size,bool secure_connections)93 SecurityProperties::SecurityProperties(SecurityLevel level,
94                                        size_t enc_key_size,
95                                        bool secure_connections)
96     : SecurityProperties((level >= SecurityLevel::kEncrypted),
97                          (level >= SecurityLevel::kAuthenticated),
98                          secure_connections,
99                          enc_key_size) {}
100 // All BR/EDR link keys, even those from legacy pairing or based on 192-bit EC
101 // points, are stored in 128 bits, according to Core Spec v5.0, Vol 2, Part H
102 // Section 3.1 "Key Types."
SecurityProperties(hci_spec::LinkKeyType lk_type)103 SecurityProperties::SecurityProperties(hci_spec::LinkKeyType lk_type)
104     : SecurityProperties(IsEncryptedKey(lk_type),
105                          IsAuthenticatedKey(lk_type),
106                          IsSecureConnectionsKey(lk_type),
107                          kMaxEncryptionKeySize) {
108   PW_DCHECK(lk_type != hci_spec::LinkKeyType::kChangedCombination,
109             "Can't infer security information from a Changed Combination Key");
110 }
111 
SecurityProperties(const SecurityProperties & other)112 SecurityProperties::SecurityProperties(const SecurityProperties& other) {
113   *this = other;
114 }
115 
operator =(const SecurityProperties & other)116 SecurityProperties& SecurityProperties::operator=(
117     const SecurityProperties& other) {
118   properties_ = other.properties_;
119   enc_key_size_ = other.enc_key_size_;
120   return *this;
121 }
122 
level() const123 SecurityLevel SecurityProperties::level() const {
124   auto level = SecurityLevel::kNoSecurity;
125   if (properties_ & Property::kEncrypted) {
126     level = SecurityLevel::kEncrypted;
127     if (properties_ & Property::kAuthenticated) {
128       level = SecurityLevel::kAuthenticated;
129       if (enc_key_size_ == kMaxEncryptionKeySize &&
130           (properties_ & Property::kSecureConnections)) {
131         level = SecurityLevel::kSecureAuthenticated;
132       }
133     }
134   }
135   return level;
136 }
137 
GetLinkKeyType() const138 hci_spec::LinkKeyType SecurityProperties::GetLinkKeyType() const {
139   if (level() == SecurityLevel::kNoSecurity) {
140     // Sapphire considers legacy pairing keys to have security level
141     // kNoSecurity. Returning kCombination type since the kLocalUnit and
142     // kRemoteUnit key types are deprecated.
143     //
144     // TODO(fxbug.dev/42113587): Implement BR/EDR security database
145     return hci_spec::LinkKeyType::kCombination;
146   }
147 
148   if (authenticated()) {
149     if (secure_connections()) {
150       return hci_spec::LinkKeyType::kAuthenticatedCombination256;
151     } else {
152       return hci_spec::LinkKeyType::kAuthenticatedCombination192;
153     }
154   } else {
155     if (secure_connections()) {
156       return hci_spec::LinkKeyType::kUnauthenticatedCombination256;
157     } else {
158       return hci_spec::LinkKeyType::kUnauthenticatedCombination192;
159     }
160   }
161 }
162 
ToString() const163 std::string SecurityProperties::ToString() const {
164   if (level() == SecurityLevel::kNoSecurity) {
165     return "[no security]";
166   }
167   // inclusive-language: disable
168   return bt_lib_cpp_string::StringPrintf(
169       "[%s%s%skey size: %zu]",
170       encrypted() ? "encrypted " : "",
171       authenticated() ? "authenticated (MITM) " : "",
172       secure_connections() ? "secure connections " : "legacy authentication ",
173       enc_key_size());
174   // inclusive-language: enable
175 }
176 
IsAsSecureAs(const SecurityProperties & other) const177 bool SecurityProperties::IsAsSecureAs(const SecurityProperties& other) const {
178   // clang-format off
179   return
180     (encrypted() || !other.encrypted()) &&
181     (authenticated() || !other.authenticated()) &&
182     (secure_connections() || !other.secure_connections()) &&
183     (enc_key_size_ >= other.enc_key_size_);
184   // clang-format on
185 }
186 
AttachInspect(inspect::Node & parent,std::string name)187 void SecurityProperties::AttachInspect(inspect::Node& parent,
188                                        std::string name) {
189   inspect_node_ = parent.CreateChild(name);
190 
191   inspect_properties_.level = inspect_node_.CreateString(
192       kInspectLevelPropertyName, LevelToString(level()));
193   inspect_properties_.encrypted =
194       inspect_node_.CreateBool(kInspectEncryptedPropertyName, encrypted());
195   inspect_properties_.secure_connections = inspect_node_.CreateBool(
196       kInspectSecureConnectionsPropertyName, secure_connections());
197   inspect_properties_.authenticated = inspect_node_.CreateBool(
198       kInspectAuthenticatedPropertyName, authenticated());
199   inspect_properties_.key_type = inspect_node_.CreateString(
200       kInspectKeyTypePropertyName,
201       hci_spec::LinkKeyTypeToString(GetLinkKeyType()));
202 }
203 
LTK(const SecurityProperties & security,const hci_spec::LinkKey & key)204 LTK::LTK(const SecurityProperties& security, const hci_spec::LinkKey& key)
205     : security_(security), key_(key) {}
206 
AttachInspect(inspect::Node & parent,std::string name)207 void LTK::AttachInspect(inspect::Node& parent, std::string name) {
208   security_.AttachInspect(parent, std::move(name));
209 }
210 
Key(const SecurityProperties & security,const UInt128 & value)211 Key::Key(const SecurityProperties& security, const UInt128& value)
212     : security_(security), value_(value) {}
213 
214 }  // namespace bt::sm
215