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