| /* |
| * Copyright (C) 2012 Samsung Electronics Co., LTD |
| * Copyright (C) 2012 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| #include <errno.h> |
| #include <string.h> |
| #include <stdint.h> |
| |
| #include <hardware/hardware.h> |
| #include <hardware/keymaster0.h> |
| |
| #include <openssl/evp.h> |
| #include <openssl/bio.h> |
| #include <openssl/rsa.h> |
| #include <openssl/err.h> |
| #include <openssl/x509.h> |
| |
| #include <UniquePtr.h> |
| |
| #define LOG_TAG "ExynosKeyMaster" |
| #include <cutils/log.h> |
| |
| #include <tlcTeeKeymaster_if.h> |
| |
| #define RSA_KEY_BUFFER_SIZE 1536 |
| #define RSA_KEY_MAX_SIZE (2048 >> 3) |
| |
| struct BIGNUM_Delete { |
| void operator()(BIGNUM* p) const { |
| BN_free(p); |
| } |
| }; |
| typedef UniquePtr<BIGNUM, BIGNUM_Delete> Unique_BIGNUM; |
| |
| struct EVP_PKEY_Delete { |
| void operator()(EVP_PKEY* p) const { |
| EVP_PKEY_free(p); |
| } |
| }; |
| typedef UniquePtr<EVP_PKEY, EVP_PKEY_Delete> Unique_EVP_PKEY; |
| |
| struct PKCS8_PRIV_KEY_INFO_Delete { |
| void operator()(PKCS8_PRIV_KEY_INFO* p) const { |
| PKCS8_PRIV_KEY_INFO_free(p); |
| } |
| }; |
| typedef UniquePtr<PKCS8_PRIV_KEY_INFO, PKCS8_PRIV_KEY_INFO_Delete> Unique_PKCS8_PRIV_KEY_INFO; |
| |
| struct RSA_Delete { |
| void operator()(RSA* p) const { |
| RSA_free(p); |
| } |
| }; |
| typedef UniquePtr<RSA, RSA_Delete> Unique_RSA; |
| |
| typedef UniquePtr<keymaster0_device_t> Unique_keymaster_device_t; |
| |
| /** |
| * Many OpenSSL APIs take ownership of an argument on success but don't free the argument |
| * on failure. This means we need to tell our scoped pointers when we've transferred ownership, |
| * without triggering a warning by not using the result of release(). |
| */ |
| #define OWNERSHIP_TRANSFERRED(obj) \ |
| typeof (obj.release()) _dummy __attribute__((unused)) = obj.release() |
| |
| /* |
| * Checks this thread's error queue and logs if necessary. |
| */ |
| static void logOpenSSLError(const char* location) { |
| int error = ERR_get_error(); |
| |
| if (error != 0) { |
| char message[256]; |
| ERR_error_string_n(error, message, sizeof(message)); |
| ALOGE("OpenSSL error in %s %d: %s", location, error, message); |
| } |
| |
| ERR_clear_error(); |
| ERR_remove_state(0); |
| } |
| |
| static int exynos_km_generate_keypair(const keymaster0_device_t* dev, |
| const keymaster_keypair_t key_type, const void* key_params, |
| uint8_t** keyBlob, size_t* keyBlobLength) { |
| teeResult_t ret = TEE_ERR_NONE; |
| |
| if (key_type != TYPE_RSA) { |
| ALOGE("Unsupported key type %d", key_type); |
| return -1; |
| } else if (key_params == NULL) { |
| ALOGE("key_params == null"); |
| return -1; |
| } |
| |
| keymaster_rsa_keygen_params_t* rsa_params = (keymaster_rsa_keygen_params_t*) key_params; |
| |
| if ((rsa_params->modulus_size != 512) && |
| (rsa_params->modulus_size != 1024) && |
| (rsa_params->modulus_size != 2048)) { |
| ALOGE("key size(%d) is not supported\n", rsa_params->modulus_size); |
| return -1; |
| } |
| |
| UniquePtr<uint8_t> keyDataPtr(reinterpret_cast<uint8_t*>(malloc(RSA_KEY_BUFFER_SIZE))); |
| if (keyDataPtr.get() == NULL) { |
| ALOGE("memory allocation is failed"); |
| return -1; |
| } |
| |
| ret = TEE_RSAGenerateKeyPair(TEE_KEYPAIR_RSACRT, keyDataPtr.get(), RSA_KEY_BUFFER_SIZE, |
| rsa_params->modulus_size, (uint32_t)rsa_params->public_exponent, |
| keyBlobLength); |
| if (ret != TEE_ERR_NONE) { |
| ALOGE("TEE_RSAGenerateKeyPair() is failed: %d", ret); |
| return -1; |
| } |
| |
| *keyBlob = keyDataPtr.release(); |
| |
| return 0; |
| } |
| |
| static int exynos_km_import_keypair(const keymaster0_device_t* dev, |
| const uint8_t* key, const size_t key_length, |
| uint8_t** key_blob, size_t* key_blob_length) { |
| uint8_t kbuf[RSA_KEY_BUFFER_SIZE]; |
| teeRsaKeyMeta_t metadata; |
| uint32_t key_len = 0; |
| teeResult_t ret = TEE_ERR_NONE; |
| |
| if (key == NULL) { |
| ALOGE("input key == NULL"); |
| return -1; |
| } else if (key_blob == NULL || key_blob_length == NULL) { |
| ALOGE("output key blob or length == NULL"); |
| return -1; |
| } |
| |
| /* decoding */ |
| Unique_PKCS8_PRIV_KEY_INFO pkcs8(d2i_PKCS8_PRIV_KEY_INFO(NULL, &key, key_length)); |
| if (pkcs8.get() == NULL) { |
| logOpenSSLError("pkcs4.get"); |
| return -1; |
| } |
| |
| /* assign to EVP */ |
| Unique_EVP_PKEY pkey(EVP_PKCS82PKEY(pkcs8.get())); |
| if (pkey.get() == NULL) { |
| logOpenSSLError("pkey.get"); |
| return -1; |
| } |
| OWNERSHIP_TRANSFERRED(pkcs8); |
| |
| /* change key format */ |
| Unique_RSA rsa(EVP_PKEY_get1_RSA(pkey.get())); |
| if (rsa.get() == NULL) { |
| logOpenSSLError("get rsa key format"); |
| return -1; |
| } |
| |
| key_len += sizeof(metadata); |
| |
| metadata.lenpubmod = BN_bn2bin(rsa->n, kbuf + key_len); |
| key_len += metadata.lenpubmod; |
| if (metadata.lenpubmod == (512 >> 3)) |
| metadata.keysize = TEE_RSA_KEY_SIZE_512; |
| else if (metadata.lenpubmod == (1024 >> 3)) |
| metadata.keysize = TEE_RSA_KEY_SIZE_1024; |
| else if (metadata.lenpubmod == (2048 >> 3)) |
| metadata.keysize = TEE_RSA_KEY_SIZE_2048; |
| else { |
| ALOGE("key size(%d) is not supported\n", metadata.lenpubmod << 3); |
| return -1; |
| } |
| |
| metadata.lenpubexp = BN_bn2bin(rsa->e, kbuf + key_len); |
| key_len += metadata.lenpubexp; |
| |
| if ((rsa->p != NULL) && (rsa->q != NULL) && (rsa->dmp1 != NULL) && |
| (rsa->dmq1 != NULL) && (rsa->iqmp != NULL)) |
| { |
| metadata.keytype = TEE_KEYPAIR_RSACRT; |
| metadata.rsacrtpriv.lenp = BN_bn2bin(rsa->p, kbuf + key_len); |
| key_len += metadata.rsacrtpriv.lenp; |
| metadata.rsacrtpriv.lenq = BN_bn2bin(rsa->q, kbuf + key_len); |
| key_len += metadata.rsacrtpriv.lenq; |
| metadata.rsacrtpriv.lendp = BN_bn2bin(rsa->dmp1, kbuf + key_len); |
| key_len += metadata.rsacrtpriv.lendp; |
| metadata.rsacrtpriv.lendq = BN_bn2bin(rsa->dmq1, kbuf + key_len); |
| key_len += metadata.rsacrtpriv.lendq; |
| metadata.rsacrtpriv.lenqinv = BN_bn2bin(rsa->iqmp, kbuf + key_len); |
| key_len += metadata.rsacrtpriv.lenqinv; |
| } else { |
| metadata.keytype = TEE_KEYPAIR_RSA; |
| metadata.rsapriv.lenpriexp = BN_bn2bin(rsa->p, kbuf + key_len); |
| key_len += metadata.rsapriv.lenprimod; |
| } |
| memcpy(kbuf, &metadata, sizeof(metadata)); |
| |
| UniquePtr<uint8_t> outPtr(reinterpret_cast<uint8_t*>(malloc(RSA_KEY_BUFFER_SIZE))); |
| if (outPtr.get() == NULL) { |
| ALOGE("memory allocation is failed"); |
| return -1; |
| } |
| |
| *key_blob_length = RSA_KEY_BUFFER_SIZE; |
| |
| ret = TEE_KeyImport(kbuf, key_len, outPtr.get(), key_blob_length); |
| if (ret != TEE_ERR_NONE) { |
| ALOGE("TEE_KeyImport() is failed: %d", ret); |
| return -1; |
| } |
| |
| *key_blob = outPtr.release(); |
| |
| return 0; |
| } |
| |
| static int exynos_km_get_keypair_public(const keymaster0_device_t* dev, |
| const uint8_t* key_blob, const size_t key_blob_length, |
| uint8_t** x509_data, size_t* x509_data_length) { |
| uint32_t bin_mod_len; |
| uint32_t bin_exp_len; |
| teeResult_t ret = TEE_ERR_NONE; |
| |
| if (x509_data == NULL || x509_data_length == NULL) { |
| ALOGE("output public key buffer == NULL"); |
| return -1; |
| } |
| |
| UniquePtr<uint8_t> binModPtr(reinterpret_cast<uint8_t*>(malloc(RSA_KEY_MAX_SIZE))); |
| if (binModPtr.get() == NULL) { |
| ALOGE("memory allocation is failed"); |
| return -1; |
| } |
| |
| UniquePtr<uint8_t> binExpPtr(reinterpret_cast<uint8_t*>(malloc(sizeof(uint32_t)))); |
| if (binExpPtr.get() == NULL) { |
| ALOGE("memory allocation is failed"); |
| return -1; |
| } |
| |
| bin_mod_len = RSA_KEY_MAX_SIZE; |
| bin_exp_len = sizeof(uint32_t); |
| |
| ret = TEE_GetPubKey(key_blob, key_blob_length, binModPtr.get(), &bin_mod_len, binExpPtr.get(), |
| &bin_exp_len); |
| if (ret != TEE_ERR_NONE) { |
| ALOGE("TEE_GetPubKey() is failed: %d", ret); |
| return -1; |
| } |
| |
| Unique_BIGNUM bn_mod(BN_new()); |
| if (bn_mod.get() == NULL) { |
| ALOGE("memory allocation is failed"); |
| return -1; |
| } |
| |
| Unique_BIGNUM bn_exp(BN_new()); |
| if (bn_exp.get() == NULL) { |
| ALOGE("memory allocation is failed"); |
| return -1; |
| } |
| |
| BN_bin2bn(binModPtr.get(), bin_mod_len, bn_mod.get()); |
| BN_bin2bn(binExpPtr.get(), bin_exp_len, bn_exp.get()); |
| |
| /* assign to RSA */ |
| Unique_RSA rsa(RSA_new()); |
| if (rsa.get() == NULL) { |
| logOpenSSLError("rsa.get"); |
| return -1; |
| } |
| |
| RSA* rsa_tmp = rsa.get(); |
| |
| rsa_tmp->n = bn_mod.release(); |
| rsa_tmp->e = bn_exp.release(); |
| |
| /* assign to EVP */ |
| Unique_EVP_PKEY pkey(EVP_PKEY_new()); |
| if (pkey.get() == NULL) { |
| logOpenSSLError("allocate EVP_PKEY"); |
| return -1; |
| } |
| |
| if (EVP_PKEY_assign_RSA(pkey.get(), rsa.get()) == 0) { |
| logOpenSSLError("assing RSA to EVP_PKEY"); |
| return -1; |
| } |
| OWNERSHIP_TRANSFERRED(rsa); |
| |
| /* change to x.509 format */ |
| int len = i2d_PUBKEY(pkey.get(), NULL); |
| if (len <= 0) { |
| logOpenSSLError("i2d_PUBKEY"); |
| return -1; |
| } |
| |
| UniquePtr<uint8_t> key(static_cast<uint8_t*>(malloc(len))); |
| if (key.get() == NULL) { |
| ALOGE("Could not allocate memory for public key data"); |
| return -1; |
| } |
| |
| unsigned char* tmp = reinterpret_cast<unsigned char*>(key.get()); |
| if (i2d_PUBKEY(pkey.get(), &tmp) != len) { |
| logOpenSSLError("Compare results"); |
| return -1; |
| } |
| |
| *x509_data_length = len; |
| *x509_data = key.release(); |
| |
| return 0; |
| } |
| |
| static int exynos_km_sign_data(const keymaster0_device_t* dev, |
| const void* params, |
| const uint8_t* keyBlob, const size_t keyBlobLength, |
| const uint8_t* data, const size_t dataLength, |
| uint8_t** signedData, size_t* signedDataLength) { |
| teeResult_t ret = TEE_ERR_NONE; |
| |
| if (data == NULL) { |
| ALOGE("input data to sign == NULL"); |
| return -1; |
| } else if (signedData == NULL || signedDataLength == NULL) { |
| ALOGE("output signature buffer == NULL"); |
| return -1; |
| } |
| |
| keymaster_rsa_sign_params_t* sign_params = (keymaster_rsa_sign_params_t*) params; |
| if (sign_params->digest_type != DIGEST_NONE) { |
| ALOGE("Cannot handle digest type %d", sign_params->digest_type); |
| return -1; |
| } else if (sign_params->padding_type != PADDING_NONE) { |
| ALOGE("Cannot handle padding type %d", sign_params->padding_type); |
| return -1; |
| } |
| |
| UniquePtr<uint8_t> signedDataPtr(reinterpret_cast<uint8_t*>(malloc(RSA_KEY_MAX_SIZE))); |
| if (signedDataPtr.get() == NULL) { |
| ALOGE("memory allocation is failed"); |
| return -1; |
| } |
| |
| *signedDataLength = RSA_KEY_MAX_SIZE; |
| |
| /* binder gives us read-only mappings we can't use with mobicore */ |
| void *tmpData = malloc(dataLength); |
| memcpy(tmpData, data, dataLength); |
| ret = TEE_RSASign(keyBlob, keyBlobLength, (const uint8_t *)tmpData, dataLength, signedDataPtr.get(), |
| signedDataLength, TEE_RSA_NODIGEST_NOPADDING); |
| free(tmpData); |
| if (ret != TEE_ERR_NONE) { |
| ALOGE("TEE_RSASign() is failed: %d", ret); |
| return -1; |
| } |
| |
| *signedData = signedDataPtr.release(); |
| |
| return 0; |
| } |
| |
| static int exynos_km_verify_data(const keymaster0_device_t* dev, |
| const void* params, |
| const uint8_t* keyBlob, const size_t keyBlobLength, |
| const uint8_t* signedData, const size_t signedDataLength, |
| const uint8_t* signature, const size_t signatureLength) { |
| bool result; |
| teeResult_t ret = TEE_ERR_NONE; |
| |
| if (signedData == NULL || signature == NULL) { |
| ALOGE("data or signature buffers == NULL"); |
| return -1; |
| } |
| |
| keymaster_rsa_sign_params_t* sign_params = (keymaster_rsa_sign_params_t*) params; |
| if (sign_params->digest_type != DIGEST_NONE) { |
| ALOGE("Cannot handle digest type %d", sign_params->digest_type); |
| return -1; |
| } else if (sign_params->padding_type != PADDING_NONE) { |
| ALOGE("Cannot handle padding type %d", sign_params->padding_type); |
| return -1; |
| } else if (signatureLength != signedDataLength) { |
| ALOGE("signed data length must be signature length"); |
| return -1; |
| } |
| |
| void *tmpSignedData = malloc(signedDataLength); |
| memcpy(tmpSignedData, signedData, signedDataLength); |
| void *tmpSig = malloc(signatureLength); |
| memcpy(tmpSig, signature, signatureLength); |
| ret = TEE_RSAVerify(keyBlob, keyBlobLength, (const uint8_t*)tmpSignedData, signedDataLength, (const uint8_t *)tmpSig, |
| signatureLength, TEE_RSA_NODIGEST_NOPADDING, &result); |
| free(tmpSignedData); |
| free(tmpSig); |
| if (ret != TEE_ERR_NONE) { |
| ALOGE("TEE_RSAVerify() is failed: %d", ret); |
| return -1; |
| } |
| |
| return (result == true) ? 0 : -1; |
| } |
| |
| /* Close an opened Exynos KM instance */ |
| static int exynos_km_close(hw_device_t *dev) { |
| free(dev); |
| return 0; |
| } |
| |
| /* |
| * Generic device handling |
| */ |
| static int exynos_km_open(const hw_module_t* module, const char* name, |
| hw_device_t** device) { |
| if (strcmp(name, KEYSTORE_KEYMASTER) != 0) |
| return -EINVAL; |
| |
| Unique_keymaster_device_t dev(new keymaster0_device_t); |
| if (dev.get() == NULL) |
| return -ENOMEM; |
| |
| dev->common.tag = HARDWARE_DEVICE_TAG; |
| dev->common.version = 1; |
| dev->common.module = (struct hw_module_t*) module; |
| dev->common.close = exynos_km_close; |
| |
| dev->flags = 0; |
| |
| dev->generate_keypair = exynos_km_generate_keypair; |
| dev->import_keypair = exynos_km_import_keypair; |
| dev->get_keypair_public = exynos_km_get_keypair_public; |
| dev->delete_keypair = NULL; |
| dev->delete_all = NULL; |
| dev->sign_data = exynos_km_sign_data; |
| dev->verify_data = exynos_km_verify_data; |
| |
| ERR_load_crypto_strings(); |
| ERR_load_BIO_strings(); |
| |
| *device = reinterpret_cast<hw_device_t*>(dev.release()); |
| |
| return 0; |
| } |
| |
| static struct hw_module_methods_t keystore_module_methods = { |
| open: exynos_km_open, |
| }; |
| |
| struct keystore_module HAL_MODULE_INFO_SYM |
| __attribute__ ((visibility ("default"))) = { |
| common: { |
| tag: HARDWARE_MODULE_TAG, |
| version_major: 1, |
| version_minor: 0, |
| id: KEYSTORE_HARDWARE_MODULE_ID, |
| name: "Keymaster Exynos HAL", |
| author: "Samsung S.LSI", |
| methods: &keystore_module_methods, |
| dso: 0, |
| reserved: {}, |
| }, |
| }; |