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
27 namespace keymaster {
28
make_vector(const T * array,size_t len)29 template <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.
37 struct PushbackCounter {
38 struct value_type {
39 // NOLINTNEXTLINE(google-explicit-constructor)
value_typekeymaster::PushbackCounter::value_type40 template <typename T> value_type(const T&) {}
41 };
push_backkeymaster::PushbackCounter42 void push_back(const value_type&) { ++count; }
43 size_t count = 0;
44 };
45
46 static std::vector<keymaster_digest_t> full_digest_list = {
47 KM_DIGEST_MD5, KM_DIGEST_SHA1, KM_DIGEST_SHA_2_224,
48 KM_DIGEST_SHA_2_256, KM_DIGEST_SHA_2_384, KM_DIGEST_SHA_2_512};
49
digest_set_is_full(Iter begin,Iter end)50 template <typename Iter> static bool digest_set_is_full(Iter begin, Iter end) {
51 PushbackCounter counter;
52 std::set_intersection(begin, end, full_digest_list.begin(), full_digest_list.end(),
53 std::back_inserter(counter));
54 return counter.count == full_digest_list.size();
55 }
56
add_digests(const keymaster1_device_t * dev,keymaster_algorithm_t algorithm,keymaster_purpose_t purpose,Keymaster1LegacySupport::DigestMap * map,bool * supports_all)57 static keymaster_error_t add_digests(const keymaster1_device_t* dev,
58 keymaster_algorithm_t algorithm, keymaster_purpose_t purpose,
59 Keymaster1LegacySupport::DigestMap* map, bool* supports_all) {
60 auto key = std::make_pair(algorithm, purpose);
61
62 keymaster_digest_t* digests;
63 size_t digests_length;
64 keymaster_error_t error =
65 dev->get_supported_digests(dev, algorithm, purpose, &digests, &digests_length);
66 if (error != KM_ERROR_OK) {
67 LOG(ERROR) << "Error " << error << " getting supported digests from keymaster1 device";
68 return error;
69 }
70 std::unique_ptr<keymaster_digest_t, Malloc_Delete> digests_deleter(digests);
71
72 auto digest_vec = make_vector(digests, digests_length);
73 *supports_all = digest_set_is_full(digest_vec.begin(), digest_vec.end());
74 (*map)[key] = std::move(digest_vec);
75 return error;
76 }
77
map_digests(const keymaster1_device_t * dev,Keymaster1LegacySupport::DigestMap * map,bool * supports_all)78 static keymaster_error_t map_digests(const keymaster1_device_t* dev,
79 Keymaster1LegacySupport::DigestMap* map, 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) return error;
91 *supports_all &= alg_purpose_supports_all;
92 }
93
94 keymaster_algorithm_t crypt_algorithms[] = {KM_ALGORITHM_RSA};
95 keymaster_purpose_t crypt_purposes[] = {KM_PURPOSE_ENCRYPT, KM_PURPOSE_DECRYPT};
96 for (auto algorithm : crypt_algorithms)
97 for (auto purpose : crypt_purposes) {
98 bool alg_purpose_supports_all;
99 keymaster_error_t error =
100 add_digests(dev, algorithm, purpose, map, &alg_purpose_supports_all);
101 if (error != KM_ERROR_OK) return error;
102 *supports_all &= alg_purpose_supports_all;
103 }
104
105 return KM_ERROR_OK;
106 }
107
Keymaster1LegacySupport(const keymaster1_device_t * dev)108 Keymaster1LegacySupport::Keymaster1LegacySupport(const keymaster1_device_t* dev) {
109 map_digests(dev, &device_digests_, &supports_all_);
110 }
111
contains(const Collection & c,const Value & v)112 template <typename Collection, typename Value> bool contains(const Collection& c, const Value& v) {
113 return std::find(c.begin(), c.end(), v) != c.end();
114 }
115
116 template <typename T>
findUnsupportedDigest(keymaster_algorithm_t algorithm,keymaster_purpose_t purpose,keymaster_digest_t digest,const T & params,const Keymaster1LegacySupport::DigestMap & digest_map)117 static bool findUnsupportedDigest(keymaster_algorithm_t algorithm, keymaster_purpose_t purpose,
118 keymaster_digest_t digest, const T& params,
119 const Keymaster1LegacySupport::DigestMap& digest_map) {
120 auto supported_digests = digest_map.find(std::make_pair(algorithm, purpose));
121 if (supported_digests == digest_map.end())
122 // Invalid algorith/purpose pair (e.g. EC encrypt). Let the error be handled by HW module.
123 return false;
124
125 if (digest != KM_DIGEST_NONE && !contains(supported_digests->second, digest)) {
126 LOG(WARNING) << "Digest " << digest << " requested but not supported by KM1 hal";
127 return true;
128 }
129
130 for (auto& entry : params)
131 if (entry.tag == TAG_DIGEST)
132 if (!contains(supported_digests->second, entry.enumerated)) {
133 LOG(WARNING) << "Digest " << entry.enumerated
134 << " requested but not supported by KM1 hal";
135 return true;
136 }
137 return false;
138 }
139
140 template <typename T>
requiresSoftwareDigesting(keymaster_algorithm_t algorithm,keymaster_purpose_t purpose,keymaster_digest_t digest,const T & params,const Keymaster1LegacySupport::DigestMap & digest_map)141 bool requiresSoftwareDigesting(keymaster_algorithm_t algorithm, keymaster_purpose_t purpose,
142 keymaster_digest_t digest, const T& params,
143 const Keymaster1LegacySupport::DigestMap& digest_map) {
144 switch (algorithm) {
145 case KM_ALGORITHM_AES:
146 case KM_ALGORITHM_TRIPLE_DES:
147 LOG(WARNING) << "Not performing software digesting for symmetric cipher keys";
148 return false;
149 case KM_ALGORITHM_HMAC:
150 case KM_ALGORITHM_RSA:
151 case KM_ALGORITHM_EC:
152 break;
153 }
154
155 if (!findUnsupportedDigest(algorithm, purpose, digest, params, digest_map)) {
156 LOG(DEBUG) << "Requested digest(s) supported for algorithm " << algorithm << " and purpose "
157 << purpose;
158 return false;
159 }
160
161 return true;
162 }
RequiresSoftwareDigesting(const AuthorizationSet & key_description) const163 bool Keymaster1LegacySupport::RequiresSoftwareDigesting(
164 const AuthorizationSet& key_description) const {
165
166 keymaster_algorithm_t algorithm;
167 if (!key_description.GetTagValue(TAG_ALGORITHM, &algorithm)) {
168 // The hardware module will return an error during keygen.
169 return false;
170 }
171
172 if (supports_all_) return false;
173
174 bool has_purpose = false;
175 for (auto& entry : key_description)
176 if (entry.tag == TAG_PURPOSE) {
177 has_purpose = true;
178 keymaster_purpose_t purpose = static_cast<keymaster_purpose_t>(entry.enumerated);
179 if (requiresSoftwareDigesting(algorithm, purpose, KM_DIGEST_NONE, key_description,
180 device_digests_))
181 return true;
182 }
183
184 return !has_purpose;
185 }
186
RequiresSoftwareDigesting(const keymaster_digest_t digest,const AuthProxy & key_description) const187 bool Keymaster1LegacySupport::RequiresSoftwareDigesting(const keymaster_digest_t digest,
188 const AuthProxy& key_description) const {
189
190 keymaster_algorithm_t algorithm;
191 if (!key_description.GetTagValue(TAG_ALGORITHM, &algorithm)) {
192 // The hardware module will return an error during keygen.
193 return false;
194 }
195
196 if (supports_all_) return false;
197
198 bool has_purpose = false;
199 for (auto& entry : key_description) {
200 if (entry.tag == TAG_PURPOSE) {
201 has_purpose = true;
202 keymaster_purpose_t purpose = static_cast<keymaster_purpose_t>(entry.enumerated);
203 if (requiresSoftwareDigesting(algorithm, purpose, digest, key_description,
204 device_digests_))
205 return true;
206 }
207 }
208
209 /*
210 * If the key does not have a purpose it is unusable, i.e., for private key operations.
211 * The public key operations which don't need purpose authorization may as well be done
212 * in software. This also addresses a bug by which begin operation on keys without purpose and
213 * unauthorized digest which is also not supported by the wrapped KM1 device fail with
214 * KM_UNSUPPORTED_DIGEST although they should not fail during the begin operation.
215 * If it has a purpose and we reach this point we did not find unsupported digests, and
216 * therefore do not required software digesting.
217 */
218 return !has_purpose;
219 }
220
221 template <>
GenerateKey(const AuthorizationSet & key_description,UniquePtr<Key> attest_key,const KeymasterBlob & issuer_subject,KeymasterKeyBlob * key_blob,AuthorizationSet * hw_enforced,AuthorizationSet * sw_enforced,CertificateChain * cert_chain) const222 keymaster_error_t Keymaster1ArbitrationFactory<EcdsaKeymaster1KeyFactory>::GenerateKey(
223 const AuthorizationSet& key_description, //
224 UniquePtr<Key> attest_key, //
225 const KeymasterBlob& issuer_subject, //
226 KeymasterKeyBlob* key_blob, //
227 AuthorizationSet* hw_enforced, //
228 AuthorizationSet* sw_enforced, //
229 CertificateChain* cert_chain) const {
230 if (legacy_support_.RequiresSoftwareDigesting(key_description)) {
231 return software_digest_factory_.GenerateKey(key_description, move(attest_key),
232 issuer_subject, key_blob, hw_enforced,
233 sw_enforced, cert_chain);
234 } else {
235 AuthorizationSet mutable_key_description = key_description;
236 keymaster_ec_curve_t curve;
237 if (key_description.GetTagValue(TAG_EC_CURVE, &curve)) {
238 // Keymaster1 doesn't know about EC curves. We need to translate to key size.
239 uint32_t key_size_from_curve;
240 keymaster_error_t error = EcCurveToKeySize(curve, &key_size_from_curve);
241 if (error != KM_ERROR_OK) {
242 return error;
243 }
244
245 uint32_t key_size_from_desc;
246 if (key_description.GetTagValue(TAG_KEY_SIZE, &key_size_from_desc)) {
247 if (key_size_from_desc != key_size_from_curve) {
248 return KM_ERROR_INVALID_ARGUMENT;
249 }
250 } else {
251 mutable_key_description.push_back(TAG_KEY_SIZE, key_size_from_curve);
252 }
253 }
254
255 return passthrough_factory_.GenerateKey(mutable_key_description, move(attest_key),
256 issuer_subject, key_blob, hw_enforced, sw_enforced,
257 cert_chain);
258 }
259 }
260
261 template <>
LoadKey(KeymasterKeyBlob && key_material,const AuthorizationSet & additional_params,AuthorizationSet && hw_enforced,AuthorizationSet && sw_enforced,UniquePtr<Key> * key) const262 keymaster_error_t Keymaster1ArbitrationFactory<EcdsaKeymaster1KeyFactory>::LoadKey(
263 KeymasterKeyBlob&& key_material, const AuthorizationSet& additional_params,
264 AuthorizationSet&& hw_enforced, AuthorizationSet&& sw_enforced, UniquePtr<Key>* key) const {
265 keymaster_digest_t digest;
266 if (!additional_params.GetTagValue(TAG_DIGEST, &digest)) {
267 digest = KM_DIGEST_NONE;
268 }
269 bool requires_software_digesting =
270 legacy_support_.RequiresSoftwareDigesting(digest, AuthProxy(hw_enforced, sw_enforced));
271 auto rc = software_digest_factory_.LoadKey(move(key_material), additional_params,
272 move(hw_enforced), move(sw_enforced), key);
273 if (rc != KM_ERROR_OK) return rc;
274 if (!requires_software_digesting) {
275 (*key)->key_factory() = &passthrough_factory_;
276 }
277 return KM_ERROR_OK;
278 }
279
280 template <>
LoadKey(KeymasterKeyBlob && key_material,const AuthorizationSet & additional_params,AuthorizationSet && hw_enforced,AuthorizationSet && sw_enforced,UniquePtr<Key> * key) const281 keymaster_error_t Keymaster1ArbitrationFactory<RsaKeymaster1KeyFactory>::LoadKey(
282 KeymasterKeyBlob&& key_material, const AuthorizationSet& additional_params,
283 AuthorizationSet&& hw_enforced, AuthorizationSet&& sw_enforced, UniquePtr<Key>* key) const {
284 keymaster_digest_t digest;
285 if (!additional_params.GetTagValue(TAG_DIGEST, &digest)) {
286 digest = KM_DIGEST_NONE;
287 }
288 bool requires_software_digesting =
289 legacy_support_.RequiresSoftwareDigesting(digest, AuthProxy(hw_enforced, sw_enforced));
290 auto rc = software_digest_factory_.LoadKey(move(key_material), additional_params,
291 move(hw_enforced), move(sw_enforced), key);
292 if (rc != KM_ERROR_OK) return rc;
293 if (!requires_software_digesting) {
294 (*key)->key_factory() = &passthrough_factory_;
295 }
296 return KM_ERROR_OK;
297 }
298
299 } // namespace keymaster
300