• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2017 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "import_key.h"
18 #include "proto_utils.h"
19 
20 #include <android-base/logging.h>
21 
22 #include <openssl/ec.h>
23 #include <openssl/evp.h>
24 #include <openssl/mem.h>
25 #include <openssl/rsa.h>
26 #include <openssl/pkcs8.h>
27 
28 namespace android {
29 namespace hardware {
30 namespace keymaster {
31 
32 // HAL
33 using ::android::hardware::keymaster::V4_0::Algorithm;
34 using ::android::hardware::keymaster::V4_0::EcCurve;
35 using ::android::hardware::keymaster::V4_0::KeyFormat;
36 using ::android::hardware::keymaster::V4_0::Tag;
37 using ::android::hardware::keymaster::V4_0::TagType;
38 
39 // App
40 using ::nugget::app::keymaster::ECKey;
41 
42 // BoringSSL
43 using bssl::UniquePtr;
44 
45 // std
46 using std::unique_ptr;
47 
evp_from_pkcs8_bytes(const uint8_t * bytes,size_t len)48 static EVP_PKEY *evp_from_pkcs8_bytes(const uint8_t *bytes, size_t len)
49 {
50     bssl::UniquePtr<PKCS8_PRIV_KEY_INFO> pkcs8(
51         d2i_PKCS8_PRIV_KEY_INFO(NULL, &bytes, len));
52     if (pkcs8.get() == NULL) {
53         // Translate error.
54         return nullptr;
55     }
56 
57     return EVP_PKCS82PKEY(pkcs8.get());
58 }
59 
import_key_rsa(const tag_map_t & params,const hidl_vec<uint8_t> & keyData,ImportKeyRequest * request)60 static ErrorCode import_key_rsa(const tag_map_t& params,
61                                 const hidl_vec<uint8_t>& keyData,
62                                 ImportKeyRequest *request)
63 {
64     const uint32_t *keySize = nullptr;
65     if (params.find(Tag::KEY_SIZE) != params.end()) {
66         const vector<KeyParameter>& v = params.find(Tag::KEY_SIZE)->second;
67         keySize = &v[0].f.integer;
68     }
69     const uint64_t *publicExponent = nullptr;
70     if (params.find(Tag::RSA_PUBLIC_EXPONENT) != params.end()) {
71         const vector<KeyParameter>& v =
72             params.find(Tag::RSA_PUBLIC_EXPONENT)->second;
73         publicExponent = &v[0].f.longInteger;
74     }
75 
76     bssl::UniquePtr<EVP_PKEY> pkey;
77     pkey.reset(evp_from_pkcs8_bytes(&keyData[0], keyData.size()));
78     if (pkey.get() == nullptr) {
79         // Parse error.
80         LOG(ERROR) << "ImportKey request: failed to parse PKCS8";
81         return ErrorCode::INVALID_ARGUMENT;
82     }
83 
84     const RSA *rsa = EVP_PKEY_get0_RSA(pkey.get());
85     if (rsa == nullptr) {
86         LOG(ERROR) << "ImportKey request: PKCS8 key is not RSA";
87         return ErrorCode::INVALID_ARGUMENT;
88     }
89 
90     size_t parsedKeySize = RSA_size(rsa) * 8;
91     if (keySize != nullptr && parsedKeySize != *keySize) {
92         // If specified, key size must match the PKCS8 blob.
93         LOG(ERROR) << "ImportKey request: key size parameter mis-match";
94         return ErrorCode::IMPORT_PARAMETER_MISMATCH;
95     }
96 
97     const BIGNUM *n;
98     const BIGNUM *e;
99     const BIGNUM *d;
100     RSA_get0_key(rsa, &n, &e, &d);
101     if (publicExponent != nullptr && BN_get_word(e) != *publicExponent) {
102         // If specified, the public exponent must match the PKCS8 blob.
103         LOG(ERROR) << "ImportKey request: invalid publicExponent tag: "
104                    << *publicExponent
105                    << " expected: "
106                    << BN_get_word(e);
107         return ErrorCode::IMPORT_PARAMETER_MISMATCH;
108     }
109 
110     // Key data may be invalid, and will be validated on the device
111     // anyway, so avoid duplicate work here.
112 
113     // Public exponent.
114     request->mutable_rsa()->set_e(BN_get_word(e));
115 
116     // Private exponent, zero-pad upto size of n.
117     bssl::UniquePtr<uint8_t> d_buf(
118         reinterpret_cast<uint8_t *>(OPENSSL_malloc(BN_num_bytes(n))));
119     if (!BN_bn2le_padded(d_buf.get(), BN_num_bytes(n), d)) {
120         LOG(ERROR) << "ImportKey request: bn2le failed";
121         return ErrorCode::UNKNOWN_ERROR;
122     }
123     request->mutable_rsa()->set_d(d_buf.get(), BN_num_bytes(n));
124 
125     // Modulus.
126     bssl::UniquePtr<uint8_t> n_buf(
127         reinterpret_cast<uint8_t *>(OPENSSL_malloc(BN_num_bytes(n))));
128     if (!BN_bn2le_padded(n_buf.get(), BN_num_bytes(n), n)) {
129         LOG(ERROR) << "ImportKey request: bn2le_padded failed";
130         return ErrorCode::UNKNOWN_ERROR;
131     }
132     request->mutable_rsa()->set_n(n_buf.get(), BN_num_bytes(n));
133 
134     return ErrorCode::OK;
135 }
136 
import_key_ec(const tag_map_t & params,const hidl_vec<uint8_t> & keyData,ImportKeyRequest * request)137 static ErrorCode import_key_ec(const tag_map_t& params,
138                                const hidl_vec<uint8_t>& keyData,
139                                ImportKeyRequest *request)
140 {
141     const EcCurve *curve_id = nullptr;
142     if (params.find(Tag::EC_CURVE) != params.end()) {
143         const vector<KeyParameter>& v = params.find(Tag::EC_CURVE)->second;
144         curve_id = &v[0].f.ecCurve;
145     }
146     const uint32_t *key_size = nullptr;
147     if (params.find(Tag::KEY_SIZE) != params.end()) {
148         const vector<KeyParameter>& v = params.find(Tag::KEY_SIZE)->second;
149         key_size = &v[0].f.integer;
150     }
151 
152     bssl::UniquePtr<EVP_PKEY> pkey;
153     pkey.reset(evp_from_pkcs8_bytes(&keyData[0], keyData.size()));
154     if (pkey.get() == nullptr) {
155         // Parse error.
156         LOG(ERROR) << "ImportKey request: failed to parse PKCS8";
157         return ErrorCode::INVALID_ARGUMENT;
158     }
159 
160     const EC_KEY *ec_key = EVP_PKEY_get0_EC_KEY(pkey.get());
161     if (ec_key == nullptr) {
162         LOG(ERROR) << "ImportKey request: PKCS8 key is not EC";
163         return ErrorCode::INVALID_ARGUMENT;
164     }
165 
166     EcCurve parsed_curve_id;
167     size_t parsed_key_size;
168     const EC_GROUP *group = EC_KEY_get0_group(ec_key);
169     switch (EC_GROUP_get_curve_name(group)) {
170     case NID_secp224r1:
171         parsed_curve_id = EcCurve::P_224;
172         parsed_key_size = 224;
173         break;
174     case NID_X9_62_prime256v1:
175         parsed_curve_id = EcCurve::P_256;
176         parsed_key_size = 256;
177         break;
178     case NID_secp384r1:
179         parsed_curve_id = EcCurve::P_384;
180         parsed_key_size = 384;
181         break;
182     case NID_secp521r1:
183         parsed_curve_id = EcCurve::P_521;
184         parsed_key_size = 521;
185         break;
186     default:
187         // Unsupported curve.
188         return ErrorCode::INVALID_ARGUMENT;
189     }
190 
191     if (curve_id != nullptr && *curve_id != parsed_curve_id) {
192         // Parameter mis-match.
193         LOG(ERROR) << "ImportKey: curve-id does not match PKCS8";
194         return ErrorCode::IMPORT_PARAMETER_MISMATCH;
195     }
196     if (key_size != nullptr && *key_size != parsed_key_size) {
197         // Parameter mis-match.
198         LOG(ERROR) << "ImportKey: key-size does not match PKCS8";
199         return ErrorCode::IMPORT_PARAMETER_MISMATCH;
200     }
201 
202     const BIGNUM *d = EC_KEY_get0_private_key(ec_key);
203     const EC_POINT *pub_key = EC_KEY_get0_public_key(ec_key);
204     bssl::UniquePtr<BIGNUM> x(BN_new());
205     bssl::UniquePtr<BIGNUM> y(BN_new());
206 
207     if (!EC_POINT_get_affine_coordinates_GFp(EC_KEY_get0_group(ec_key),
208                                              pub_key, x.get(), y.get(), NULL)) {
209         LOG(ERROR) << "ImportKey: failed to get public key in affine coordinates";
210         return ErrorCode::INVALID_ARGUMENT;
211     }
212 
213     // Key data may be invalid, and will be validated on the device
214     // anyway, so avoid duplicate work here.
215 
216     // Curve parameter.
217     request->mutable_ec()->set_curve_id((uint32_t)parsed_curve_id);
218 
219     // Private key.
220     const size_t field_size = (parsed_key_size + 7) >> 3;
221     unique_ptr<uint8_t[]> d_buf(new uint8_t[field_size]);
222     if (!BN_bn2le_padded(d_buf.get(), field_size, d)) {
223         LOG(ERROR) << "ImportKey request: bn2le(d) failed";
224         return ErrorCode::UNKNOWN_ERROR;
225     }
226     request->mutable_ec()->set_d(d_buf.get(), field_size);
227 
228     // Public key.
229     unique_ptr<uint8_t[]> x_buf(new uint8_t[field_size]);
230     if (!BN_bn2le_padded(x_buf.get(), field_size, x.get())) {
231         LOG(ERROR) << "ImportKey request: bn2le(x) failed";
232         return ErrorCode::UNKNOWN_ERROR;
233     }
234     request->mutable_ec()->set_x(x_buf.get(), field_size);
235 
236     unique_ptr<uint8_t[]> y_buf(new uint8_t[field_size]);
237     if (!BN_bn2le_padded(y_buf.get(), field_size, y.get())) {
238         LOG(ERROR) << "ImportKey request: bn2le(y) failed";
239         return ErrorCode::UNKNOWN_ERROR;
240     }
241     request->mutable_ec()->set_y(y_buf.get(), field_size);
242 
243     return ErrorCode::OK;
244 }
245 
import_key_raw(const tag_map_t & params,Algorithm algorithm,const hidl_vec<uint8_t> & keyData,ImportKeyRequest * request)246 static ErrorCode import_key_raw(const tag_map_t& params,
247                                 Algorithm algorithm,
248                                 const hidl_vec<uint8_t>& keyData,
249                                 ImportKeyRequest *request)
250 {
251   if (algorithm != Algorithm::AES && algorithm != Algorithm::TRIPLE_DES &&
252       algorithm != Algorithm::HMAC) {
253         LOG(ERROR) << "ImportKey request: unsupported algorithm";
254         return ErrorCode::UNSUPPORTED_ALGORITHM;
255     }
256 
257     const uint32_t *key_size = nullptr;
258     if (params.find(Tag::KEY_SIZE) != params.end()) {
259         const vector<KeyParameter>& v = params.find(Tag::KEY_SIZE)->second;
260         key_size = &v[0].f.integer;
261     }
262 
263     if (algorithm != Algorithm::TRIPLE_DES) {
264         if (key_size != nullptr && *key_size != keyData.size() * 8) {
265             LOG(ERROR) << "ImportKey request: mis-matched KEY_SIZE tag: "
266                        << ((key_size == NULL) ? -1 : *key_size)
267                        << " provided data size: "
268                        << keyData.size();
269             return ErrorCode::IMPORT_PARAMETER_MISMATCH;
270         }
271     } else {
272         if ((key_size != nullptr && *key_size != 168) ||
273             keyData.size() != 24) {
274             LOG(ERROR) << "ImportKey request: mis-matched DES KEY_SIZE tag: "
275                        << ((key_size == NULL) ? -1 : *key_size)
276                        << " provided data size: "
277                        << keyData.size();
278             return ErrorCode::IMPORT_PARAMETER_MISMATCH;
279         }
280         LOG(ERROR) << "ImportKey request: DES OK: ";
281     }
282 
283     if (keyData.size() == 0) {
284         LOG(ERROR) << "ImportKey request: invalid key size 0";
285         return ErrorCode::IMPORT_PARAMETER_MISMATCH;
286     }
287 
288     request->mutable_symmetric_key()->set_material(
289         keyData.data(), keyData.size());
290 
291     return ErrorCode::OK;
292 }
293 
import_key_request(const hidl_vec<KeyParameter> & params,KeyFormat keyFormat,const hidl_vec<uint8_t> & keyData,ImportKeyRequest * request)294 ErrorCode import_key_request(const hidl_vec<KeyParameter>& params,
295                              KeyFormat keyFormat,
296                              const hidl_vec<uint8_t>& keyData,
297                              ImportKeyRequest *request) {
298     const enum Algorithm *algorithm;
299 
300     if (keyFormat != KeyFormat::PKCS8 && keyFormat != KeyFormat::RAW) {
301         return ErrorCode::UNSUPPORTED_KEY_FORMAT;
302     }
303 
304     ErrorCode error;
305     tag_map_t tag_map;
306     error = hidl_params_to_map(params, &tag_map);
307     if (error != ErrorCode::OK) {
308         return error;
309     }
310 
311     if (tag_map.find(Tag::ALGORITHM) != tag_map.end()) {
312         // Algorithm is a required parameter.
313         const vector<KeyParameter>& v = tag_map.find(Tag::ALGORITHM)->second;
314         algorithm = &v[0].f.algorithm;
315     } else {
316         LOG(ERROR) << "ImportKey request: Algorithm Tag missing";
317         return ErrorCode::INVALID_ARGUMENT;
318     }
319 
320     if (keyFormat == KeyFormat::PKCS8) {
321         switch (*algorithm) {
322         case Algorithm::RSA:
323             error = import_key_rsa(tag_map, keyData, request);
324             break;
325         case Algorithm::EC:
326             error = import_key_ec(tag_map, keyData, request);
327             break;
328         default:
329             LOG(ERROR) << "ImportKey request: unsupported algoritm: "
330                        << (uint32_t)*algorithm;
331             return ErrorCode::UNSUPPORTED_ALGORITHM;
332             break;
333         }
334     } else {
335         error = import_key_raw(tag_map, *algorithm, keyData, request);
336     }
337 
338     if (error != ErrorCode::OK) {
339         return error;
340     }
341 
342     error = map_params_to_pb(tag_map, request->mutable_params());
343     if (error != ErrorCode::OK) {
344         LOG(ERROR) << "ImportKey request: failed to map params to pb: "
345                    << (uint32_t) error;
346         return error;
347     }
348 
349     return ErrorCode::OK;
350 }
351 
352 }  // namespace keymaster
353 }  // hardware
354 }  // android
355