1/* 2** 3** Copyright 2017, The Android Open Source Project 4** 5** Licensed under the Apache License, Version 2.0 (the "License"); 6** you may not use this file except in compliance with the License. 7** You may obtain a copy of the License at 8** 9** http://www.apache.org/licenses/LICENSE-2.0 10** 11** Unless required by applicable law or agreed to in writing, software 12** distributed under the License is distributed on an "AS IS" BASIS, 13** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14** See the License for the specific language governing permissions and 15** limitations under the License. 16*/ 17 18#include <keymaster/legacy_support/keymaster1_legacy_support.h> 19 20#include <android-base/logging.h> 21 22#include <assert.h> 23 24#include <algorithm> 25#include <vector> 26 27namespace keymaster { 28 29template <typename T> std::vector<T> make_vector(const T* array, size_t len) { 30 return std::vector<T>(array, array + len); 31} 32 33// This helper class implements just enough of the C++ standard collection interface to be able to 34// accept push_back calls, and it does nothing but count them. It's useful when you want to count 35// insertions but not actually store anything. It's used in digest_set_is_full below to count the 36// size of a set intersection. 37struct PushbackCounter { 38 struct value_type { 39 template <typename T> value_type(const T&) {} 40 }; 41 void push_back(const value_type&) { ++count; } 42 size_t count = 0; 43}; 44 45static std::vector<keymaster_digest_t> full_digest_list = { 46 KM_DIGEST_MD5, KM_DIGEST_SHA1, KM_DIGEST_SHA_2_224, 47 KM_DIGEST_SHA_2_256, KM_DIGEST_SHA_2_384, KM_DIGEST_SHA_2_512}; 48 49template <typename Iter> static bool digest_set_is_full(Iter begin, Iter end) { 50 PushbackCounter counter; 51 std::set_intersection(begin, end, full_digest_list.begin(), full_digest_list.end(), 52 std::back_inserter(counter)); 53 return counter.count == full_digest_list.size(); 54} 55 56static keymaster_error_t add_digests(const keymaster1_device_t* dev, keymaster_algorithm_t algorithm, 57 keymaster_purpose_t purpose, 58 Keymaster1LegacySupport::DigestMap* map, bool* supports_all) { 59 auto key = std::make_pair(algorithm, purpose); 60 61 keymaster_digest_t* digests; 62 size_t digests_length; 63 keymaster_error_t error = 64 dev->get_supported_digests(dev, algorithm, purpose, &digests, &digests_length); 65 if (error != KM_ERROR_OK) { 66 LOG(ERROR) << "Error " << error << " getting supported digests from keymaster1 device"; 67 return error; 68 } 69 std::unique_ptr<keymaster_digest_t, Malloc_Delete> digests_deleter(digests); 70 71 auto digest_vec = make_vector(digests, digests_length); 72 *supports_all = digest_set_is_full(digest_vec.begin(), digest_vec.end()); 73 (*map)[key] = std::move(digest_vec); 74 return error; 75} 76 77static keymaster_error_t map_digests(const keymaster1_device_t* dev, 78 Keymaster1LegacySupport::DigestMap* map, 79 bool* supports_all) { 80 map->clear(); 81 *supports_all = true; 82 83 keymaster_algorithm_t sig_algorithms[] = {KM_ALGORITHM_RSA, KM_ALGORITHM_EC, KM_ALGORITHM_HMAC}; 84 keymaster_purpose_t sig_purposes[] = {KM_PURPOSE_SIGN, KM_PURPOSE_VERIFY}; 85 for (auto algorithm : sig_algorithms) 86 for (auto purpose : sig_purposes) { 87 bool alg_purpose_supports_all; 88 keymaster_error_t error = 89 add_digests(dev, algorithm, purpose, map, &alg_purpose_supports_all); 90 if (error != KM_ERROR_OK) 91 return error; 92 *supports_all &= alg_purpose_supports_all; 93 } 94 95 keymaster_algorithm_t crypt_algorithms[] = {KM_ALGORITHM_RSA}; 96 keymaster_purpose_t crypt_purposes[] = {KM_PURPOSE_ENCRYPT, KM_PURPOSE_DECRYPT}; 97 for (auto algorithm : crypt_algorithms) 98 for (auto purpose : crypt_purposes) { 99 bool alg_purpose_supports_all; 100 keymaster_error_t error = 101 add_digests(dev, algorithm, purpose, map, &alg_purpose_supports_all); 102 if (error != KM_ERROR_OK) 103 return error; 104 *supports_all &= alg_purpose_supports_all; 105 } 106 107 return KM_ERROR_OK; 108} 109 110Keymaster1LegacySupport::Keymaster1LegacySupport(const keymaster1_device_t* dev) { 111 map_digests(dev, &device_digests_, &supports_all_); 112} 113 114template <typename Collection, typename Value> bool contains(const Collection& c, const Value& v) { 115 return std::find(c.begin(), c.end(), v) != c.end(); 116} 117 118template <typename T> 119static bool findUnsupportedDigest(keymaster_algorithm_t algorithm, 120 keymaster_purpose_t purpose, 121 const T& params, 122 const Keymaster1LegacySupport::DigestMap& digest_map) { 123 auto supported_digests = digest_map.find(std::make_pair(algorithm, purpose)); 124 if (supported_digests == digest_map.end()) 125 // Invalid algorith/purpose pair (e.g. EC encrypt). Let the error be handled by HW module. 126 return false; 127 128 for (auto& entry : params) 129 if (entry.tag == TAG_DIGEST) 130 if (!contains(supported_digests->second, entry.enumerated)) { 131 LOG(WARNING) << "Digest " << entry.enumerated << " requested but not supported by KM1 hal"; 132 return true; 133 } 134 return false; 135} 136 137template <typename T> 138bool requiresSoftwareDigesting(keymaster_algorithm_t algorithm, keymaster_purpose_t purpose, 139 const T& params, 140 const Keymaster1LegacySupport::DigestMap& digest_map) { 141 switch (algorithm) { 142 case KM_ALGORITHM_AES: 143 case KM_ALGORITHM_TRIPLE_DES: 144 LOG(WARNING) << "Not performing software digesting for symmetric cipher keys"; 145 return false; 146 case KM_ALGORITHM_HMAC: 147 case KM_ALGORITHM_RSA: 148 case KM_ALGORITHM_EC: 149 break; 150 } 151 152 if (!findUnsupportedDigest(algorithm, purpose, params, digest_map)) { 153 LOG(DEBUG) << "Requested digest(s) supported for algorithm " << algorithm << " and purpose " << purpose; 154 return false; 155 } 156 157 return true; 158} 159bool Keymaster1LegacySupport::RequiresSoftwareDigesting( 160 const AuthorizationSet& key_description) const { 161 162 keymaster_algorithm_t algorithm; 163 if (!key_description.GetTagValue(TAG_ALGORITHM, &algorithm)) { 164 // The hardware module will return an error during keygen. 165 return false; 166 } 167 168 if (supports_all_) return false; 169 170 for (auto& entry : key_description) 171 if (entry.tag == TAG_PURPOSE) { 172 keymaster_purpose_t purpose = static_cast<keymaster_purpose_t>(entry.enumerated); 173 if (requiresSoftwareDigesting(algorithm, purpose, key_description, device_digests_)) 174 return true; 175 } 176 177 return false; 178} 179 180bool Keymaster1LegacySupport::RequiresSoftwareDigesting( 181 const AuthProxy& key_description) const { 182 183 keymaster_algorithm_t algorithm; 184 if (!key_description.GetTagValue(TAG_ALGORITHM, &algorithm)) { 185 // The hardware module will return an error during keygen. 186 return false; 187 } 188 189 if (supports_all_) return false; 190 191 for (auto& entry : key_description) 192 if (entry.tag == TAG_PURPOSE) { 193 keymaster_purpose_t purpose = static_cast<keymaster_purpose_t>(entry.enumerated); 194 if (requiresSoftwareDigesting(algorithm, purpose, key_description, device_digests_)) 195 return true; 196 } 197 198 return false; 199} 200 201template<> 202keymaster_error_t 203Keymaster1ArbitrationFactory<EcdsaKeymaster1KeyFactory>::GenerateKey( 204 const AuthorizationSet& key_description, 205 KeymasterKeyBlob* key_blob, AuthorizationSet* hw_enforced, 206 AuthorizationSet* sw_enforced) const { 207 if (legacy_support_.RequiresSoftwareDigesting(key_description)) { 208 return software_digest_factory_.GenerateKey(key_description, key_blob, hw_enforced, 209 sw_enforced); 210 } else { 211 AuthorizationSet mutable_key_description = key_description; 212 keymaster_ec_curve_t curve; 213 if (key_description.GetTagValue(TAG_EC_CURVE, &curve)) { 214 // Keymaster1 doesn't know about EC curves. We need to translate to key size. 215 uint32_t key_size_from_curve; 216 keymaster_error_t error = EcCurveToKeySize(curve, &key_size_from_curve); 217 if (error != KM_ERROR_OK) { 218 return error; 219 } 220 221 uint32_t key_size_from_desc; 222 if (key_description.GetTagValue(TAG_KEY_SIZE, &key_size_from_desc)) { 223 if (key_size_from_desc != key_size_from_curve) { 224 return KM_ERROR_INVALID_ARGUMENT; 225 } 226 } else { 227 mutable_key_description.push_back(TAG_KEY_SIZE, key_size_from_curve); 228 } 229 } 230 231 return passthrough_factory_.GenerateKey(mutable_key_description, key_blob, hw_enforced, 232 sw_enforced); 233 } 234} 235 236template<> 237keymaster_error_t 238Keymaster1ArbitrationFactory<EcdsaKeymaster1KeyFactory>::LoadKey(KeymasterKeyBlob&& key_material, 239 const AuthorizationSet& additional_params, 240 AuthorizationSet&& hw_enforced, 241 AuthorizationSet&& sw_enforced, 242 UniquePtr<Key>* key) const { 243 bool requires_software_digesting = legacy_support_.RequiresSoftwareDigesting( 244 AuthProxy(hw_enforced, sw_enforced)); 245 auto rc = software_digest_factory_.LoadKey(move(key_material), additional_params, 246 move(hw_enforced), move(sw_enforced), key); 247 if (rc != KM_ERROR_OK) return rc; 248 if (!requires_software_digesting) { 249 (*key)->key_factory() = & passthrough_factory_; 250 } 251 return KM_ERROR_OK; 252} 253 254template<> 255keymaster_error_t 256Keymaster1ArbitrationFactory<RsaKeymaster1KeyFactory>::LoadKey(KeymasterKeyBlob&& key_material, 257 const AuthorizationSet& additional_params, 258 AuthorizationSet&& hw_enforced, 259 AuthorizationSet&& sw_enforced, 260 UniquePtr<Key>* key) const { 261 bool requires_software_digesting = legacy_support_.RequiresSoftwareDigesting( 262 AuthProxy(hw_enforced, sw_enforced)); 263 auto rc = software_digest_factory_.LoadKey(move(key_material), additional_params, 264 move(hw_enforced), move(sw_enforced), key); 265 if (rc != KM_ERROR_OK) return rc; 266 if (!requires_software_digesting) { 267 (*key)->key_factory() = & passthrough_factory_; 268 } 269 return KM_ERROR_OK; 270} 271 272 273} // namespace keymaster 274