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 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 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 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 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 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