Home | History | Annotate | Download | only in keymaster
      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