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