diff options
Diffstat (limited to 'lib/libutee/tee_api_operations.c')
-rw-r--r-- | lib/libutee/tee_api_operations.c | 1757 |
1 files changed, 1757 insertions, 0 deletions
diff --git a/lib/libutee/tee_api_operations.c b/lib/libutee/tee_api_operations.c new file mode 100644 index 0000000..c8560d3 --- /dev/null +++ b/lib/libutee/tee_api_operations.c @@ -0,0 +1,1757 @@ +/* + * Copyright (c) 2014, STMicroelectronics International N.V. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#include <stdlib.h> +#include <string.h> +#include <string_ext.h> + +#include <tee_api.h> +#include <tee_api_defines_extensions.h> +#include <tee_internal_api_extensions.h> +#include <utee_syscalls.h> +#include <utee_defines.h> +#include <util.h> +#include "tee_api_private.h" + +struct __TEE_OperationHandle { + TEE_OperationInfo info; + TEE_ObjectHandle key1; + TEE_ObjectHandle key2; + uint32_t operationState;/* Operation state : INITIAL or ACTIVE */ + uint8_t *buffer; /* buffer to collect complete blocks */ + bool buffer_two_blocks; /* True if two blocks need to be buffered */ + size_t block_size; /* Block size of cipher */ + size_t buffer_offs; /* Offset in buffer */ + uint32_t state; /* Handle to state in TEE Core */ + uint32_t ae_tag_len; /* + * tag_len in bytes for AE operation else unused + */ +}; + +/* Cryptographic Operations API - Generic Operation Functions */ + +TEE_Result TEE_AllocateOperation(TEE_OperationHandle *operation, + uint32_t algorithm, uint32_t mode, + uint32_t maxKeySize) +{ + TEE_Result res; + TEE_OperationHandle op = TEE_HANDLE_NULL; + uint32_t handle_state = 0; + size_t block_size = 1; + uint32_t req_key_usage; + bool with_private_key = false; + bool buffer_two_blocks = false; + + if (!operation) + TEE_Panic(0); + + if (algorithm == TEE_ALG_AES_XTS) + handle_state = TEE_HANDLE_FLAG_EXPECT_TWO_KEYS; + + /* Check algorithm max key size */ + switch (algorithm) { + case TEE_ALG_DSA_SHA1: + if (maxKeySize < 512) + return TEE_ERROR_NOT_SUPPORTED; + if (maxKeySize > 1024) + return TEE_ERROR_NOT_SUPPORTED; + if (maxKeySize % 64 != 0) + return TEE_ERROR_NOT_SUPPORTED; + break; + + case TEE_ALG_DSA_SHA224: + if (maxKeySize != 2048) + return TEE_ERROR_NOT_SUPPORTED; + break; + + case TEE_ALG_DSA_SHA256: + if (maxKeySize != 2048 && maxKeySize != 3072) + return TEE_ERROR_NOT_SUPPORTED; + break; + + case TEE_ALG_ECDSA_P192: + case TEE_ALG_ECDH_P192: + if (maxKeySize != 192) + return TEE_ERROR_NOT_SUPPORTED; + break; + + case TEE_ALG_ECDSA_P224: + case TEE_ALG_ECDH_P224: + if (maxKeySize != 224) + return TEE_ERROR_NOT_SUPPORTED; + break; + + case TEE_ALG_ECDSA_P256: + case TEE_ALG_ECDH_P256: + if (maxKeySize != 256) + return TEE_ERROR_NOT_SUPPORTED; + break; + + case TEE_ALG_ECDSA_P384: + case TEE_ALG_ECDH_P384: + if (maxKeySize != 384) + return TEE_ERROR_NOT_SUPPORTED; + break; + + case TEE_ALG_ECDSA_P521: + case TEE_ALG_ECDH_P521: + if (maxKeySize != 521) + return TEE_ERROR_NOT_SUPPORTED; + break; + + default: + break; + } + + /* Check algorithm mode */ + switch (algorithm) { + case TEE_ALG_AES_CTS: + case TEE_ALG_AES_XTS: + buffer_two_blocks = true; + /* FALLTHROUGH */ + case TEE_ALG_AES_ECB_NOPAD: + case TEE_ALG_AES_CBC_NOPAD: + case TEE_ALG_AES_CTR: + case TEE_ALG_AES_CCM: + case TEE_ALG_AES_GCM: + case TEE_ALG_DES_ECB_NOPAD: + case TEE_ALG_DES_CBC_NOPAD: + case TEE_ALG_DES3_ECB_NOPAD: + case TEE_ALG_DES3_CBC_NOPAD: + if (TEE_ALG_GET_MAIN_ALG(algorithm) == TEE_MAIN_ALGO_AES) + block_size = TEE_AES_BLOCK_SIZE; + else + block_size = TEE_DES_BLOCK_SIZE; + + if (mode == TEE_MODE_ENCRYPT) + req_key_usage = TEE_USAGE_ENCRYPT; + else if (mode == TEE_MODE_DECRYPT) + req_key_usage = TEE_USAGE_DECRYPT; + else + return TEE_ERROR_NOT_SUPPORTED; + break; + + case TEE_ALG_RSASSA_PKCS1_V1_5_MD5: + case TEE_ALG_RSASSA_PKCS1_V1_5_SHA1: + case TEE_ALG_RSASSA_PKCS1_V1_5_SHA224: + case TEE_ALG_RSASSA_PKCS1_V1_5_SHA256: + case TEE_ALG_RSASSA_PKCS1_V1_5_SHA384: + case TEE_ALG_RSASSA_PKCS1_V1_5_SHA512: + case TEE_ALG_RSASSA_PKCS1_PSS_MGF1_SHA1: + case TEE_ALG_RSASSA_PKCS1_PSS_MGF1_SHA224: + case TEE_ALG_RSASSA_PKCS1_PSS_MGF1_SHA256: + case TEE_ALG_RSASSA_PKCS1_PSS_MGF1_SHA384: + case TEE_ALG_RSASSA_PKCS1_PSS_MGF1_SHA512: + case TEE_ALG_DSA_SHA1: + case TEE_ALG_DSA_SHA224: + case TEE_ALG_DSA_SHA256: + case TEE_ALG_ECDSA_P192: + case TEE_ALG_ECDSA_P224: + case TEE_ALG_ECDSA_P256: + case TEE_ALG_ECDSA_P384: + case TEE_ALG_ECDSA_P521: + if (mode == TEE_MODE_SIGN) { + with_private_key = true; + req_key_usage = TEE_USAGE_SIGN; + } else if (mode == TEE_MODE_VERIFY) { + req_key_usage = TEE_USAGE_VERIFY; + } else { + return TEE_ERROR_NOT_SUPPORTED; + } + break; + + case TEE_ALG_RSAES_PKCS1_V1_5: + case TEE_ALG_RSAES_PKCS1_OAEP_MGF1_SHA1: + case TEE_ALG_RSAES_PKCS1_OAEP_MGF1_SHA224: + case TEE_ALG_RSAES_PKCS1_OAEP_MGF1_SHA256: + case TEE_ALG_RSAES_PKCS1_OAEP_MGF1_SHA384: + case TEE_ALG_RSAES_PKCS1_OAEP_MGF1_SHA512: + if (mode == TEE_MODE_ENCRYPT) { + req_key_usage = TEE_USAGE_ENCRYPT; + } else if (mode == TEE_MODE_DECRYPT) { + with_private_key = true; + req_key_usage = TEE_USAGE_DECRYPT; + } else { + return TEE_ERROR_NOT_SUPPORTED; + } + break; + + case TEE_ALG_RSA_NOPAD: + if (mode == TEE_MODE_ENCRYPT) { + req_key_usage = TEE_USAGE_ENCRYPT | TEE_USAGE_VERIFY; + } else if (mode == TEE_MODE_DECRYPT) { + with_private_key = true; + req_key_usage = TEE_USAGE_DECRYPT | TEE_USAGE_SIGN; + } else { + return TEE_ERROR_NOT_SUPPORTED; + } + break; + + case TEE_ALG_DH_DERIVE_SHARED_SECRET: + case TEE_ALG_ECDH_P192: + case TEE_ALG_ECDH_P224: + case TEE_ALG_ECDH_P256: + case TEE_ALG_ECDH_P384: + case TEE_ALG_ECDH_P521: + case TEE_ALG_HKDF_MD5_DERIVE_KEY: + case TEE_ALG_HKDF_SHA1_DERIVE_KEY: + case TEE_ALG_HKDF_SHA224_DERIVE_KEY: + case TEE_ALG_HKDF_SHA256_DERIVE_KEY: + case TEE_ALG_HKDF_SHA384_DERIVE_KEY: + case TEE_ALG_HKDF_SHA512_DERIVE_KEY: + case TEE_ALG_CONCAT_KDF_SHA1_DERIVE_KEY: + case TEE_ALG_CONCAT_KDF_SHA224_DERIVE_KEY: + case TEE_ALG_CONCAT_KDF_SHA256_DERIVE_KEY: + case TEE_ALG_CONCAT_KDF_SHA384_DERIVE_KEY: + case TEE_ALG_CONCAT_KDF_SHA512_DERIVE_KEY: + case TEE_ALG_PBKDF2_HMAC_SHA1_DERIVE_KEY: + if (mode != TEE_MODE_DERIVE) + return TEE_ERROR_NOT_SUPPORTED; + with_private_key = true; + req_key_usage = TEE_USAGE_DERIVE; + break; + + case TEE_ALG_MD5: + case TEE_ALG_SHA1: + case TEE_ALG_SHA224: + case TEE_ALG_SHA256: + case TEE_ALG_SHA384: + case TEE_ALG_SHA512: + if (mode != TEE_MODE_DIGEST) + return TEE_ERROR_NOT_SUPPORTED; + /* v1.1: flags always set for digest operations */ + handle_state |= TEE_HANDLE_FLAG_KEY_SET; + req_key_usage = 0; + break; + + case TEE_ALG_DES_CBC_MAC_NOPAD: + case TEE_ALG_AES_CBC_MAC_NOPAD: + case TEE_ALG_AES_CBC_MAC_PKCS5: + case TEE_ALG_AES_CMAC: + case TEE_ALG_DES_CBC_MAC_PKCS5: + case TEE_ALG_DES3_CBC_MAC_NOPAD: + case TEE_ALG_DES3_CBC_MAC_PKCS5: + case TEE_ALG_HMAC_MD5: + case TEE_ALG_HMAC_SHA1: + case TEE_ALG_HMAC_SHA224: + case TEE_ALG_HMAC_SHA256: + case TEE_ALG_HMAC_SHA384: + case TEE_ALG_HMAC_SHA512: + if (mode != TEE_MODE_MAC) + return TEE_ERROR_NOT_SUPPORTED; + req_key_usage = TEE_USAGE_MAC; + break; + + default: + return TEE_ERROR_NOT_SUPPORTED; + } + + op = TEE_Malloc(sizeof(*op), TEE_MALLOC_FILL_ZERO); + if (!op) + return TEE_ERROR_OUT_OF_MEMORY; + + op->info.algorithm = algorithm; + op->info.operationClass = TEE_ALG_GET_CLASS(algorithm); + op->info.mode = mode; + op->info.maxKeySize = maxKeySize; + op->info.requiredKeyUsage = req_key_usage; + op->info.handleState = handle_state; + + if (block_size > 1) { + size_t buffer_size = block_size; + + if (buffer_two_blocks) + buffer_size *= 2; + + op->buffer = TEE_Malloc(buffer_size, + TEE_USER_MEM_HINT_NO_FILL_ZERO); + if (op->buffer == NULL) { + res = TEE_ERROR_OUT_OF_MEMORY; + goto out; + } + } + op->block_size = block_size; + op->buffer_two_blocks = buffer_two_blocks; + + if (TEE_ALG_GET_CLASS(algorithm) != TEE_OPERATION_DIGEST) { + uint32_t mks = maxKeySize; + TEE_ObjectType key_type = TEE_ALG_GET_KEY_TYPE(algorithm, + with_private_key); + + /* + * If two keys are expected the max key size is the sum of + * the size of both keys. + */ + if (op->info.handleState & TEE_HANDLE_FLAG_EXPECT_TWO_KEYS) + mks /= 2; + + res = TEE_AllocateTransientObject(key_type, mks, &op->key1); + if (res != TEE_SUCCESS) + goto out; + + if (op->info.handleState & TEE_HANDLE_FLAG_EXPECT_TWO_KEYS) { + res = TEE_AllocateTransientObject(key_type, mks, + &op->key2); + if (res != TEE_SUCCESS) + goto out; + } + } + + res = utee_cryp_state_alloc(algorithm, mode, (unsigned long)op->key1, + (unsigned long)op->key2, &op->state); + if (res != TEE_SUCCESS) + goto out; + + /* + * Initialize digest operations + * Other multi-stage operations initialized w/ TEE_xxxInit functions + * Non-applicable on asymmetric operations + */ + if (TEE_ALG_GET_CLASS(algorithm) == TEE_OPERATION_DIGEST) { + res = utee_hash_init(op->state, NULL, 0); + if (res != TEE_SUCCESS) + goto out; + /* v1.1: flags always set for digest operations */ + op->info.handleState |= TEE_HANDLE_FLAG_INITIALIZED; + } + + op->operationState = TEE_OPERATION_STATE_INITIAL; + + *operation = op; + +out: + if (res != TEE_SUCCESS) { + if (res != TEE_ERROR_OUT_OF_MEMORY && + res != TEE_ERROR_NOT_SUPPORTED) + TEE_Panic(res); + if (op) { + if (op->state) { + TEE_FreeOperation(op); + } else { + TEE_Free(op->buffer); + TEE_FreeTransientObject(op->key1); + TEE_FreeTransientObject(op->key2); + TEE_Free(op); + } + } + } + + return res; +} + +void TEE_FreeOperation(TEE_OperationHandle operation) +{ + TEE_Result res; + + if (operation == TEE_HANDLE_NULL) + TEE_Panic(0); + + /* + * Note that keys should not be freed here, since they are + * claimed by the operation they will be freed by + * utee_cryp_state_free(). + */ + res = utee_cryp_state_free(operation->state); + if (res != TEE_SUCCESS) + TEE_Panic(res); + + TEE_Free(operation->buffer); + TEE_Free(operation); +} + +void TEE_GetOperationInfo(TEE_OperationHandle operation, + TEE_OperationInfo *operationInfo) +{ + if (operation == TEE_HANDLE_NULL) + TEE_Panic(0); + + if (!operationInfo) + TEE_Panic(0); + + *operationInfo = operation->info; +} + +TEE_Result TEE_GetOperationInfoMultiple(TEE_OperationHandle operation, + TEE_OperationInfoMultiple *operationInfoMultiple, + uint32_t *operationSize) +{ + TEE_Result res = TEE_SUCCESS; + TEE_ObjectInfo key_info1; + TEE_ObjectInfo key_info2; + uint32_t num_of_keys; + size_t n; + + if (operation == TEE_HANDLE_NULL) { + res = TEE_ERROR_BAD_PARAMETERS; + goto out; + } + + if (!operationInfoMultiple) { + res = TEE_ERROR_BAD_PARAMETERS; + goto out; + } + + if (!operationSize) { + res = TEE_ERROR_BAD_PARAMETERS; + goto out; + } + + num_of_keys = (*operationSize-sizeof(TEE_OperationInfoMultiple))/ + sizeof(TEE_OperationInfoKey); + + if (num_of_keys > 2) { + res = TEE_ERROR_BAD_PARAMETERS; + goto out; + } + + /* Two keys flag (TEE_ALG_AES_XTS only) */ + if ((operation->info.handleState & TEE_HANDLE_FLAG_EXPECT_TWO_KEYS) != + 0 && + (num_of_keys != 2)) { + res = TEE_ERROR_SHORT_BUFFER; + goto out; + } + + /* Clear */ + for (n = 0; n < num_of_keys; n++) { + operationInfoMultiple->keyInformation[n].keySize = 0; + operationInfoMultiple->keyInformation[n].requiredKeyUsage = 0; + } + + if (num_of_keys == 2) { + res = TEE_GetObjectInfo1(operation->key2, &key_info2); + /* Key2 is not a valid handle */ + if (res != TEE_SUCCESS) + goto out; + + operationInfoMultiple->keyInformation[1].keySize = + key_info2.keySize; + operationInfoMultiple->keyInformation[1].requiredKeyUsage = + operation->info.requiredKeyUsage; + } + + if (num_of_keys >= 1) { + res = TEE_GetObjectInfo1(operation->key1, &key_info1); + /* Key1 is not a valid handle */ + if (res != TEE_SUCCESS) { + if (num_of_keys == 2) { + operationInfoMultiple->keyInformation[1]. + keySize = 0; + operationInfoMultiple->keyInformation[1]. + requiredKeyUsage = 0; + } + goto out; + } + + operationInfoMultiple->keyInformation[0].keySize = + key_info1.keySize; + operationInfoMultiple->keyInformation[0].requiredKeyUsage = + operation->info.requiredKeyUsage; + } + + /* No key */ + operationInfoMultiple->algorithm = operation->info.algorithm; + operationInfoMultiple->operationClass = operation->info.operationClass; + operationInfoMultiple->mode = operation->info.mode; + operationInfoMultiple->digestLength = operation->info.digestLength; + operationInfoMultiple->maxKeySize = operation->info.maxKeySize; + operationInfoMultiple->handleState = operation->info.handleState; + operationInfoMultiple->operationState = operation->operationState; + operationInfoMultiple->numberOfKeys = num_of_keys; + +out: + if (res != TEE_SUCCESS && + res != TEE_ERROR_SHORT_BUFFER) + TEE_Panic(res); + + return res; +} + +void TEE_ResetOperation(TEE_OperationHandle operation) +{ + TEE_Result res; + + if (operation == TEE_HANDLE_NULL) + TEE_Panic(0); + + if (!(operation->info.handleState & TEE_HANDLE_FLAG_KEY_SET)) + TEE_Panic(0); + + operation->operationState = TEE_OPERATION_STATE_INITIAL; + + if (operation->info.operationClass == TEE_OPERATION_DIGEST) { + res = utee_hash_init(operation->state, NULL, 0); + if (res != TEE_SUCCESS) + TEE_Panic(res); + operation->info.handleState |= TEE_HANDLE_FLAG_INITIALIZED; + } else { + operation->info.handleState &= ~TEE_HANDLE_FLAG_INITIALIZED; + } +} + +TEE_Result TEE_SetOperationKey(TEE_OperationHandle operation, + TEE_ObjectHandle key) +{ + TEE_Result res; + uint32_t key_size = 0; + TEE_ObjectInfo key_info; + + if (operation == TEE_HANDLE_NULL) { + res = TEE_ERROR_BAD_PARAMETERS; + goto out; + } + + if (operation->operationState != TEE_OPERATION_STATE_INITIAL) { + res = TEE_ERROR_BAD_PARAMETERS; + goto out; + } + + if (key == TEE_HANDLE_NULL) { + /* Operation key cleared */ + TEE_ResetTransientObject(operation->key1); + res = TEE_ERROR_BAD_PARAMETERS; + goto out; + } + + /* No key for digest operation */ + if (operation->info.operationClass == TEE_OPERATION_DIGEST) { + res = TEE_ERROR_BAD_PARAMETERS; + goto out; + } + + /* Two keys flag not expected (TEE_ALG_AES_XTS excluded) */ + if ((operation->info.handleState & TEE_HANDLE_FLAG_EXPECT_TWO_KEYS) != + 0) { + res = TEE_ERROR_BAD_PARAMETERS; + goto out; + } + + res = TEE_GetObjectInfo1(key, &key_info); + /* Key is not a valid handle */ + if (res != TEE_SUCCESS) + goto out; + + /* Supplied key has to meet required usage */ + if ((key_info.objectUsage & operation->info.requiredKeyUsage) != + operation->info.requiredKeyUsage) { + res = TEE_ERROR_BAD_PARAMETERS; + goto out; + } + + if (operation->info.maxKeySize < key_info.keySize) { + res = TEE_ERROR_BAD_PARAMETERS; + goto out; + } + + key_size = key_info.keySize; + + TEE_ResetTransientObject(operation->key1); + operation->info.handleState &= ~TEE_HANDLE_FLAG_KEY_SET; + + res = TEE_CopyObjectAttributes1(operation->key1, key); + if (res != TEE_SUCCESS) + goto out; + + operation->info.handleState |= TEE_HANDLE_FLAG_KEY_SET; + + operation->info.keySize = key_size; + +out: + if (res != TEE_SUCCESS && + res != TEE_ERROR_CORRUPT_OBJECT && + res != TEE_ERROR_STORAGE_NOT_AVAILABLE) + TEE_Panic(res); + + return res; +} + +TEE_Result TEE_SetOperationKey2(TEE_OperationHandle operation, + TEE_ObjectHandle key1, TEE_ObjectHandle key2) +{ + TEE_Result res; + uint32_t key_size = 0; + TEE_ObjectInfo key_info1; + TEE_ObjectInfo key_info2; + + if (operation == TEE_HANDLE_NULL) { + res = TEE_ERROR_BAD_PARAMETERS; + goto out; + } + + if (operation->operationState != TEE_OPERATION_STATE_INITIAL) { + res = TEE_ERROR_BAD_PARAMETERS; + goto out; + } + + /* + * Key1/Key2 and/or are not initialized and + * Either both keys are NULL or both are not NULL + */ + if (key1 == TEE_HANDLE_NULL || key2 == TEE_HANDLE_NULL) { + /* Clear operation key1 (if needed) */ + if (key1 == TEE_HANDLE_NULL) + TEE_ResetTransientObject(operation->key1); + /* Clear operation key2 (if needed) */ + if (key2 == TEE_HANDLE_NULL) + TEE_ResetTransientObject(operation->key2); + res = TEE_ERROR_BAD_PARAMETERS; + goto out; + } + + /* No key for digest operation */ + if (operation->info.operationClass == TEE_OPERATION_DIGEST) { + res = TEE_ERROR_BAD_PARAMETERS; + goto out; + } + + /* Two keys flag expected (TEE_ALG_AES_XTS only) */ + if ((operation->info.handleState & TEE_HANDLE_FLAG_EXPECT_TWO_KEYS) == + 0) { + res = TEE_ERROR_BAD_PARAMETERS; + goto out; + } + + res = TEE_GetObjectInfo1(key1, &key_info1); + /* Key1 is not a valid handle */ + if (res != TEE_SUCCESS) + goto out; + + /* Supplied key has to meet required usage */ + if ((key_info1.objectUsage & operation->info. + requiredKeyUsage) != operation->info.requiredKeyUsage) { + res = TEE_ERROR_BAD_PARAMETERS; + goto out; + } + + res = TEE_GetObjectInfo1(key2, &key_info2); + /* Key2 is not a valid handle */ + if (res != TEE_SUCCESS) { + if (res == TEE_ERROR_CORRUPT_OBJECT) + res = TEE_ERROR_CORRUPT_OBJECT_2; + goto out; + } + + /* Supplied key has to meet required usage */ + if ((key_info2.objectUsage & operation->info. + requiredKeyUsage) != operation->info.requiredKeyUsage) { + res = TEE_ERROR_BAD_PARAMETERS; + goto out; + } + + /* + * AES-XTS (the only multi key algorithm supported, requires the + * keys to be of equal size. + */ + if (operation->info.algorithm == TEE_ALG_AES_XTS && + key_info1.keySize != key_info2.keySize) { + res = TEE_ERROR_BAD_PARAMETERS; + goto out; + + } + + if (operation->info.maxKeySize < key_info1.keySize) { + res = TEE_ERROR_BAD_PARAMETERS; + goto out; + } + + /* + * Odd that only the size of one key should be reported while + * size of two key are used when allocating the operation. + */ + key_size = key_info1.keySize; + + TEE_ResetTransientObject(operation->key1); + TEE_ResetTransientObject(operation->key2); + operation->info.handleState &= ~TEE_HANDLE_FLAG_KEY_SET; + + res = TEE_CopyObjectAttributes1(operation->key1, key1); + if (res != TEE_SUCCESS) + goto out; + + res = TEE_CopyObjectAttributes1(operation->key2, key2); + if (res != TEE_SUCCESS) { + if (res == TEE_ERROR_CORRUPT_OBJECT) + res = TEE_ERROR_CORRUPT_OBJECT_2; + goto out; + } + + operation->info.handleState |= TEE_HANDLE_FLAG_KEY_SET; + + operation->info.keySize = key_size; + +out: + if (res != TEE_SUCCESS && + res != TEE_ERROR_CORRUPT_OBJECT && + res != TEE_ERROR_CORRUPT_OBJECT_2 && + res != TEE_ERROR_STORAGE_NOT_AVAILABLE && + res != TEE_ERROR_STORAGE_NOT_AVAILABLE_2) + TEE_Panic(res); + + return res; +} + +void TEE_CopyOperation(TEE_OperationHandle dst_op, TEE_OperationHandle src_op) +{ + TEE_Result res; + + if (dst_op == TEE_HANDLE_NULL || src_op == TEE_HANDLE_NULL) + TEE_Panic(0); + if (dst_op->info.algorithm != src_op->info.algorithm) + TEE_Panic(0); + if (src_op->info.operationClass != TEE_OPERATION_DIGEST) { + TEE_ObjectHandle key1 = TEE_HANDLE_NULL; + TEE_ObjectHandle key2 = TEE_HANDLE_NULL; + + if (src_op->info.handleState & TEE_HANDLE_FLAG_KEY_SET) { + key1 = src_op->key1; + key2 = src_op->key2; + } + + if ((src_op->info.handleState & + TEE_HANDLE_FLAG_EXPECT_TWO_KEYS) == 0) { + TEE_SetOperationKey(dst_op, key1); + } else { + TEE_SetOperationKey2(dst_op, key1, key2); + } + } + dst_op->info.handleState = src_op->info.handleState; + dst_op->info.keySize = src_op->info.keySize; + dst_op->operationState = src_op->operationState; + + if (dst_op->buffer_two_blocks != src_op->buffer_two_blocks || + dst_op->block_size != src_op->block_size) + TEE_Panic(0); + + if (dst_op->buffer != NULL) { + if (src_op->buffer == NULL) + TEE_Panic(0); + + memcpy(dst_op->buffer, src_op->buffer, src_op->buffer_offs); + dst_op->buffer_offs = src_op->buffer_offs; + } else if (src_op->buffer != NULL) { + TEE_Panic(0); + } + + res = utee_cryp_state_copy(dst_op->state, src_op->state); + if (res != TEE_SUCCESS) + TEE_Panic(res); +} + +/* Cryptographic Operations API - Message Digest Functions */ + +static void init_hash_operation(TEE_OperationHandle operation, const void *IV, + uint32_t IVLen) +{ + TEE_Result res; + + /* + * Note : IV and IVLen are never used in current implementation + * This is why coherent values of IV and IVLen are not checked + */ + res = utee_hash_init(operation->state, IV, IVLen); + if (res != TEE_SUCCESS) + TEE_Panic(res); + operation->buffer_offs = 0; + operation->info.handleState |= TEE_HANDLE_FLAG_INITIALIZED; +} + +void TEE_DigestUpdate(TEE_OperationHandle operation, + const void *chunk, uint32_t chunkSize) +{ + TEE_Result res = TEE_ERROR_GENERIC; + + if (operation == TEE_HANDLE_NULL || + operation->info.operationClass != TEE_OPERATION_DIGEST) + TEE_Panic(0); + + operation->operationState = TEE_OPERATION_STATE_ACTIVE; + + res = utee_hash_update(operation->state, chunk, chunkSize); + if (res != TEE_SUCCESS) + TEE_Panic(res); +} + +TEE_Result TEE_DigestDoFinal(TEE_OperationHandle operation, const void *chunk, + uint32_t chunkLen, void *hash, uint32_t *hashLen) +{ + TEE_Result res; + uint64_t hl; + + if ((operation == TEE_HANDLE_NULL) || + (!chunk && chunkLen) || + !hash || + !hashLen || + (operation->info.operationClass != TEE_OPERATION_DIGEST)) { + res = TEE_ERROR_BAD_PARAMETERS; + goto out; + } + + hl = *hashLen; + res = utee_hash_final(operation->state, chunk, chunkLen, hash, &hl); + *hashLen = hl; + if (res != TEE_SUCCESS) + goto out; + + /* Reset operation state */ + init_hash_operation(operation, NULL, 0); + + operation->operationState = TEE_OPERATION_STATE_INITIAL; + +out: + if (res != TEE_SUCCESS && + res != TEE_ERROR_SHORT_BUFFER) + TEE_Panic(res); + + return res; +} + +/* Cryptographic Operations API - Symmetric Cipher Functions */ + +void TEE_CipherInit(TEE_OperationHandle operation, const void *IV, + uint32_t IVLen) +{ + TEE_Result res; + + if (operation == TEE_HANDLE_NULL) + TEE_Panic(0); + + if (operation->info.operationClass != TEE_OPERATION_CIPHER) + TEE_Panic(0); + + if (!(operation->info.handleState & TEE_HANDLE_FLAG_KEY_SET) || + !(operation->key1)) + TEE_Panic(0); + + if (operation->operationState != TEE_OPERATION_STATE_INITIAL) + TEE_ResetOperation(operation); + + operation->operationState = TEE_OPERATION_STATE_ACTIVE; + + res = utee_cipher_init(operation->state, IV, IVLen); + if (res != TEE_SUCCESS) + TEE_Panic(res); + + operation->buffer_offs = 0; + operation->info.handleState |= TEE_HANDLE_FLAG_INITIALIZED; +} + +static TEE_Result tee_buffer_update( + TEE_OperationHandle op, + TEE_Result(*update_func)(unsigned long state, const void *src, + size_t slen, void *dst, uint64_t *dlen), + const void *src_data, size_t src_len, + void *dest_data, uint64_t *dest_len) +{ + TEE_Result res; + const uint8_t *src = src_data; + size_t slen = src_len; + uint8_t *dst = dest_data; + size_t dlen = *dest_len; + size_t acc_dlen = 0; + uint64_t tmp_dlen; + size_t l; + size_t buffer_size; + size_t buffer_left; + + if (!src) { + if (slen) + TEE_Panic(0); + goto out; + } + + if (op->buffer_two_blocks) { + buffer_size = op->block_size * 2; + buffer_left = 1; + } else { + buffer_size = op->block_size; + buffer_left = 0; + } + + if (op->buffer_offs > 0) { + /* Fill up complete block */ + if (op->buffer_offs < op->block_size) + l = MIN(slen, op->block_size - op->buffer_offs); + else + l = MIN(slen, buffer_size - op->buffer_offs); + memcpy(op->buffer + op->buffer_offs, src, l); + op->buffer_offs += l; + src += l; + slen -= l; + if ((op->buffer_offs % op->block_size) != 0) + goto out; /* Nothing left to do */ + } + + /* If we can feed from buffer */ + if ((op->buffer_offs > 0) && + ((op->buffer_offs + slen) >= (buffer_size + buffer_left))) { + l = ROUNDUP(op->buffer_offs + slen - buffer_size, + op->block_size); + l = MIN(op->buffer_offs, l); + tmp_dlen = dlen; + res = update_func(op->state, op->buffer, l, dst, &tmp_dlen); + if (res != TEE_SUCCESS) + TEE_Panic(res); + dst += tmp_dlen; + dlen -= tmp_dlen; + acc_dlen += tmp_dlen; + op->buffer_offs -= l; + if (op->buffer_offs > 0) { + /* + * Slen is small enough to be contained in rest buffer. + */ + memcpy(op->buffer, op->buffer + l, buffer_size - l); + memcpy(op->buffer + op->buffer_offs, src, slen); + op->buffer_offs += slen; + goto out; /* Nothing left to do */ + } + } + + if (slen >= (buffer_size + buffer_left)) { + /* Buffer is empty, feed as much as possible from src */ + if (op->info.algorithm == TEE_ALG_AES_CTS) + l = ROUNDUP(slen - buffer_size, op->block_size); + else + l = ROUNDUP(slen - buffer_size + 1, op->block_size); + + tmp_dlen = dlen; + res = update_func(op->state, src, l, dst, &tmp_dlen); + if (res != TEE_SUCCESS) + TEE_Panic(res); + src += l; + slen -= l; + dst += tmp_dlen; + dlen -= tmp_dlen; + acc_dlen += tmp_dlen; + } + + /* Slen is small enough to be contained in buffer. */ + memcpy(op->buffer + op->buffer_offs, src, slen); + op->buffer_offs += slen; + +out: + *dest_len = acc_dlen; + return TEE_SUCCESS; +} + +TEE_Result TEE_CipherUpdate(TEE_OperationHandle operation, const void *srcData, + uint32_t srcLen, void *destData, uint32_t *destLen) +{ + TEE_Result res; + size_t req_dlen; + uint64_t dl; + + if (operation == TEE_HANDLE_NULL || + (srcData == NULL && srcLen != 0) || + destLen == NULL || + (destData == NULL && *destLen != 0)) { + res = TEE_ERROR_BAD_PARAMETERS; + goto out; + } + + if (operation->info.operationClass != TEE_OPERATION_CIPHER) { + res = TEE_ERROR_BAD_PARAMETERS; + goto out; + } + + if ((operation->info.handleState & TEE_HANDLE_FLAG_INITIALIZED) == 0) { + res = TEE_ERROR_BAD_PARAMETERS; + goto out; + } + + if (operation->operationState != TEE_OPERATION_STATE_ACTIVE) { + res = TEE_ERROR_BAD_PARAMETERS; + goto out; + } + + if (!srcData && !srcLen) { + *destLen = 0; + res = TEE_SUCCESS; + goto out; + } + + /* Calculate required dlen */ + req_dlen = ((operation->buffer_offs + srcLen) / operation->block_size) * + operation->block_size; + if (operation->buffer_two_blocks) { + if (req_dlen > operation->block_size * 2) + req_dlen -= operation->block_size * 2; + else + req_dlen = 0; + } + /* + * Check that required destLen is big enough before starting to feed + * data to the algorithm. Errors during feeding of data are fatal as we + * can't restore sync with this API. + */ + if (*destLen < req_dlen) { + *destLen = req_dlen; + res = TEE_ERROR_SHORT_BUFFER; + goto out; + } + + dl = *destLen; + res = tee_buffer_update(operation, utee_cipher_update, srcData, srcLen, + destData, &dl); + *destLen = dl; + +out: + if (res != TEE_SUCCESS && + res != TEE_ERROR_SHORT_BUFFER) + TEE_Panic(res); + + return res; +} + +TEE_Result TEE_CipherDoFinal(TEE_OperationHandle operation, + const void *srcData, uint32_t srcLen, + void *destData, uint32_t *destLen) +{ + TEE_Result res; + uint8_t *dst = destData; + size_t acc_dlen = 0; + uint64_t tmp_dlen; + size_t req_dlen; + + if (operation == TEE_HANDLE_NULL || + (srcData == NULL && srcLen != 0) || + destLen == NULL || + (destData == NULL && *destLen != 0)) { + res = TEE_ERROR_BAD_PARAMETERS; + goto out; + } + + if (operation->info.operationClass != TEE_OPERATION_CIPHER) { + res = TEE_ERROR_BAD_PARAMETERS; + goto out; + } + + if ((operation->info.handleState & TEE_HANDLE_FLAG_INITIALIZED) == 0) { + res = TEE_ERROR_BAD_PARAMETERS; + goto out; + } + + if (operation->operationState != TEE_OPERATION_STATE_ACTIVE) { + res = TEE_ERROR_BAD_PARAMETERS; + goto out; + } + + /* + * Check that the final block doesn't require padding for those + * algorithms that requires client to supply padding. + */ + if (operation->info.algorithm == TEE_ALG_AES_ECB_NOPAD || + operation->info.algorithm == TEE_ALG_AES_CBC_NOPAD || + operation->info.algorithm == TEE_ALG_DES_ECB_NOPAD || + operation->info.algorithm == TEE_ALG_DES_CBC_NOPAD || + operation->info.algorithm == TEE_ALG_DES3_ECB_NOPAD || + operation->info.algorithm == TEE_ALG_DES3_CBC_NOPAD) { + if (((operation->buffer_offs + srcLen) % operation->block_size) + != 0) { + res = TEE_ERROR_BAD_PARAMETERS; + goto out; + } + } + + /* + * Check that required destLen is big enough before starting to feed + * data to the algorithm. Errors during feeding of data are fatal as we + * can't restore sync with this API. + */ + req_dlen = operation->buffer_offs + srcLen; + if (*destLen < req_dlen) { + *destLen = req_dlen; + res = TEE_ERROR_SHORT_BUFFER; + goto out; + } + + tmp_dlen = *destLen - acc_dlen; + res = tee_buffer_update(operation, utee_cipher_update, srcData, srcLen, + dst, &tmp_dlen); + if (res != TEE_SUCCESS) + goto out; + + dst += tmp_dlen; + acc_dlen += tmp_dlen; + + tmp_dlen = *destLen - acc_dlen; + res = utee_cipher_final(operation->state, operation->buffer, + operation->buffer_offs, dst, &tmp_dlen); + if (res != TEE_SUCCESS) + goto out; + + acc_dlen += tmp_dlen; + *destLen = acc_dlen; + + operation->info.handleState &= ~TEE_HANDLE_FLAG_INITIALIZED; + + operation->operationState = TEE_OPERATION_STATE_INITIAL; + +out: + if (res != TEE_SUCCESS && + res != TEE_ERROR_SHORT_BUFFER) + TEE_Panic(res); + + return res; +} + +/* Cryptographic Operations API - MAC Functions */ + +void TEE_MACInit(TEE_OperationHandle operation, const void *IV, uint32_t IVLen) +{ + if (operation == TEE_HANDLE_NULL) + TEE_Panic(0); + + if (operation->info.operationClass != TEE_OPERATION_MAC) + TEE_Panic(0); + + if (!(operation->info.handleState & TEE_HANDLE_FLAG_KEY_SET) || + !(operation->key1)) + TEE_Panic(0); + + if (operation->operationState != TEE_OPERATION_STATE_INITIAL) + TEE_ResetOperation(operation); + + operation->operationState = TEE_OPERATION_STATE_ACTIVE; + + init_hash_operation(operation, IV, IVLen); +} + +void TEE_MACUpdate(TEE_OperationHandle operation, const void *chunk, + uint32_t chunkSize) +{ + TEE_Result res; + + if (operation == TEE_HANDLE_NULL || (chunk == NULL && chunkSize != 0)) + TEE_Panic(0); + + if (operation->info.operationClass != TEE_OPERATION_MAC) + TEE_Panic(0); + + if ((operation->info.handleState & TEE_HANDLE_FLAG_INITIALIZED) == 0) + TEE_Panic(0); + + if (operation->operationState != TEE_OPERATION_STATE_ACTIVE) + TEE_Panic(0); + + res = utee_hash_update(operation->state, chunk, chunkSize); + if (res != TEE_SUCCESS) + TEE_Panic(res); +} + +TEE_Result TEE_MACComputeFinal(TEE_OperationHandle operation, + const void *message, uint32_t messageLen, + void *mac, uint32_t *macLen) +{ + TEE_Result res; + uint64_t ml; + + if (operation == TEE_HANDLE_NULL || + (message == NULL && messageLen != 0) || + mac == NULL || + macLen == NULL) { + res = TEE_ERROR_BAD_PARAMETERS; + goto out; + } + + if (operation->info.operationClass != TEE_OPERATION_MAC) { + res = TEE_ERROR_BAD_PARAMETERS; + goto out; + } + + if ((operation->info.handleState & TEE_HANDLE_FLAG_INITIALIZED) == 0) { + res = TEE_ERROR_BAD_PARAMETERS; + goto out; + } + + if (operation->operationState != TEE_OPERATION_STATE_ACTIVE) { + res = TEE_ERROR_BAD_PARAMETERS; + goto out; + } + + ml = *macLen; + res = utee_hash_final(operation->state, message, messageLen, mac, &ml); + *macLen = ml; + if (res != TEE_SUCCESS) + goto out; + + operation->info.handleState &= ~TEE_HANDLE_FLAG_INITIALIZED; + + operation->operationState = TEE_OPERATION_STATE_INITIAL; + +out: + if (res != TEE_SUCCESS && + res != TEE_ERROR_SHORT_BUFFER) + TEE_Panic(res); + + return res; +} + +TEE_Result TEE_MACCompareFinal(TEE_OperationHandle operation, + const void *message, uint32_t messageLen, + const void *mac, uint32_t macLen) +{ + TEE_Result res; + uint8_t computed_mac[TEE_MAX_HASH_SIZE]; + uint32_t computed_mac_size = TEE_MAX_HASH_SIZE; + + if (operation->info.operationClass != TEE_OPERATION_MAC) { + res = TEE_ERROR_BAD_PARAMETERS; + goto out; + } + + if ((operation->info.handleState & TEE_HANDLE_FLAG_INITIALIZED) == 0) { + res = TEE_ERROR_BAD_PARAMETERS; + goto out; + } + + if (operation->operationState != TEE_OPERATION_STATE_ACTIVE) { + res = TEE_ERROR_BAD_PARAMETERS; + goto out; + } + + res = TEE_MACComputeFinal(operation, message, messageLen, computed_mac, + &computed_mac_size); + if (res != TEE_SUCCESS) + goto out; + + if (computed_mac_size != macLen) { + res = TEE_ERROR_MAC_INVALID; + goto out; + } + + if (buf_compare_ct(mac, computed_mac, computed_mac_size) != 0) { + res = TEE_ERROR_MAC_INVALID; + goto out; + } + + operation->operationState = TEE_OPERATION_STATE_INITIAL; + +out: + if (res != TEE_SUCCESS && + res != TEE_ERROR_MAC_INVALID) + TEE_Panic(res); + + return res; +} + +/* Cryptographic Operations API - Authenticated Encryption Functions */ + +TEE_Result TEE_AEInit(TEE_OperationHandle operation, const void *nonce, + uint32_t nonceLen, uint32_t tagLen, uint32_t AADLen, + uint32_t payloadLen) +{ + TEE_Result res; + + if (operation == TEE_HANDLE_NULL || nonce == NULL) { + res = TEE_ERROR_BAD_PARAMETERS; + goto out; + } + + if (operation->info.operationClass != TEE_OPERATION_AE) { + res = TEE_ERROR_BAD_PARAMETERS; + goto out; + } + + if (operation->operationState != TEE_OPERATION_STATE_INITIAL) { + res = TEE_ERROR_BAD_PARAMETERS; + goto out; + } + + /* + * AES-CCM tag len is specified by AES-CCM spec and handled in TEE Core + * in the implementation. But AES-GCM spec doesn't specify the tag len + * according to the same principle so we have to check here instead to + * be GP compliant. + */ + if (operation->info.algorithm == TEE_ALG_AES_GCM) { + /* + * From GP spec: For AES-GCM, can be 128, 120, 112, 104, or 96 + */ + if (tagLen < 96 || tagLen > 128 || (tagLen % 8 != 0)) { + res = TEE_ERROR_NOT_SUPPORTED; + goto out; + } + } + + res = utee_authenc_init(operation->state, nonce, nonceLen, + tagLen / 8, AADLen, payloadLen); + if (res != TEE_SUCCESS) + goto out; + + operation->ae_tag_len = tagLen / 8; + operation->info.handleState |= TEE_HANDLE_FLAG_INITIALIZED; + +out: + if (res != TEE_SUCCESS && + res != TEE_ERROR_NOT_SUPPORTED) + TEE_Panic(res); + + return res; +} + +void TEE_AEUpdateAAD(TEE_OperationHandle operation, const void *AADdata, + uint32_t AADdataLen) +{ + TEE_Result res; + + if (operation == TEE_HANDLE_NULL || + (AADdata == NULL && AADdataLen != 0)) + TEE_Panic(0); + + if (operation->info.operationClass != TEE_OPERATION_AE) + TEE_Panic(0); + + if ((operation->info.handleState & TEE_HANDLE_FLAG_INITIALIZED) == 0) + TEE_Panic(0); + + res = utee_authenc_update_aad(operation->state, AADdata, AADdataLen); + + operation->operationState = TEE_OPERATION_STATE_ACTIVE; + + if (res != TEE_SUCCESS) + TEE_Panic(res); +} + +TEE_Result TEE_AEUpdate(TEE_OperationHandle operation, const void *srcData, + uint32_t srcLen, void *destData, uint32_t *destLen) +{ + TEE_Result res; + size_t req_dlen; + uint64_t dl; + + if (operation == TEE_HANDLE_NULL || + (srcData == NULL && srcLen != 0) || + destLen == NULL || + (destData == NULL && *destLen != 0)) { + res = TEE_ERROR_BAD_PARAMETERS; + goto out; + } + + if (operation->info.operationClass != TEE_OPERATION_AE) { + res = TEE_ERROR_BAD_PARAMETERS; + goto out; + } + + if ((operation->info.handleState & TEE_HANDLE_FLAG_INITIALIZED) == 0) { + res = TEE_ERROR_BAD_PARAMETERS; + goto out; + } + + if (!srcData && !srcLen) { + *destLen = 0; + res = TEE_SUCCESS; + goto out; + } + + /* + * Check that required destLen is big enough before starting to feed + * data to the algorithm. Errors during feeding of data are fatal as we + * can't restore sync with this API. + */ + req_dlen = ROUNDDOWN(operation->buffer_offs + srcLen, + operation->block_size); + if (*destLen < req_dlen) { + *destLen = req_dlen; + res = TEE_ERROR_SHORT_BUFFER; + goto out; + } + + dl = *destLen; + res = tee_buffer_update(operation, utee_authenc_update_payload, srcData, + srcLen, destData, &dl); + *destLen = dl; + + operation->operationState = TEE_OPERATION_STATE_ACTIVE; + +out: + if (res != TEE_SUCCESS && + res != TEE_ERROR_SHORT_BUFFER) + TEE_Panic(res); + + return res; +} + +TEE_Result TEE_AEEncryptFinal(TEE_OperationHandle operation, + const void *srcData, uint32_t srcLen, + void *destData, uint32_t *destLen, void *tag, + uint32_t *tagLen) +{ + TEE_Result res; + uint8_t *dst = destData; + size_t acc_dlen = 0; + uint64_t tmp_dlen; + size_t req_dlen; + uint64_t tl; + + if (operation == TEE_HANDLE_NULL || + (srcData == NULL && srcLen != 0) || + destLen == NULL || + (destData == NULL && *destLen != 0) || + tag == NULL || tagLen == NULL) { + res = TEE_ERROR_BAD_PARAMETERS; + goto out; + } + + if (operation->info.operationClass != TEE_OPERATION_AE) { + res = TEE_ERROR_BAD_PARAMETERS; + goto out; + } + + if ((operation->info.handleState & TEE_HANDLE_FLAG_INITIALIZED) == 0) { + res = TEE_ERROR_BAD_PARAMETERS; + goto out; + } + + /* + * Check that required destLen is big enough before starting to feed + * data to the algorithm. Errors during feeding of data are fatal as we + * can't restore sync with this API. + */ + req_dlen = operation->buffer_offs + srcLen; + if (*destLen < req_dlen) { + *destLen = req_dlen; + res = TEE_ERROR_SHORT_BUFFER; + goto out; + } + + /* + * Need to check this before update_payload since sync would be lost if + * we return short buffer after that. + */ + if (*tagLen < operation->ae_tag_len) { + *tagLen = operation->ae_tag_len; + res = TEE_ERROR_SHORT_BUFFER; + goto out; + } + + tmp_dlen = *destLen - acc_dlen; + res = tee_buffer_update(operation, utee_authenc_update_payload, srcData, + srcLen, dst, &tmp_dlen); + if (res != TEE_SUCCESS) + goto out; + + dst += tmp_dlen; + acc_dlen += tmp_dlen; + + tmp_dlen = *destLen - acc_dlen; + tl = *tagLen; + res = utee_authenc_enc_final(operation->state, operation->buffer, + operation->buffer_offs, dst, &tmp_dlen, + tag, &tl); + *tagLen = tl; + if (res != TEE_SUCCESS) + goto out; + + acc_dlen += tmp_dlen; + *destLen = acc_dlen; + + operation->info.handleState &= ~TEE_HANDLE_FLAG_INITIALIZED; + + operation->operationState = TEE_OPERATION_STATE_INITIAL; + +out: + if (res != TEE_SUCCESS && + res != TEE_ERROR_SHORT_BUFFER) + TEE_Panic(res); + + return res; +} + +TEE_Result TEE_AEDecryptFinal(TEE_OperationHandle operation, + const void *srcData, uint32_t srcLen, + void *destData, uint32_t *destLen, void *tag, + uint32_t tagLen) +{ + TEE_Result res; + uint8_t *dst = destData; + size_t acc_dlen = 0; + uint64_t tmp_dlen; + size_t req_dlen; + + if (operation == TEE_HANDLE_NULL || + (srcData == NULL && srcLen != 0) || + destLen == NULL || + (destData == NULL && *destLen != 0) || + (tag == NULL && tagLen != 0)) { + res = TEE_ERROR_BAD_PARAMETERS; + goto out; + } + + if (operation->info.operationClass != TEE_OPERATION_AE) { + res = TEE_ERROR_BAD_PARAMETERS; + goto out; + } + + if ((operation->info.handleState & TEE_HANDLE_FLAG_INITIALIZED) == 0) { + res = TEE_ERROR_BAD_PARAMETERS; + goto out; + } + + /* + * Check that required destLen is big enough before starting to feed + * data to the algorithm. Errors during feeding of data are fatal as we + * can't restore sync with this API. + */ + req_dlen = operation->buffer_offs + srcLen; + if (*destLen < req_dlen) { + *destLen = req_dlen; + res = TEE_ERROR_SHORT_BUFFER; + goto out; + } + + tmp_dlen = *destLen - acc_dlen; + res = tee_buffer_update(operation, utee_authenc_update_payload, srcData, + srcLen, dst, &tmp_dlen); + if (res != TEE_SUCCESS) + goto out; + + dst += tmp_dlen; + acc_dlen += tmp_dlen; + + tmp_dlen = *destLen - acc_dlen; + res = utee_authenc_dec_final(operation->state, operation->buffer, + operation->buffer_offs, dst, &tmp_dlen, + tag, tagLen); + if (res != TEE_SUCCESS) + goto out; + + /* Supplied tagLen should match what we initiated with */ + if (tagLen != operation->ae_tag_len) + res = TEE_ERROR_MAC_INVALID; + + acc_dlen += tmp_dlen; + *destLen = acc_dlen; + + operation->info.handleState &= ~TEE_HANDLE_FLAG_INITIALIZED; + + operation->operationState = TEE_OPERATION_STATE_INITIAL; + +out: + if (res != TEE_SUCCESS && + res != TEE_ERROR_SHORT_BUFFER && + res != TEE_ERROR_MAC_INVALID) + TEE_Panic(res); + + return res; +} + +/* Cryptographic Operations API - Asymmetric Functions */ + +TEE_Result TEE_AsymmetricEncrypt(TEE_OperationHandle operation, + const TEE_Attribute *params, + uint32_t paramCount, const void *srcData, + uint32_t srcLen, void *destData, + uint32_t *destLen) +{ + TEE_Result res; + struct utee_attribute ua[paramCount]; + uint64_t dl; + + if (operation == TEE_HANDLE_NULL || (srcData == NULL && srcLen != 0) || + destLen == NULL || (destData == NULL && *destLen != 0)) + TEE_Panic(0); + if (params == NULL && paramCount != 0) + TEE_Panic(0); + if (!operation->key1) + TEE_Panic(0); + if (operation->info.operationClass != TEE_OPERATION_ASYMMETRIC_CIPHER) + TEE_Panic(0); + if (operation->info.mode != TEE_MODE_ENCRYPT) + TEE_Panic(0); + + __utee_from_attr(ua, params, paramCount); + dl = *destLen; + res = utee_asymm_operate(operation->state, ua, paramCount, srcData, + srcLen, destData, &dl); + *destLen = dl; + + if (res != TEE_SUCCESS && + res != TEE_ERROR_SHORT_BUFFER && + res != TEE_ERROR_BAD_PARAMETERS) + TEE_Panic(res); + + return res; +} + +TEE_Result TEE_AsymmetricDecrypt(TEE_OperationHandle operation, + const TEE_Attribute *params, + uint32_t paramCount, const void *srcData, + uint32_t srcLen, void *destData, + uint32_t *destLen) +{ + TEE_Result res; + struct utee_attribute ua[paramCount]; + uint64_t dl; + + if (operation == TEE_HANDLE_NULL || (srcData == NULL && srcLen != 0) || + destLen == NULL || (destData == NULL && *destLen != 0)) + TEE_Panic(0); + if (params == NULL && paramCount != 0) + TEE_Panic(0); + if (!operation->key1) + TEE_Panic(0); + if (operation->info.operationClass != TEE_OPERATION_ASYMMETRIC_CIPHER) + TEE_Panic(0); + if (operation->info.mode != TEE_MODE_DECRYPT) + TEE_Panic(0); + + __utee_from_attr(ua, params, paramCount); + dl = *destLen; + res = utee_asymm_operate(operation->state, ua, paramCount, srcData, + srcLen, destData, &dl); + *destLen = dl; + + if (res != TEE_SUCCESS && + res != TEE_ERROR_SHORT_BUFFER && + res != TEE_ERROR_BAD_PARAMETERS) + TEE_Panic(res); + + return res; +} + +TEE_Result TEE_AsymmetricSignDigest(TEE_OperationHandle operation, + const TEE_Attribute *params, + uint32_t paramCount, const void *digest, + uint32_t digestLen, void *signature, + uint32_t *signatureLen) +{ + TEE_Result res; + struct utee_attribute ua[paramCount]; + uint64_t sl; + + if (operation == TEE_HANDLE_NULL || + (digest == NULL && digestLen != 0) || + signature == NULL || signatureLen == NULL) + TEE_Panic(0); + if (params == NULL && paramCount != 0) + TEE_Panic(0); + if (!operation->key1) + TEE_Panic(0); + if (operation->info.operationClass != + TEE_OPERATION_ASYMMETRIC_SIGNATURE) + TEE_Panic(0); + if (operation->info.mode != TEE_MODE_SIGN) + TEE_Panic(0); + + __utee_from_attr(ua, params, paramCount); + sl = *signatureLen; + res = utee_asymm_operate(operation->state, ua, paramCount, digest, + digestLen, signature, &sl); + *signatureLen = sl; + + if (res != TEE_SUCCESS && res != TEE_ERROR_SHORT_BUFFER) + TEE_Panic(res); + + return res; +} + +TEE_Result TEE_AsymmetricVerifyDigest(TEE_OperationHandle operation, + const TEE_Attribute *params, + uint32_t paramCount, const void *digest, + uint32_t digestLen, + const void *signature, + uint32_t signatureLen) +{ + TEE_Result res; + struct utee_attribute ua[paramCount]; + + if (operation == TEE_HANDLE_NULL || + (digest == NULL && digestLen != 0) || + (signature == NULL && signatureLen != 0)) + TEE_Panic(0); + if (params == NULL && paramCount != 0) + TEE_Panic(0); + if (!operation->key1) + TEE_Panic(0); + if (operation->info.operationClass != + TEE_OPERATION_ASYMMETRIC_SIGNATURE) + TEE_Panic(0); + if (operation->info.mode != TEE_MODE_VERIFY) + TEE_Panic(0); + + __utee_from_attr(ua, params, paramCount); + res = utee_asymm_verify(operation->state, ua, paramCount, digest, + digestLen, signature, signatureLen); + + if (res != TEE_SUCCESS && res != TEE_ERROR_SIGNATURE_INVALID) + TEE_Panic(res); + + return res; +} + +/* Cryptographic Operations API - Key Derivation Functions */ + +void TEE_DeriveKey(TEE_OperationHandle operation, + const TEE_Attribute *params, uint32_t paramCount, + TEE_ObjectHandle derivedKey) +{ + TEE_Result res; + TEE_ObjectInfo key_info; + struct utee_attribute ua[paramCount]; + + if (operation == TEE_HANDLE_NULL || derivedKey == 0) + TEE_Panic(0); + if (params == NULL && paramCount != 0) + TEE_Panic(0); + if (TEE_ALG_GET_CLASS(operation->info.algorithm) != + TEE_OPERATION_KEY_DERIVATION) + TEE_Panic(0); + + if (operation->info.operationClass != TEE_OPERATION_KEY_DERIVATION) + TEE_Panic(0); + if (!operation->key1) + TEE_Panic(0); + if (operation->info.mode != TEE_MODE_DERIVE) + TEE_Panic(0); + if ((operation->info.handleState & TEE_HANDLE_FLAG_KEY_SET) == 0) + TEE_Panic(0); + + res = utee_cryp_obj_get_info((unsigned long)derivedKey, &key_info); + if (res != TEE_SUCCESS) + TEE_Panic(res); + + if (key_info.objectType != TEE_TYPE_GENERIC_SECRET) + TEE_Panic(0); + if ((key_info.handleFlags & TEE_HANDLE_FLAG_INITIALIZED) != 0) + TEE_Panic(0); + + __utee_from_attr(ua, params, paramCount); + res = utee_cryp_derive_key(operation->state, ua, paramCount, + (unsigned long)derivedKey); + if (res != TEE_SUCCESS) + TEE_Panic(res); +} + +/* Cryptographic Operations API - Random Number Generation Functions */ + +void TEE_GenerateRandom(void *randomBuffer, uint32_t randomBufferLen) +{ + TEE_Result res; + + res = utee_cryp_random_number_generate(randomBuffer, randomBufferLen); + if (res != TEE_SUCCESS) + TEE_Panic(res); +} |