#include <tee_internal_api.h>
#include <km_ta_defines.h>
#include <internal.h>
+#include <crypto_asymmetric.h>
#include <crypto_symmetric.h>
#include <crypto_auth.h>
#include <crypto_derive.h>
+#include <crypto_digest.h>
#include <km_serialization.h>
#include <cmd_exec.h>
#include <log.h>
#define KM_TA_ALG_AES_CFB 0x50005050
const uint32_t AES_BLOCK_SIZE = 16; // in bytes
+const uint32_t RSA_BLOCK_SIZE = 512; // in bytes, assumes max RSA key size 4096 bits
static uint32_t KM_AlgoType2TeeType(int algo)
return TEE_SUCCESS;
}
+static uint32_t KM_Hash2TeeAlgo(int hash)
+{
+ switch (hash) {
+ case HASH_SHA1: return TEE_ALG_SHA1;
+ case HASH_SHA256: return TEE_ALG_SHA256;
+ case HASH_SHA384: return TEE_ALG_SHA384;
+ case HASH_SHA512: return TEE_ALG_SHA512;
+ default: return 0;
+ }
+}
+
+static uint32_t KM_DigestSizeFromHash(int hash)
+{
+ // returned in bytes
+ switch (hash) {
+ case HASH_SHA1: return 20;
+ case HASH_SHA256: return 32;
+ case HASH_SHA384: return 48;
+ case HASH_SHA512: return 64;
+ default: return 0;
+ }
+}
+
+static uint32_t KM_AlgoHash2SignVerifyAlgo(int algo, int hash)
+{
+ switch (algo) {
+ case ALGO_RSA_SV: {
+ switch (hash) {
+ case HASH_SHA1: return TEE_ALG_RSASSA_PKCS1_PSS_MGF1_SHA1;
+ case HASH_SHA256: return TEE_ALG_RSASSA_PKCS1_PSS_MGF1_SHA256;
+ case HASH_SHA384: return TEE_ALG_RSASSA_PKCS1_PSS_MGF1_SHA384;
+ case HASH_SHA512: return TEE_ALG_RSASSA_PKCS1_PSS_MGF1_SHA512;
+ default: return 0; // TODO more SV algs unsupported
+ }
+ }
+ case ALGO_DSA_SV: {
+ switch (hash) {
+ case HASH_SHA1: return TEE_ALG_DSA_SHA1;
+ default: return 0; // TODO more SV algs unsupported
+ }
+ }
+ case ALGO_ECDSA_SV: {
+ // TODO unsupported
+ return 0;
+ }
+ default: return 0;
+ }
+}
+
TEE_Result KM_ExecCmdGenerateKey(TEE_Param param[4])
{
TEE_Result ret = TEE_SUCCESS;
uint32_t type = KM_AlgoType2TeeType(param[0].value.a);
uint32_t key_bits_size = param[0].value.b;
-
uint32_t objId_size = KM_KEY_ID_SIZE;
uint32_t *objId = (uint32_t*)malloc(objId_size);
+
if (objId == NULL) {
LOG("Failed to allocate object ID buffer");
ret = TEE_ERROR_OUT_OF_MEMORY;
goto clean;
}
+ if (type == 0) {
+ LOG("Unsupported key type provided: %u", type);
+ ret = TEE_ERROR_BAD_PARAMETERS;
+ goto clean;
+ }
+
ret = KM_CreateRandomKey(type, key_bits_size, &hndl);
if (TEE_SUCCESS != ret) {
LOG("Failed to randomize new key");
goto clean;
}
+
ret = KM_SaveKey(NULL, 0, hndl, objId, objId_size);
if (TEE_SUCCESS != ret) {
LOG("Failed to save generated key");
return TEE_ERROR_BAD_PARAMETERS;
}
+ if (algo == 0) {
+ LOG("Unsupported algorithm provided: %u", algo);
+ return TEE_ERROR_BAD_PARAMETERS;
+ }
+
ret = KM_DeserializeInput(param[1].memref.buffer, param[1].memref.size,
&input, &input_data, &iv_data, &key_id_data,
&key_data, &ae_data, &tag_data);
TEE_OperationHandle operation = TEE_HANDLE_NULL;
SymmetricInput *input = NULL;
InputData *input_data = NULL;
- IVData *iv_data = NULL;
KeyId *key_id_data = NULL;
Key *key_data = NULL;
- char ownIVFlag = 0;
- uint32_t *iv = NULL;
- uint32_t iv_size = 0;
void *out = NULL;
- uint32_t out_size = 0;
- uint32_t out_size_pad = 0;
+ uint32_t out_size = RSA_BLOCK_SIZE;
uint32_t type = 0;
uint32_t algo = KM_Algo2TeeAlgo(param[0].value.a);
}
ret = KM_DeserializeInput(param[1].memref.buffer, param[1].memref.size,
- &input, &input_data, &iv_data, &key_id_data,
+ &input, &input_data, NULL, &key_id_data,
&key_data, NULL, NULL);
if (ret != TEE_SUCCESS) {
LOG("Failed to deserialize data from input buffer");
return TEE_ERROR_BAD_PARAMETERS;
}
- out_size_pad = AES_BLOCK_SIZE - (input_data->data_size % AES_BLOCK_SIZE);
- out_size = input_data->data_size + out_size_pad;
+ if (key_id_data) {
+ ret = KM_CreateOperationWithKeyId(key_id_data->data, key_id_data->data_size, mode, algo,
+ &operation);
+ } else if (key_data) {
+ type = KM_AlgoType2TeeType(param[0].value.a);
+ ret = KM_CreateOperationWithKey(key_data->key.data, key_data->key.data_size, type, mode,
+ algo, key_data->key_bits_size, &operation);
+ }
+ if (TEE_SUCCESS != ret) {
+ return ret;
+ }
+
out = malloc(out_size);
if (out == NULL) {
LOG("Failed to allocate output buffer");
goto clean;
}
- if (iv_data) {
- iv = iv_data->data;
- iv_size = iv_data->data_size;
- } else {
- // create empty (zeroed) IV based on AES block size
- ownIVFlag = 1;
- iv_size = AES_BLOCK_SIZE;
- iv = malloc(iv_size);
- if (iv == NULL) {
- LOG("Failed to allocate IV buffer");
- ret = TEE_ERROR_OUT_OF_MEMORY;
- goto clean;
- }
- memset(iv, 0x00, iv_size);
+ if (commandID == CMD_ENCRYPT)
+ ret = KM_AsymmetricEncrypt(operation, input_data->data, input_data->data_size,
+ out, &out_size);
+ else
+ ret = KM_AsymmetricDecrypt(operation, input_data->data, input_data->data_size,
+ out, &out_size);
+
+ if (TEE_SUCCESS != ret) {
+ goto clean;
}
- if (algo == KM_TA_ALG_AES_CFB) {
- ret = KM_SymmetricCrypt_AES_CFB(key_id_data->data, key_id_data->data_size, mode, iv, iv_size,
- input_data->data, input_data->data_size, out, &out_size);
- } else {
- if (key_id_data) {
- ret = KM_CreateOperationWithKeyId(key_id_data->data, key_id_data->data_size, mode, algo, &operation);
- } else if (key_data) {
- type = KM_AlgoType2TeeType(param[0].value.a);
- ret = KM_CreateOperationWithKey(key_data->key.data, key_data->key.data_size, type, mode,
- algo, key_data->key_bits_size, &operation);
- }
+ if (0 != KM_ParamsSerializationInit(param[2].memref.buffer, param[2].memref.size, &input)
+ || 0 != KM_ParamsSerializeOutData(input, out, out_size)) {
+ ret = TEE_ERROR_BAD_PARAMETERS;
+ }
- if (TEE_SUCCESS != ret) {
- goto clean;
- }
+clean:
+ free(out);
+ if (operation != TEE_HANDLE_NULL) TEE_FreeOperation(operation);
+ return ret;
+}
- ret = KM_SymmetricCrypt(operation, iv, iv_size, input_data->data, input_data->data_size,
- out, &out_size);
+TEE_Result KM_ExecCmdSign(TEE_Param param[4])
+{
+ TEE_Result ret = TEE_SUCCESS;
+ TEE_OperationHandle digestOperation = TEE_HANDLE_NULL;
+ TEE_OperationHandle operation = TEE_HANDLE_NULL;
+ SymmetricInput *input = NULL;
+ InputData *input_data = NULL;
+ KeyId *key_id_data = NULL;
+ Key *key_data = NULL;
+
+ void *digest = NULL;
+ uint32_t digest_size = 0;
+ void *out = NULL;
+ uint32_t out_size = 0;
+ uint32_t out_size_pad = 0;
+
+ uint32_t type = 0;
+ uint32_t algo = KM_AlgoHash2SignVerifyAlgo(param[0].value.a, param[0].value.b);
+
+ if (algo == 0) {
+ LOG("Unsupported algorithm provided: %u", algo);
+ return TEE_ERROR_BAD_PARAMETERS;
}
+ if (0 != KM_ParamsDeserializationInit(param[1].memref.buffer, param[1].memref.size, &input)
+ || 0 != KM_ParamsDeserializeInputData(input, &input_data)
+ || 0 != KM_ParamsDeserializeKeyId(input, &key_id_data)
+ || 0 != KM_ParamsDeserializeKey(input, &key_data)) {
+ return TEE_ERROR_BAD_PARAMETERS;
+ }
+
+ KM_ParamsDump(input, input_data, NULL, key_data, key_id_data, NULL, NULL, NULL);
+
+ if (!input_data) {
+ LOG("There needs to be InputData!");
+ return TEE_ERROR_BAD_PARAMETERS;
+ }
+
+ if ((NULL != key_data && NULL != key_id_data) || (NULL == key_data && NULL == key_id_data)) {
+ LOG("You need to specify key or keyId. At least one and only one.");
+ return TEE_ERROR_BAD_PARAMETERS;
+ }
+
+ if (key_id_data) {
+ ret = KM_CreateOperationWithKeyId(key_id_data->data, key_id_data->data_size,
+ TEE_MODE_SIGN, algo, &operation);
+ } else if (key_data) {
+ type = KM_AlgoType2TeeType(param[0].value.a);
+ ret = KM_CreateOperationWithKey(key_data->key.data, key_data->key.data_size, type,
+ TEE_MODE_SIGN, algo, key_data->key_bits_size, &operation);
+ }
+
+ ret = KM_CreateDigestOperation(KM_Hash2TeeAlgo(param[0].value.b), &digestOperation);
+ if (TEE_SUCCESS != ret) {
+ LOG("Failed to create digest operation");
+ goto clean;
+ }
+
+ digest_size = KM_DigestSizeFromHash(param[0].value.b);
+ digest = malloc(digest_size);
+ if (digest == NULL) {
+ LOG("Failed to allocate buffer for digest");
+ ret = TEE_ERROR_OUT_OF_MEMORY;
+ goto clean;
+ }
+
+ out_size_pad = RSA_BLOCK_SIZE;
+ out_size = input_data->data_size + out_size_pad;
+ out = malloc(out_size);
+ if (out == NULL) {
+ LOG("Failed to allocate output buffer");
+ ret = TEE_ERROR_OUT_OF_MEMORY;
+ goto clean;
+ }
+
+ ret = KM_Digest(digestOperation, input_data->data, input_data->data_size,
+ digest, &digest_size);
if (TEE_SUCCESS != ret) {
goto clean;
}
- LOG("LKDEBUG out_size = %u", out_size);
+ ret = KM_AsymmetricSign(operation, digest, digest_size, out, &out_size);
+ if (TEE_SUCCESS != ret) {
+ goto clean;
+ }
if (0 != KM_ParamsSerializationInit(param[2].memref.buffer, param[2].memref.size, &input)
|| 0 != KM_ParamsSerializeOutData(input, out, out_size)) {
clean:
free(out);
- if (ownIVFlag) free(iv);
+ free(digest);
+ if (digestOperation != TEE_HANDLE_NULL) TEE_FreeOperation(digestOperation);
+ if (operation != TEE_HANDLE_NULL) TEE_FreeOperation(operation);
+ return ret;
+}
+
+TEE_Result KM_ExecCmdVerify(TEE_Param param[4])
+{
+ TEE_Result ret = TEE_ERROR_NOT_IMPLEMENTED;
+ TEE_OperationHandle digestOperation = TEE_HANDLE_NULL;
+ TEE_OperationHandle operation = TEE_HANDLE_NULL;
+ SymmetricInput *input = NULL;
+ InputData *input_data = NULL;
+ IVData *iv_data = NULL;
+ KeyId *key_id_data = NULL;
+ Key *key_data = NULL;
+
+ void* digest = NULL;
+ uint32_t digest_size = 0;
+
+ uint32_t type = 0;
+ uint32_t algo = KM_AlgoHash2SignVerifyAlgo(param[0].value.a, param[0].value.b);
+
+ if (algo == 0) {
+ LOG("Unsupported algorithm provided: %u", algo);
+ return TEE_ERROR_BAD_PARAMETERS;
+ }
+
+ if (0 != KM_ParamsDeserializationInit(param[1].memref.buffer, param[1].memref.size, &input)
+ || 0 != KM_ParamsDeserializeInputData(input, &input_data)
+ || 0 != KM_ParamsDeserializeIVData(input, &iv_data)
+ || 0 != KM_ParamsDeserializeKeyId(input, &key_id_data)
+ || 0 != KM_ParamsDeserializeKey(input, &key_data)) {
+ return TEE_ERROR_BAD_PARAMETERS;
+ }
+
+ KM_ParamsDump(input, input_data, iv_data, key_data, key_id_data, NULL, NULL, NULL);
+
+ if (!input_data) {
+ LOG("There needs to be InputData!");
+ return TEE_ERROR_BAD_PARAMETERS;
+ }
+
+ if ((NULL != key_data && NULL != key_id_data) || (NULL == key_data && NULL == key_id_data)) {
+ LOG("You need to specify key or keyId. At least one and only one.");
+ return TEE_ERROR_BAD_PARAMETERS;
+ }
+
+ ret = KM_CreateDigestOperation(KM_Hash2TeeAlgo(param[0].value.b), &digestOperation);
+ if (TEE_SUCCESS != ret) {
+ LOG("Failed to create digest operation");
+ goto clean;
+ }
+
+ if (key_id_data) {
+ ret = KM_CreateOperationWithKeyId(key_id_data->data, key_id_data->data_size,
+ TEE_MODE_VERIFY, algo, &operation);
+ } else if (key_data) {
+ type = KM_AlgoType2TeeType(param[0].value.a);
+ ret = KM_CreateOperationWithKey(key_data->key.data, key_data->key.data_size, type,
+ TEE_MODE_VERIFY, algo, key_data->key_bits_size, &operation);
+ }
+
+ digest_size = KM_DigestSizeFromHash(param[0].value.b);
+ digest = malloc(digest_size);
+ if (digest == NULL) {
+ LOG("Failed to allocate buffer for digest");
+ ret = TEE_ERROR_OUT_OF_MEMORY;
+ goto clean;
+ }
+
+ ret = KM_Digest(digestOperation, input_data->data, input_data->data_size,
+ digest, &digest_size);
+ if (TEE_SUCCESS != ret) {
+ goto clean;
+ }
+
+ ret = KM_AsymmetricVerify(operation, digest, digest_size,
+ iv_data->data, iv_data->data_size);
+
+clean:
+ free(digest);
+ if (digestOperation != TEE_HANDLE_NULL) TEE_FreeOperation(digestOperation);
if (operation != TEE_HANDLE_NULL) TEE_FreeOperation(operation);
return ret;
}
--- /dev/null
+/*
+ * Copyright (c) 2017 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * 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
+ */
+/*
+ * @file crypto_asymmetric.c
+ * @author Lukasz Kostyra (l.kostyra@samsung.com)
+ * @version 1.0
+ * @brief Implementation of Global Platform Internal API usage (asymmetric operations)
+ */
+
+#include "crypto_asymmetric.h"
+#include "log.h"
+
+TEE_Result KM_AsymmetricEncrypt(TEE_OperationHandle hndl, void *input, uint32_t input_size,
+ void *output, uint32_t *output_size)
+{
+ TEE_Result ret = TEE_SUCCESS;
+
+ LOG("Asym encrypt");
+ ret = TEE_AsymmetricEncrypt(hndl, NULL, 0, input, input_size, output, output_size);
+ if (TEE_SUCCESS != ret) {
+ LOG("TEE_AsymmetricEncrypt has failed with=%x.", ret);
+ return ret;
+ }
+
+ LOG("Asym encrypt done");
+ return ret;
+}
+
+TEE_Result KM_AsymmetricDecrypt(TEE_OperationHandle hndl, void *input, uint32_t input_size,
+ void *output, uint32_t *output_size)
+{
+ TEE_Result ret = TEE_SUCCESS;
+
+ LOG("Asym decrypt");
+ ret = TEE_AsymmetricDecrypt(hndl, NULL, 0, input, input_size, output, output_size);
+ if (TEE_SUCCESS != ret) {
+ LOG("TEE_AsymmetricEncrypt has failed with=%x.", ret);
+ return ret;
+ }
+
+ LOG("Asym encrypt done");
+ return ret;
+}
+
+TEE_Result KM_AsymmetricSign(TEE_OperationHandle hndl, void *digest, uint32_t digest_size,
+ void *signature, uint32_t *sig_size)
+{
+ TEE_Result ret = TEE_SUCCESS;
+
+ LOG("Asym sign");
+ ret = TEE_AsymmetricSignDigest(hndl, NULL, 0, digest, digest_size, signature, sig_size);
+ if (TEE_SUCCESS != ret) {
+ LOG("TEE_AsymmetricSignDigest has failed with=%x.", ret);
+ return ret;
+ }
+
+ LOG("Asym sign done");
+ return ret;
+}
+
+TEE_Result KM_AsymmetricVerify(TEE_OperationHandle hndl, void *digest, uint32_t digest_size,
+ void *signature, uint32_t sig_size)
+{
+ TEE_Result ret = TEE_SUCCESS;
+
+ LOG("Asym verify");
+ ret = TEE_AsymmetricVerifyDigest(hndl, NULL, 0, digest, digest_size, signature, sig_size);
+ if (TEE_SUCCESS != ret && TEE_ERROR_SIGNATURE_INVALID != ret) {
+ LOG("TEE_AsymmetricVerifyDigest has failed with=%x.", ret);
+ return ret;
+ }
+
+ LOG("Asym verify done");
+ return ret;
+}
\ No newline at end of file
S_VAR_NOT_USED(param_types);
switch (commandID) {
- case CMD_GENERATE_KEY:
+ case CMD_GENERATE_KEY: {
LOGD("!!! Generate key !!!");
ret = KM_ExecCmdGenerateKey(param);
break;
- case CMD_GENERATE_IV:
+ }
+ case CMD_GENERATE_IV: {
LOGD("!!! Generate IV !!!");
KM_GenerateIV(param[1].memref.buffer, param[1].memref.size);
break;
- case CMD_GENERATE_KEY_PWD:
- LOGD("!!! Generate PWD !!!");
+ }
+ case CMD_GENERATE_KEY_PWD: {
+ LOGD("!!! Generate Key from PWD !!!");
ret = KM_ExecCmdGenerateKeyPwd(param);
break;
+ }
case CMD_ENCRYPT:
- case CMD_DECRYPT:
+ case CMD_DECRYPT: {
LOGD("!!! %scrypt !!!", (commandID == CMD_ENCRYPT) ? "En" : "De");
+
if (ALGO_AES_CTR != param[0].value.a &&
ALGO_AES_CBC != param[0].value.a &&
ALGO_AES_GCM != param[0].value.a &&
ret = TEE_ERROR_BAD_PARAMETERS;
break;
}
+
if (ALGO_AES_GCM == param[0].value.a) {
ret = KM_ExecCmdAuth(commandID, param);
} else if (ALGO_RSA == param[0].value.a) {
} else {
ret = KM_ExecCmdSymmetric(commandID, param);
}
+
+ break;
+ }
+ case CMD_SIGN: {
+ LOGD("!!! Sign !!!");
+
+ if (ALGO_RSA_SV != param[0].value.a &&
+ ALGO_DSA_SV != param[0].value.a &&
+ ALGO_ECDSA_SV != param[0].value.a) {
+ LOG("Invalid key type=%d for command=%d.", param[0].value.a, commandID);
+ ret = TEE_ERROR_BAD_PARAMETERS;
+ break;
+ }
+
+ ret = KM_ExecCmdSign(param);
+ break;
+ }
+ case CMD_VERIFY: {
+ LOGD("!!! Verify !!!");
+
+ if (ALGO_RSA_SV != param[0].value.a &&
+ ALGO_DSA_SV != param[0].value.a &&
+ ALGO_ECDSA_SV != param[0].value.a) {
+ LOG("Invalid key type=%d for command=%d.", param[0].value.a, commandID);
+ ret = TEE_ERROR_BAD_PARAMETERS;
+ break;
+ }
+
+ ret = KM_ExecCmdVerify(param);
break;
- default:
+ }
+ default: {
LOG("Unknown commandID=%d.", commandID);
ret = TEE_ERROR_BAD_PARAMETERS;
}
+ }
// inform about successful operation, or about an error in authorization
// TEEC API has less return codes than TEE, so about some exceptional
param[0].value.a = KM_TA_SUCCESS;
if (ret != TEE_SUCCESS) {
switch (ret) {
- case TEE_ERROR_MAC_INVALID:
+ case TEE_ERROR_MAC_INVALID: {
// error during auth cipher - revert return to success because
// TEE Client API does not support this error code and inform
// about it thorugh our own TA-specific return value
ret = TEE_SUCCESS;
param[0].value.a = KM_TA_ERROR_AUTH_FAILED;
break;
- default:
+ }
+ case TEE_ERROR_SIGNATURE_INVALID: {
+ // error during signature verification - same as above
+ ret = TEE_SUCCESS;
+ param[0].value.a = KM_TA_ERROR_SIGNATURE;
+ }
+ default: {
// other errors can be added here as we need
param[0].value.a = KM_TA_ERROR_GENERIC;
break;
}
+ }
}
return ret;