• 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 
19 #include <utility>
20 
21 #include "pw_bluetooth_sapphire/internal/host/hci-spec/constants.h"
22 #include "pw_bluetooth_sapphire/internal/host/hci-spec/util.h"
23 #include "pw_bluetooth_sapphire/internal/host/sm/smp.h"
24 
25 #pragma clang diagnostic ignored "-Wswitch-enum"
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)55 bool HasKeysToDistribute(PairingFeatures features) {
56   return DistributableKeys(features.local_key_distribution) ||
57          DistributableKeys(features.remote_key_distribution);
58 }
59 
LevelToString(SecurityLevel level)60 const char* LevelToString(SecurityLevel level) {
61   switch (level) {
62     case SecurityLevel::kEncrypted:
63       return "encrypted";
64     case SecurityLevel::kAuthenticated:
65       return "Authenticated";
66     case SecurityLevel::kSecureAuthenticated:
67       return "Authenticated with Secure Connections and 128-bit key";
68     default:
69       break;
70   }
71   return "not secure";
72 }
73 
SecurityProperties()74 SecurityProperties::SecurityProperties()
75     : SecurityProperties(/*encrypted=*/false,
76                          /*authenticated=*/false,
77                          /*secure_connections=*/false,
78                          0u) {}
79 
SecurityProperties(bool encrypted,bool authenticated,bool secure_connections,size_t enc_key_size)80 SecurityProperties::SecurityProperties(bool encrypted,
81                                        bool authenticated,
82                                        bool secure_connections,
83                                        size_t enc_key_size)
84     : properties_(0u), enc_key_size_(enc_key_size) {
85   properties_ |= (encrypted ? Property::kEncrypted : 0u);
86   properties_ |= (authenticated ? Property::kAuthenticated : 0u);
87   properties_ |= (secure_connections ? Property::kSecureConnections : 0u);
88 }
89 
SecurityProperties(SecurityLevel level,size_t enc_key_size,bool secure_connections)90 SecurityProperties::SecurityProperties(SecurityLevel level,
91                                        size_t enc_key_size,
92                                        bool secure_connections)
93     : SecurityProperties((level >= SecurityLevel::kEncrypted),
94                          (level >= SecurityLevel::kAuthenticated),
95                          secure_connections,
96                          enc_key_size) {}
97 // All BR/EDR link keys, even those from legacy pairing or based on 192-bit EC
98 // points, are stored in 128 bits, according to Core Spec v5.0, Vol 2, Part H
99 // Section 3.1 "Key Types."
SecurityProperties(hci_spec::LinkKeyType lk_type)100 SecurityProperties::SecurityProperties(hci_spec::LinkKeyType lk_type)
101     : SecurityProperties(IsEncryptedKey(lk_type),
102                          IsAuthenticatedKey(lk_type),
103                          IsSecureConnectionsKey(lk_type),
104                          kMaxEncryptionKeySize) {
105   BT_DEBUG_ASSERT_MSG(
106       lk_type != hci_spec::LinkKeyType::kChangedCombination,
107       "Can't infer security information from a Changed Combination Key");
108 }
109 
SecurityProperties(const SecurityProperties & other)110 SecurityProperties::SecurityProperties(const SecurityProperties& other) {
111   *this = other;
112 }
113 
operator =(const SecurityProperties & other)114 SecurityProperties& SecurityProperties::operator=(
115     const SecurityProperties& other) {
116   properties_ = other.properties_;
117   enc_key_size_ = other.enc_key_size_;
118   return *this;
119 }
120 
level() const121 SecurityLevel SecurityProperties::level() const {
122   auto level = SecurityLevel::kNoSecurity;
123   if (properties_ & Property::kEncrypted) {
124     level = SecurityLevel::kEncrypted;
125     if (properties_ & Property::kAuthenticated) {
126       level = SecurityLevel::kAuthenticated;
127       if (enc_key_size_ == kMaxEncryptionKeySize &&
128           (properties_ & Property::kSecureConnections)) {
129         level = SecurityLevel::kSecureAuthenticated;
130       }
131     }
132   }
133   return level;
134 }
135 
GetLinkKeyType() const136 std::optional<hci_spec::LinkKeyType> SecurityProperties::GetLinkKeyType()
137     const {
138   if (level() == SecurityLevel::kNoSecurity) {
139     return std::nullopt;
140   }
141   if (authenticated()) {
142     if (secure_connections()) {
143       return hci_spec::LinkKeyType::kAuthenticatedCombination256;
144     } else {
145       return hci_spec::LinkKeyType::kAuthenticatedCombination192;
146     }
147   } else {
148     if (secure_connections()) {
149       return hci_spec::LinkKeyType::kUnauthenticatedCombination256;
150     } else {
151       return hci_spec::LinkKeyType::kUnauthenticatedCombination192;
152     }
153   }
154 }
155 
ToString() const156 std::string SecurityProperties::ToString() const {
157   if (level() == SecurityLevel::kNoSecurity) {
158     return "[no security]";
159   }
160   // inclusive-language: disable
161   return bt_lib_cpp_string::StringPrintf(
162       "[%s%s%skey size: %lu]",
163       encrypted() ? "encrypted " : "",
164       authenticated() ? "authenticated (MITM) " : "",
165       secure_connections() ? "secure connections " : "legacy authentication ",
166       enc_key_size());
167   // inclusive-language: enable
168 }
169 
IsAsSecureAs(const SecurityProperties & other) const170 bool SecurityProperties::IsAsSecureAs(const SecurityProperties& other) const {
171   // clang-format off
172   return
173     (encrypted() || !other.encrypted()) &&
174     (authenticated() || !other.authenticated()) &&
175     (secure_connections() || !other.secure_connections()) &&
176     (enc_key_size_ >= other.enc_key_size_);
177   // clang-format on
178 }
179 
AttachInspect(inspect::Node & parent,std::string name)180 void SecurityProperties::AttachInspect(inspect::Node& parent,
181                                        std::string name) {
182   inspect_node_ = parent.CreateChild(name);
183 
184   inspect_properties_.level = inspect_node_.CreateString(
185       kInspectLevelPropertyName, LevelToString(level()));
186   inspect_properties_.encrypted =
187       inspect_node_.CreateBool(kInspectEncryptedPropertyName, encrypted());
188   inspect_properties_.secure_connections = inspect_node_.CreateBool(
189       kInspectSecureConnectionsPropertyName, secure_connections());
190   inspect_properties_.authenticated = inspect_node_.CreateBool(
191       kInspectAuthenticatedPropertyName, authenticated());
192   if (GetLinkKeyType().has_value()) {
193     inspect_properties_.key_type = inspect_node_.CreateString(
194         kInspectKeyTypePropertyName,
195         hci_spec::LinkKeyTypeToString(GetLinkKeyType().value()));
196   }
197 }
198 
LTK(const SecurityProperties & security,const hci_spec::LinkKey & key)199 LTK::LTK(const SecurityProperties& security, const hci_spec::LinkKey& key)
200     : security_(security), key_(key) {}
201 
AttachInspect(inspect::Node & parent,std::string name)202 void LTK::AttachInspect(inspect::Node& parent, std::string name) {
203   security_.AttachInspect(parent, std::move(name));
204 }
205 
Key(const SecurityProperties & security,const UInt128 & value)206 Key::Key(const SecurityProperties& security, const UInt128& value)
207     : security_(security), value_(value) {}
208 
209 }  // namespace bt::sm
210