diff options
author | Bruce Beare <bruce.j.beare@intel.com> | 2016-05-02 08:39:28 -0700 |
---|---|---|
committer | Bruce Beare <bruce.j.beare@intel.com> | 2016-05-06 13:13:06 -0700 |
commit | 5e73541ac39b627586f653fbabc7fd84fbda5414 (patch) | |
tree | c19cafaf9e383f8887329ab1d884acf90825dcde | |
parent | 80aa74eba68f03c97ae7c6955c0a9428037ea011 (diff) | |
download | intel-5e73541ac39b627586f653fbabc7fd84fbda5414.tar.gz |
Reland "chaabi: initial commit for libkeymaster"
This reverts commit 58b25e17098adddf41a0ee53912cf99ac2759e1d.
Also conditions the Android.mk file to not build for non-chaabi-source builds.
Change-Id: Ic827a7c74ece2c3456873988da29022d4e90de45
Signed-off-by: Beare, Bruce J <bruce.j.beare@intel.com>
4 files changed, 756 insertions, 0 deletions
diff --git a/peripheral/keystore/chaabi/libkeymaster/Android.mk b/peripheral/keystore/chaabi/libkeymaster/Android.mk new file mode 100644 index 0000000..f94e5bc --- /dev/null +++ b/peripheral/keystore/chaabi/libkeymaster/Android.mk @@ -0,0 +1,22 @@ +LOCAL_PATH:= $(call my-dir) + +ifeq ($(INTEL_CHAABI_KEYSTORE_SOURCE_BUILD),true) + +include $(CLEAR_VARS) +LOCAL_MODULE := libkeymaster +LOCAL_MODULE_TAGS := optional + +LOCAL_SRC_FILES := src/sep_keymaster.c +LOCAL_C_INCLUDES += \ + $(LOCAL_PATH)/include \ + external/openssl/include +LOCAL_CFLAGS += -DDX_CC_HOST -DDX_CC54_SUPPORTED +LOCAL_SHARED_LIBRARIES := libc libdx_cc7 libcrypto libcutils + +LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_C_INCLUDES) +LOCAL_COPY_HEADERS_TO := libsepkeymaster +LOCAL_COPY_HEADERS += include/sep_keymaster.h + +include $(BUILD_SHARED_LIBRARY) + +endif diff --git a/peripheral/keystore/chaabi/libkeymaster/include/fw_interface.h b/peripheral/keystore/chaabi/libkeymaster/include/fw_interface.h new file mode 100644 index 0000000..75f3e47 --- /dev/null +++ b/peripheral/keystore/chaabi/libkeymaster/include/fw_interface.h @@ -0,0 +1,153 @@ +/************************************************************************* +** Copyright (C) 2013-2016 Intel Corporation. All rights reserved. ** +** ** +** Permission is hereby granted, free of charge, to any person ** +** obtaining a copy of this software and associated documentation ** +** files (the "Software"), to deal in the Software without ** +** restriction, including without limitation the rights to use, copy, ** +** modify, merge, publish, distribute, sublicense, and/or sell copies ** +** of the Software, and to permit persons to whom the Software is ** +** furnished to do so, subject to the following conditions: ** +** ** +** The above copyright notice and this permission notice shall be ** +** included in all copies or substantial portions of the Software. ** +** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, ** +** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF ** +** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND ** +** NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS ** +** BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ** +** ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN ** +** CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE ** +** SOFTWARE. ** +*************************************************************************/ + +#ifndef __TEE_SEP_FW_INTERFACE_KEYSTORE_H__ +#define __TEE_SEP_FW_INTERFACE_KEYSTORE_H__ + +#include <stdint.h> + +#define SYM_KEY_SIZE_BYTES 32 +#define HMAC_SIZE_BYTES 32 +#define IVV_SIZE_BYTES 16 +#define BLOB_LAYOUT_VERSION 1 +#define INTEL_KEYMASTER_MAX_MESSAGE_SIZE 4000 + +enum keymaster_key_type +{ + KEY_TYPE_RSA = 1, + KEY_TYPE_DSA, + KEY_TYPE_EC +}; + +/*! + * Parameters needed to generate an RSA key. + */ +struct keymaster_rsa_keygen_params +{ + uint32_t modulus_size; + uint32_t reserved; + uint64_t public_exponent; +}; + +/*! + * \brief The keymaster_import_key_data struct + * Paramaters that are required to import a key pair + */ +struct keymaster_import_key_data +{ + uint32_t modulus_size; /*!< The size of the modulus in bytes */ + uint32_t pub_exp_size; /*!< The size of the public exponent size */ + uint32_t priv_exp_size; /*!< The size of the private exponent size */ + uint32_t buffer[]; /*!< A concatination of modulus, public and priv exponents */ +}; + +/*! + * \brief The keymaster_import_gen_request struct + * This struct defines the layout of a key import and key generate request as received from the + * higherlevel keystore + */ +struct keymaster_import_gen_request +{ + enum keymaster_key_type key_type; /*!< The type of the key material that follows */ + uint8_t key_data[]; /*!< RSA keygen = struct keymaster_rsa_keygen_params + RSA import_key = struct keymaster_import_key_data */ +}; + +struct keymaster_get_keypair_data +{ + uint32_t modulus_size; + uint32_t pub_exp_size; + uint8_t buffer[]; +}; + +/*! + * \brief The keymaster_signing_cmd_data struct + * Structure passed from userspace containing the data needed for signing + */ +struct keymaster_signing_cmd_data +{ + uint32_t key_blob_length; /*!< The length of the key blob */ + uint32_t data_length; /*!< The length of the data to be signed */ + uint32_t buffer[]; /*!< A concatination of key blob and data block to be signed */ +}; + +/*! + * \brief The length_data_generic struct + * A generic structure to hold the length of a piece of data and the data itself + */ +struct length_data_generic +{ + uint32_t length; /*!< The length of the data */ + uint8_t data[]; /*!< The generic data */ +}; + +enum intel_keymaster_cmd +{ + KEYMASTER_CMD_GENERATE_KEYPAIR = 1, + KEYMASTER_CMD_IMPORT_KEYPAIR, + KEYMASTER_CMD_GET_KEYPAIR_PUBLIC, + KEYMASTER_CMD_DELETE_KEYPAIR, + KEYMASTER_CMD_DELETE_ALL, + KEYMASTER_CMD_SIGN_DATA, + KEYMASTER_CMD_VERIFY_DATA, + KEYMASTER_CMD_GENERATE_KEYPAIR_GKEK = 101, + KEYMASTER_CMD_GET_KEYPAIR_PUBLIC_GKEK, + KEYMASTER_RSP_FLAG = 0x80000000 // responses are flagged with cmd_id with msb changed to 1 +}; + +/*! + * \brief The key_blob_layout struct + */ +struct key_blob_layout +{ + uint8_t magic[4]; /*!< "KBLB" */ + uint32_t version; /*!< Blob layout version */ + uint8_t hmac[HMAC_SIZE_BYTES]; /*!< HMAC calculated over the key blob */ + uint8_t wrapKey[SYM_KEY_SIZE_BYTES]; /*!< Wrapping key encrypted with KEK */ + uint8_t iv[IVV_SIZE_BYTES]; /*!< IV for the wrapping key */ + uint32_t key_type; /*!< The type of key contained in the blob (RSA) */ + uint32_t exponent_size; /*!< The size of the exponent buffer in bytes*/ + uint32_t modulus_size; /*!< The size of the modulus buffer in bytes */ + uint32_t priv_key_size; /*!< The size of the private key buffer in bytes */ + uint32_t key_data[]; /*!< Exponent, modulus, and encrypted private key */ +}; + +/*! + * \brief The raw_cmd_layout struct the layout of the command buffer that is received from the HAL + */ +struct raw_cmd_layout +{ + uint32_t cmd_id; /*!< The command to be executed */ + uint32_t cmd_length; /*!< The lenght of the buffer that follows */ + uint8_t buf[]; /*!< The main body of the command */ +}; + +struct raw_resp_layout +{ + uint32_t resp_id; /*!< The result id of the executed command */ + uint32_t resp_length; /*!< The lenght of the buffer that follows */ + uint32_t result_code; /*!< The result status of the command */ + uint8_t buf[]; /*!< The response data of the call */ +}; + +#endif diff --git a/peripheral/keystore/chaabi/libkeymaster/include/sep_keymaster.h b/peripheral/keystore/chaabi/libkeymaster/include/sep_keymaster.h new file mode 100644 index 0000000..d9122e4 --- /dev/null +++ b/peripheral/keystore/chaabi/libkeymaster/include/sep_keymaster.h @@ -0,0 +1,75 @@ +/************************************************************************* +** Copyright (C) 2013-2016 Intel Corporation. All rights reserved. ** +** ** +** Permission is hereby granted, free of charge, to any person ** +** obtaining a copy of this software and associated documentation ** +** files (the "Software"), to deal in the Software without ** +** restriction, including without limitation the rights to use, copy, ** +** modify, merge, publish, distribute, sublicense, and/or sell copies ** +** of the Software, and to permit persons to whom the Software is ** +** furnished to do so, subject to the following conditions: ** +** ** +** The above copyright notice and this permission notice shall be ** +** included in all copies or substantial portions of the Software. ** +** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, ** +** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF ** +** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND ** +** NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS ** +** BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ** +** ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN ** +** CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE ** +** SOFTWARE. ** +*************************************************************************/ + +#ifndef __SEP_TEE_KEYMASTER_H__ +#define __SEP_TEE_KEYMASTER_H__ + +#include <stdint.h> + +typedef enum +{ + SEP_KEYMASTER_SUCCESS = 0, + SEP_KEYMASTER_BAD_PARAMETER, + SEP_KEYMASTER_CMD_BUFFER_TOO_BIG, + SEP_KEYMASTER_RSP_BUFFER_TOO_SMALL, + SEP_KEYMASTER_CC_INIT_FAILURE, + SEP_KEYMASTER_FAILURE +} sep_keymaster_return_t; + + +#ifdef __cplusplus +extern "C" { +#endif + +/*! + * Send a keymaster command to sep, and waits for a response + * \param cmd_buffer : Pointer to command buffer + * \param cmd_length : Number of command bytes + * \param rsp_buffer : Pointer to response buffer + * \param rsp_length [IN/OUT]: [IN] sizeof response buffer, [OUT] actual size of response + * \return SEP_KEYMASTER_CMD_SUCCESS on success + */ +sep_keymaster_return_t sep_keymaster_send_cmd(const uint8_t * const cmd_buffer, + uint32_t cmd_length, + uint8_t * const rsp_buffer, + uint32_t * const rsp_length); + +/*! + * Generates public and private RSA keys and returns them and their sizes + * \param pub_key_size [OUT]: Size of the public key in DER format + * \param pub_key [OUT]: Pointer to the public key buffer, must be freed by caller! + * \param prv_key_size [OUT]: Size of the key blob containing encrypted private key. + * \param prv_key [OUT]: Pointer to the key blob buffer containing encrypted private key. + Must be freed by caller! + * \return SEP_KEYMASTER_SUCCESS on success + */ +sep_keymaster_return_t tee_token_gen_shared_rsa(size_t *pub_key_size, + uint8_t **pub_key, + size_t *prv_key_size, + uint8_t **prv_key); +#ifdef __cplusplus +} +#endif + + +#endif diff --git a/peripheral/keystore/chaabi/libkeymaster/src/sep_keymaster.c b/peripheral/keystore/chaabi/libkeymaster/src/sep_keymaster.c new file mode 100644 index 0000000..a043841 --- /dev/null +++ b/peripheral/keystore/chaabi/libkeymaster/src/sep_keymaster.c @@ -0,0 +1,506 @@ +/************************************************************************* +** Copyright (C) 2013-2016 Intel Corporation. All rights reserved. ** +** ** +** Permission is hereby granted, free of charge, to any person ** +** obtaining a copy of this software and associated documentation ** +** files (the "Software"), to deal in the Software without ** +** restriction, including without limitation the rights to use, copy, ** +** modify, merge, publish, distribute, sublicense, and/or sell copies ** +** of the Software, and to permit persons to whom the Software is ** +** furnished to do so, subject to the following conditions: ** +** ** +** The above copyright notice and this permission notice shall be ** +** included in all copies or substantial portions of the Software. ** +** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, ** +** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF ** +** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND ** +** NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS ** +** BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ** +** ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN ** +** CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE ** +** SOFTWARE. ** +*************************************************************************/ + +#include "sep_keymaster.h" +#include "fw_interface.h" + +#include <stddef.h> +#include <stdint.h> +#include <string.h> + +#include "tee_client_api.h" +#include "dx_cclib.h" + +#include <openssl/evp.h> +#include <openssl/bio.h> +#include <openssl/rsa.h> +#include <openssl/err.h> +#include <openssl/x509.h> +#include <openssl/pem.h> + +#include <cutils/log.h> + +static const uint8_t keystore_app_uuid[] = "INTELKEYSTOREAPP"; +#define TEE_INVALID_PARAMETER 0xCAB15002 +#define TEE_INVALID_SIZE 0xCAB15003 +#define PUBKEY_BUF_SZ 1024 + +/*! + * \brief send_to_sep Package a buffer for delivery to sep and invoke a command and + * return the result of the invoked command + * \param cmd_id The id of the command the is to be executed in sep FW + * \param in_buf The input buffer that is to be passed to sep + * \param in_buf_size the size of the buffer + * \param out_buf The buffer in which to store the response + * \param out_buf_size [IN/OUT] [IN] the size available in out_buf, [OUT] The actual size of out_buf + * \return SEP_KEYMASTER_SUCCESS on success + */ +static int32_t send_to_sep(uint32_t cmd_id, uint8_t *in_buf, uint32_t in_buf_size, + uint8_t *out_buf, uint32_t *out_buf_size) +{ + TEEC_Context context; + TEEC_Session session; + TEEC_Operation operation; + TEEC_Result ret; + TEEC_SharedMemory input; + TEEC_SharedMemory output; + uint32_t retOrigin = 0; + TEEC_UUID applet_uuid; + + memset((void *)&operation, 0, sizeof(operation)); + memset((void *)&input, 0, sizeof(input)); + memset((void *)&output, 0, sizeof(output)); + memset((void *)&context, 0, sizeof(context)); + memcpy(&applet_uuid, &keystore_app_uuid, 16); + + ret = DX_CclibInit(); + if (ret != TEEC_SUCCESS) + { + ret = SEP_KEYMASTER_CC_INIT_FAILURE; + goto FinLib; + } + + ret = TEEC_InitializeContext(NULL, &context); + if (ret != TEEC_SUCCESS) + { + ret = SEP_KEYMASTER_CC_INIT_FAILURE; + goto FinContext; + } + + ret = TEEC_OpenSession(&context, &session, &applet_uuid, + TEEC_LOGIN_PUBLIC, NULL, NULL, &retOrigin); + if (ret != TEEC_SUCCESS) + { + ret = SEP_KEYMASTER_CC_INIT_FAILURE; + goto FinSession; + } + + // Map the input buffer and register it as shared memory + input.size = in_buf_size; + input.flags = TEEC_MEM_INPUT; + input.buffer = in_buf; + + ret = TEEC_RegisterSharedMemory(&context, &input); + if (ret != TEEC_SUCCESS) + { + ret = SEP_KEYMASTER_CC_INIT_FAILURE; + goto FinInput; + } + + //update the output shared memory and register it as a shared buffer + output.size = *out_buf_size; + output.flags = TEEC_MEM_OUTPUT; + output.buffer = out_buf; + + ret = TEEC_RegisterSharedMemory(&context, &output); + if (ret != TEEC_SUCCESS) + { + ret = SEP_KEYMASTER_CC_INIT_FAILURE; + goto FinOutput; + } + + TEEC_PARAM_TYPE_SET(operation.paramTypes, 0, TEEC_VALUE_INPUT); // size of input buffer + TEEC_PARAM_TYPE_SET(operation.paramTypes, 1, TEEC_MEMREF_WHOLE); // the input buffer + TEEC_PARAM_TYPE_SET(operation.paramTypes, 2, TEEC_VALUE_INOUT); // the size needed for output + TEEC_PARAM_TYPE_SET(operation.paramTypes, 3, TEEC_MEMREF_WHOLE); // the output buffer + + operation.params[0].value.a = in_buf_size; + operation.params[1].memref.parent = &input; + operation.params[2].value.a = *out_buf_size; + operation.params[3].memref.parent = &output; + + ret = TEEC_InvokeCommand(&session, cmd_id, &operation, &retOrigin); + if (ret != TEEC_SUCCESS) + { + if (ret == TEE_INVALID_PARAMETER) + ret = SEP_KEYMASTER_BAD_PARAMETER; + else if (ret == TEE_INVALID_SIZE) + ret = SEP_KEYMASTER_RSP_BUFFER_TOO_SMALL; + else + ret = SEP_KEYMASTER_FAILURE; + goto FinOutput; + } + + // Ensure to tell the caller the actual size of the response + *out_buf_size = operation.params[2].value.a; + +FinOutput: + TEEC_ReleaseSharedMemory(&output); + +FinInput: + TEEC_ReleaseSharedMemory(&input); + +FinSession: + TEEC_CloseSession(&session); + +FinContext: + TEEC_FinalizeContext(&context); + +FinLib: + DX_CclibFini(); + + return ret; +} + +/*! + * \brief generate_import_key + * Handle requests to generate or import a key. the function takes the raw command and returns + * a properly formatted response message. + * \param cb_layout The raw message received from the caller, intrepreted as struct raw_cmd_layout + * \param res_layout The raw response buffer, intrepreted as struct raw_resp_layout + * \param rsp_length [IN/OUT] [IN] the size available in the response buf, [OUT] actual size uzed + * \return sep_keymaster_return_t, depending on status + */ +static sep_keymaster_return_t generate_import_key(struct raw_cmd_layout *cb_layout, + struct raw_resp_layout *res_layout, + uint32_t *rsp_length) +{ + struct keymaster_import_gen_request *imp_gen; + sep_keymaster_return_t ret; + + if (cb_layout->cmd_length < sizeof(struct keymaster_import_gen_request)) + return SEP_KEYMASTER_BAD_PARAMETER; + + imp_gen = (struct keymaster_import_gen_request *)cb_layout->buf; + + if (imp_gen->key_type != KEY_TYPE_RSA) + return SEP_KEYMASTER_BAD_PARAMETER; + + ret = send_to_sep(cb_layout->cmd_id, imp_gen->key_data, + cb_layout->cmd_length - sizeof(int32_t), //Just pass the key material to sep + res_layout->buf, + rsp_length); + + return ret; +} + +sep_keymaster_return_t sep_keymaster_send_cmd(const uint8_t * const cmd_buffer, + uint32_t cmd_length, + uint8_t * const rsp_buffer, + uint32_t * const rsp_length) +{ + int32_t ret = SEP_KEYMASTER_SUCCESS; + struct raw_cmd_layout *cb_layout; + struct raw_resp_layout *res_layout; + uint32_t in_out_resp_size; + + if (cmd_buffer == NULL || cmd_length < sizeof(struct raw_cmd_layout) || + cmd_length > INTEL_KEYMASTER_MAX_MESSAGE_SIZE || + rsp_buffer == NULL || rsp_length == NULL || + *rsp_length < sizeof(struct raw_resp_layout)) + return SEP_KEYMASTER_BAD_PARAMETER; + + cb_layout = (struct raw_cmd_layout *)cmd_buffer; + res_layout = (struct raw_resp_layout *)rsp_buffer; + in_out_resp_size = *rsp_length - sizeof(struct raw_resp_layout); + + switch (cb_layout->cmd_id) + { + case KEYMASTER_CMD_GENERATE_KEYPAIR: + case KEYMASTER_CMD_GENERATE_KEYPAIR_GKEK: + case KEYMASTER_CMD_IMPORT_KEYPAIR: + ret = generate_import_key(cb_layout, res_layout, &in_out_resp_size); + break; + case KEYMASTER_CMD_GET_KEYPAIR_PUBLIC: + case KEYMASTER_CMD_GET_KEYPAIR_PUBLIC_GKEK: + case KEYMASTER_CMD_DELETE_ALL: + case KEYMASTER_CMD_SIGN_DATA: + case KEYMASTER_CMD_VERIFY_DATA: + ret = send_to_sep(cb_layout->cmd_id, cb_layout->buf, cb_layout->cmd_length, + res_layout->buf, &in_out_resp_size); + break; + case KEYMASTER_CMD_DELETE_KEYPAIR: + // we do not have to do anything for an individual key + ret = SEP_KEYMASTER_SUCCESS; + in_out_resp_size = 0; + break; + default: + ret = SEP_KEYMASTER_BAD_PARAMETER; + break; + } + + res_layout->resp_id = cb_layout->cmd_id | KEYMASTER_RSP_FLAG; + // the size of the result field is included response length + res_layout->resp_length = in_out_resp_size + sizeof(uint32_t); + res_layout->result_code = ret; + // the overall response is the data buffer + the default headers + *rsp_length = in_out_resp_size + sizeof(struct raw_resp_layout); + + return ret; +} + +static sep_keymaster_return_t sep_keymaster_unwrap_pubkey(const uint8_t *keyBlob, + const size_t keyBlobLength, + uint32_t *pubkey_len, + uint8_t **pubkey_ptr) +{ + struct raw_cmd_layout *cmd_buf; + uint8_t cmd_buf_raw[INTEL_KEYMASTER_MAX_MESSAGE_SIZE]; + struct raw_resp_layout *rsp_buf; + uint8_t rsp_buf_raw[INTEL_KEYMASTER_MAX_MESSAGE_SIZE]; + struct length_data_generic *key_blob; + uint32_t cmd_len, rsp_len; + sep_keymaster_return_t sep_ret; + struct keymaster_import_gen_request *public_key; + struct keymaster_get_keypair_data *rsa_public_key; + uint32_t rsp_result_and_data_length; + BIO *out = NULL; + RSA *rsa = NULL; + EVP_PKEY *pkey = NULL; + char buf[256] = {0}; + + if ((keyBlob == NULL) || (keyBlobLength == 0)) + { + return SEP_KEYMASTER_BAD_PARAMETER; + } + + cmd_buf = (struct raw_cmd_layout *)cmd_buf_raw; + rsp_buf = (struct raw_resp_layout *)rsp_buf_raw; + + cmd_buf->cmd_id = KEYMASTER_CMD_GET_KEYPAIR_PUBLIC_GKEK; + cmd_buf->cmd_length = keyBlobLength + sizeof(struct length_data_generic); + cmd_len = cmd_buf->cmd_length + sizeof(struct raw_resp_layout); + + if (cmd_len > INTEL_KEYMASTER_MAX_MESSAGE_SIZE) + { + ALOGE("keyBlob is too big, keyBlobLength = %u", keyBlobLength); + return SEP_KEYMASTER_CMD_BUFFER_TOO_BIG; + } + + key_blob = (struct length_data_generic *)cmd_buf->buf; + key_blob->length = keyBlobLength; + memcpy(key_blob->data, keyBlob, keyBlobLength); + + rsp_len = INTEL_KEYMASTER_MAX_MESSAGE_SIZE; + + sep_ret = sep_keymaster_send_cmd((uint8_t *)cmd_buf, cmd_len, (uint8_t *)rsp_buf, &rsp_len); + if (sep_ret != SEP_KEYMASTER_SUCCESS) + { + ALOGE("sep_keymaster_send_cmd() returned error %d", sep_ret); + return SEP_KEYMASTER_FAILURE; + } + + // response should contain at least rsp_id, rsp_result_and_data_length and result + if (rsp_len < offsetof(struct raw_resp_layout, buf)) + { + ALOGE("response is too short, rsp_len = %u", rsp_len); + return SEP_KEYMASTER_RSP_BUFFER_TOO_SMALL; + } + + // rsp_result_and_data_length should include at least the result field + if (rsp_buf->resp_length < sizeof(sep_keymaster_return_t)) + { + ALOGE("rsp_result_and_data_length too small, rsp_result_and_data_length = %u", + rsp_buf->resp_length); + return SEP_KEYMASTER_RSP_BUFFER_TOO_SMALL; + } + + // the result must indicate success + if (rsp_buf->result_code != SEP_KEYMASTER_SUCCESS) + { + ALOGE("firmware returned result is not successful, result = 0x%x", rsp_buf->result_code); + return SEP_KEYMASTER_FAILURE; + } + + public_key = (struct keymaster_import_gen_request *)rsp_buf->buf; + + if (public_key->key_type != KEY_TYPE_RSA) + { + ALOGE("key type other than RSA is not yet supported"); + return SEP_KEYMASTER_FAILURE; + } + + rsa_public_key = (struct keymaster_get_keypair_data *)public_key->key_data; + + rsp_result_and_data_length = rsa_public_key->modulus_size + + rsa_public_key->pub_exp_size + + offsetof(struct keymaster_get_keypair_data, buffer) + + offsetof(struct keymaster_import_gen_request, key_data) + + sizeof(sep_keymaster_return_t); + if (rsp_result_and_data_length != rsp_buf->resp_length) + { + ALOGE("rsp_result_and_data_length %u does not match rsp_result_and_data_length %u", + rsp_result_and_data_length, rsp_buf->resp_length); + return SEP_KEYMASTER_FAILURE; + } + + if (rsp_buf->resp_length + offsetof(struct raw_resp_layout, result_code) != rsp_len) + { + ALOGE("rsp_result_and_data_length %u is inconsistent with rsp_len %u", + rsp_buf->resp_length, rsp_len); + return SEP_KEYMASTER_FAILURE; + } + + // convert to PEM encoded format + rsa = RSA_new(); + if (rsa == NULL) + { + ALOGE("Memory allocation for rsa failed"); + return SEP_KEYMASTER_FAILURE; + } + + rsa->n = BN_bin2bn(rsa_public_key->buffer, rsa_public_key->modulus_size, NULL); + if (rsa->n == NULL) + { + ALOGE("Couldn't create modulus from public key byte array"); + sep_ret = SEP_KEYMASTER_FAILURE; + goto out; + } + + rsa->e = BN_bin2bn(rsa_public_key->buffer + rsa_public_key->modulus_size, + rsa_public_key->pub_exp_size, NULL); + if (rsa->e == NULL) + { + ALOGE("Couldn't create public exponent from public key byte array"); + sep_ret = SEP_KEYMASTER_FAILURE; + goto out; + } + + pkey = EVP_PKEY_new(); + if (pkey == NULL) + { + ALOGE("Memory allocation for pkey failed"); + sep_ret = SEP_KEYMASTER_FAILURE; + goto out; + } + + if (!EVP_PKEY_assign_RSA(pkey, rsa)) + { + ALOGE("Couldn't assign rsa to pkey\n"); + sep_ret = SEP_KEYMASTER_FAILURE; + goto out; + } + + out = BIO_new(BIO_s_mem()); + if (out == NULL) + { + ALOGE("Couldn't create a new bio\n"); + sep_ret = SEP_KEYMASTER_FAILURE; + goto out; + } + + if (PEM_write_bio_PUBKEY(out, pkey) != 1) + { + ALOGE("Couldn't write pkey to bio\n"); + sep_ret = SEP_KEYMASTER_FAILURE; + goto out; + } + + *pubkey_ptr = calloc(PUBKEY_BUF_SZ, 1); + if (*pubkey_ptr == NULL) + { + ALOGE("Could not assign menory\n"); + sep_ret = SEP_KEYMASTER_FAILURE; + goto out; + } + + size_t available = PUBKEY_BUF_SZ; + + // While there is Data in BIO, read line by line. Public cannot be larger that Private. + while (BIO_gets(out, buf, sizeof(buf)) > 0) + { + if (available >= strlen(buf)) + { + strcat((char *)*pubkey_ptr, buf); + available -= strlen(buf); + } + else + { + ALOGE("Insufficient space to public key\n"); + sep_ret = SEP_KEYMASTER_FAILURE; + goto out; + } + } + + *pubkey_len = strlen((const char *)*pubkey_ptr); + +out: + BIO_free_all(out); + EVP_PKEY_free(pkey); + return 0; +} + +sep_keymaster_return_t tee_token_gen_shared_rsa(size_t *pub_key_size, + uint8_t **pub_key, + size_t *prv_key_size, + uint8_t **prv_key) +{ + struct raw_cmd_layout *cmd_layout; + struct keymaster_import_gen_request *req_body; + struct keymaster_rsa_keygen_params *key_config; + struct raw_resp_layout *resp; + struct length_data_generic *blob_load; + uint32_t ret; + int32_t req_size = sizeof(struct raw_cmd_layout) + + sizeof(struct keymaster_import_gen_request) + + sizeof(struct keymaster_rsa_keygen_params); + + uint8_t req_buff[req_size]; + + //create the overall request structure + cmd_layout = (struct raw_cmd_layout *)req_buff; + cmd_layout->cmd_id = KEYMASTER_CMD_GENERATE_KEYPAIR_GKEK; + cmd_layout->cmd_length = sizeof(struct keymaster_import_gen_request) + + sizeof(struct keymaster_rsa_keygen_params); + + //define the type of request + req_body = (struct keymaster_import_gen_request *)cmd_layout->buf; + req_body->key_type = KEY_TYPE_RSA; + + // define the properties of the key that we are going to generate + key_config = (struct keymaster_rsa_keygen_params *)req_body->key_data; + key_config->modulus_size = 2048; + key_config->public_exponent = 0x10001; + + *pub_key_size = 2048; + *pub_key = malloc(*pub_key_size); + if (*pub_key == NULL) + { + ALOGE("failed to malloc public key\n"); + return SEP_KEYMASTER_FAILURE; + } + + *prv_key_size = INTEL_KEYMASTER_MAX_MESSAGE_SIZE; + *prv_key = malloc(*prv_key_size); + if (*prv_key == NULL) + { + ALOGE("Allocating key blob failed\n"); + return SEP_KEYMASTER_FAILURE; + } + + ret = sep_keymaster_send_cmd((uint8_t *)cmd_layout, req_size, *prv_key, prv_key_size); + if (ret != SEP_KEYMASTER_SUCCESS) + { + ALOGE("sep_keymaster_send_cmd failed 0x%08X\n", ret); + return SEP_KEYMASTER_FAILURE; + } + + // remove the response transport headers from the keyblob so we point to the actual key blob + resp = (struct raw_resp_layout *)*prv_key; + blob_load = (struct length_data_generic *)resp->buf; + + *prv_key_size -= sizeof(struct raw_resp_layout) + sizeof(struct length_data_generic); + memmove(*prv_key, blob_load->data, *prv_key_size); + + return sep_keymaster_unwrap_pubkey(*prv_key, *prv_key_size, pub_key_size, pub_key); +} |