Permalink
Cannot retrieve contributors at this time
Name already in use
A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch?
mTower/tee/lib/libutee/tee_api_operations.c
Go to fileThis commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
1819 lines (1533 sloc)
45.8 KB
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // SPDX-License-Identifier: BSD-2-Clause | |
| /* | |
| * 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" | |
| #include "utee_types.h" | |
| TEE_Result utee_cipher_update(unsigned long state, const void *src, | |
| size_t src_len, void *dst, uint64_t *dst_len); | |
| 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_CCM: | |
| 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; | |
| /* FALLTHROUGH */ | |
| case TEE_ALG_AES_CTR: | |
| case TEE_ALG_AES_GCM: | |
| 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 */ | |
| if (operation->block_size > 1) { | |
| req_dlen = ((operation->buffer_offs + srcLen) / | |
| operation->block_size) * operation->block_size; | |
| } else { | |
| req_dlen = srcLen; | |
| } | |
| 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; | |
| if (operation->block_size > 1) { | |
| res = tee_buffer_update(operation, utee_cipher_update, srcData, | |
| srcLen, destData, &dl); | |
| } else { | |
| if (srcLen > 0) { | |
| res = utee_cipher_update(operation->state, srcData, | |
| srcLen, destData, &dl); | |
| } else { | |
| res = TEE_SUCCESS; | |
| dl = 0; | |
| } | |
| } | |
| *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. | |
| */ | |
| if (operation->block_size > 1) { | |
| req_dlen = operation->buffer_offs + srcLen; | |
| } else { | |
| req_dlen = srcLen; | |
| } | |
| if (*destLen < req_dlen) { | |
| *destLen = req_dlen; | |
| res = TEE_ERROR_SHORT_BUFFER; | |
| goto out; | |
| } | |
| tmp_dlen = *destLen - acc_dlen; | |
| if (operation->block_size > 1) { | |
| 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); | |
| } else { | |
| res = utee_cipher_final(operation->state, srcData, | |
| srcLen, 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 = TEE_SUCCESS; | |
| 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. | |
| */ | |
| if (operation->block_size > 1) { | |
| req_dlen = ROUNDDOWN(operation->buffer_offs + srcLen, | |
| operation->block_size); | |
| } else { | |
| req_dlen = srcLen; | |
| } | |
| if (*destLen < req_dlen) { | |
| *destLen = req_dlen; | |
| res = TEE_ERROR_SHORT_BUFFER; | |
| goto out; | |
| } | |
| dl = *destLen; | |
| // if (operation->block_size > 1) { | |
| // res = tee_buffer_update(operation, utee_authenc_update_payload, | |
| // srcData, srcLen, destData, &dl); | |
| // } else { | |
| // if (srcLen > 0) { | |
| // res = utee_authenc_update_payload(operation->state, | |
| // srcData, srcLen, | |
| // destData, &dl); | |
| // } else { | |
| // dl = 0; | |
| // res = TEE_SUCCESS; | |
| // } | |
| // } | |
| // if (res != TEE_SUCCESS) | |
| // goto out; | |
| *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 = TEE_SUCCESS; | |
| // 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; | |
| } | |
| // tl = *tagLen; | |
| tmp_dlen = *destLen - acc_dlen; | |
| // if (operation->block_size > 1) { | |
| // 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_enc_final(operation->state, | |
| // operation->buffer, | |
| // operation->buffer_offs, dst, | |
| // &tmp_dlen, tag, &tl); | |
| // } else { | |
| // res = utee_authenc_enc_final(operation->state, srcData, | |
| // srcLen, 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; | |
| // if (operation->block_size > 1) { | |
| // 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); | |
| // } else { | |
| // res = utee_authenc_dec_final(operation->state, srcData, | |
| // srcLen, 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); | |
| } |