From: Jan Wojtkowski Date: Mon, 5 Aug 2024 10:26:00 +0000 (+0200) Subject: Support ML-KEM (en/de)capsulation X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=287e79cb8ccdf8bd7d243d02f5f22243c85a687c;p=platform%2Fcore%2Fsecurity%2Ftrusted%2Fkey-manager-ta.git Support ML-KEM (en/de)capsulation Change-Id: I88e9782f56b8ae95b9286bfd218c09bab9cff3c1 --- diff --git a/ta/include/cmd_exec.h b/ta/include/cmd_exec.h index b0f9f08..a7defbc 100644 --- a/ta/include/cmd_exec.h +++ b/ta/include/cmd_exec.h @@ -78,4 +78,8 @@ TEE_Result KM_ExecCmdWrapConcatenatedData(TEE_Param param[4]); TEE_Result KM_ExecCmdUnwrapConcatenatedData(TEE_Param param[4]); +TEE_Result KM_ExecCmdEncapsulateKey(TEE_Param param[4]); + +TEE_Result KM_ExecCmdDecapsulateKey(TEE_Param param[4]); + #endif // __CMD_EXEC_H__ diff --git a/ta/include/km_ta_defines.h b/ta/include/km_ta_defines.h index af4cb92..856e07c 100644 --- a/ta/include/km_ta_defines.h +++ b/ta/include/km_ta_defines.h @@ -68,6 +68,8 @@ typedef enum { CMD_WRAP_CONCATENATED_DATA, ///< Wraps concatenated key|data with wrapping key and export CMD_UNWRAP_CONCATENATED_DATA, ///< Unwraps concatenated key|data with wrapping key, ///< import key and export data + CMD_ENCAPSULATE_KEY, ///< Generates shared secret, encapsulates it and produces a ciphertext + CMD_DECAPSULATE_KEY, ///< Decapsulates the shared secret from the ciphertext and key } tz_command; /** \enum tz_algo_type @@ -90,6 +92,7 @@ typedef enum { ALGO_RSA_GEN, ALGO_DSA_GEN, ALGO_ECDSA_GEN, + ALGO_KEM_GEN, ALGO_RSA_SV, ALGO_DSA_SV, ALGO_ECDSA_SV, diff --git a/ta/src/cmd_exec.c b/ta/src/cmd_exec.c index f4e7475..9db25f8 100644 --- a/ta/src/cmd_exec.c +++ b/ta/src/cmd_exec.c @@ -59,6 +59,7 @@ static uint32_t KM_AlgoType2TeeType(int algo) case ALGO_AES_GEN: return TEE_TYPE_AES; case ALGO_RSA_GEN: return TEE_TYPE_RSA_KEYPAIR; case ALGO_DSA_GEN: return TEE_TYPE_DSA_KEYPAIR; + case ALGO_KEM_GEN: return TEE_TYPE_GENERIC_SECRET; default: return 0; } } @@ -3516,3 +3517,292 @@ clean: TEE_Free(user_data.data); return ret; } + +TEE_Result KM_ExecCmdEncapsulateKey(TEE_Param param[4]) +{ + TEE_Result ret = TEE_SUCCESS; + + void *in_buffer_ptr = param[1].memref.buffer; + void *out_buffer_ptr = param[2].memref.buffer; + uint32_t buffer_size_guard = param[1].memref.size; + uint32_t out_buffer_size_guard = param[2].memref.size; + + uint32_t has_pub_pwd = 0; + KM_BinaryData pub_key_id = {0, NULL}; + KM_BinaryData pub_key = {0, NULL}; + KM_BinaryData shared_secret_id = {0, NULL}; + KM_BinaryData encrypted_shared_secret = {0, NULL}; + KM_BinaryData shared_secret_tag = {0, NULL}; + KM_PwdData pub_pwd, shared_secret_pwd; + uint32_t has_shared_secret_pwd = 0; + uint32_t pub_key_len = 0; + uint8_t* shared_secret = NULL; + uint8_t* ciphertext = NULL; + OQS_KEM* kem = NULL; + TEE_ObjectHandle key = TEE_HANDLE_NULL; + + tz_kem kem_type = param[0].value.a; + + ret = KM_DeserializeBinaryData(&in_buffer_ptr, &buffer_size_guard, &pub_key_id); + if (ret != TEE_SUCCESS) { + LOG("Error in deserialization of hash(pub_key_id), ret = %x", ret); + goto clean; + } + + ret = KM_DeserializeFlagAndPw(&in_buffer_ptr, &buffer_size_guard, &has_pub_pwd, &pub_pwd); + if (ret != TEE_SUCCESS) { + LOG("Error in deserialization of public flag and password, ret = %x", ret); + goto clean; + } + + ret = KM_DeserializeFlagAndPw(&in_buffer_ptr, &buffer_size_guard, &has_shared_secret_pwd, &shared_secret_pwd); + if (ret != TEE_SUCCESS) { + LOG("Error in deserialization of shared secret flag and password, ret = %x", ret); + goto clean; + } + + ret = KM_DeserializeBinaryData(&in_buffer_ptr, &buffer_size_guard, &shared_secret_id); + if (ret != TEE_SUCCESS) { + LOG("Error in deserialization of hash(shared_secret_id), ret = %x", ret); + goto clean; + } + + kem = createNewKem(kem_type); + if (kem == NULL) { + LOG("Invalid OQS algorithm name was provided, or the \ + requested algorithm was disabled at compile-time."); + ret = TEE_ERROR_GENERIC; + goto clean; + } + + ret = KM_GetDataSize(&pub_key_len, &pub_key_id, + has_pub_pwd, &pub_pwd, TYPE_GENERIC_SECRET); + if (ret != TEE_SUCCESS) { + LOG("Failed to read object data size from storage"); + goto clean; + } + + if (pub_key_len != kem->length_public_key) { + LOG("KEM type differs from public key KEM type"); + ret = TEE_ERROR_BAD_PARAMETERS; + goto clean; + } + + pub_key.data = TEE_Malloc(pub_key_len, 0); + if (pub_key.data == NULL) { + LOG("Failed to assign memory. requested size=%d", pub_key_len); + ret = TEE_ERROR_OUT_OF_MEMORY; + goto clean; + } + pub_key.data_size = pub_key_len; + + ret = KM_GetData(pub_key.data, pub_key.data_size, &pub_key_id, + has_pub_pwd, &pub_pwd, TYPE_GENERIC_SECRET); + if (ret != TEE_SUCCESS) { + LOG("Failed to read object data from storage"); + goto clean; + } + + shared_secret = TEE_Malloc(kem->length_shared_secret*sizeof(uint8_t), 0); + ciphertext = TEE_Malloc(kem->length_ciphertext*sizeof(uint8_t), 0); + if (shared_secret == NULL || ciphertext == NULL) { + LOG("Failed to allocate buffers"); + ret = TEE_ERROR_OUT_OF_MEMORY; + goto clean; + } + + OQS_STATUS rc = OQS_KEM_encaps(kem, ciphertext, shared_secret, pub_key.data); + if (rc != OQS_SUCCESS) { + LOG("Error in KEM key encapsulation: %x", rc); + ret = TEE_ERROR_GENERIC; + goto clean; + } + + KM_BinaryData out_ciphertext = {kem->length_ciphertext, ciphertext}; + KM_BinaryData out_shared_secret = {kem->length_shared_secret, shared_secret}; + + ret = KM_Serialize(&out_buffer_ptr, &out_buffer_size_guard, out_ciphertext.data, out_ciphertext.data_size); + if (ret != TEE_SUCCESS) { + LOG("Error in serialization"); + goto clean; + } + + if (has_shared_secret_pwd) { + ret = KM_EncryptBinary(&shared_secret_pwd, &out_shared_secret, &encrypted_shared_secret, &shared_secret_tag); + if (ret != TEE_SUCCESS) { + LOG("Failed to encrypt new key"); + goto clean; + } + ret = KM_Serialize(&out_buffer_ptr, &out_buffer_size_guard, shared_secret_tag.data, shared_secret_tag.data_size); + if (ret != TEE_SUCCESS) { + LOG("Error in serialization"); + goto clean; + } + ret = KM_CreateKey(TEE_TYPE_AES, encrypted_shared_secret.data_size * 8, encrypted_shared_secret.data, &key); + } else { + ret = KM_CreateKey(TEE_TYPE_AES, out_shared_secret.data_size * 8, out_shared_secret.data, &key); + } + if (ret != TEE_SUCCESS) { + LOG("Failed to create key"); + goto clean; + } + + ret = KM_SaveKey(NULL, 0, key, shared_secret_id.data, shared_secret_id.data_size); + if (TEE_SUCCESS != ret) { + LOG("Failed to save generated key"); + goto clean; + } + +clean: + TEE_CloseObject(key); + TEE_Free(pub_key.data); + TEE_Free(shared_secret_tag.data); + TEE_Free(encrypted_shared_secret.data); + TEE_Free(shared_secret); + TEE_Free(ciphertext); + OQS_KEM_free(kem); + return ret; +} + +TEE_Result KM_ExecCmdDecapsulateKey(TEE_Param param[4]) +{ + TEE_Result ret = TEE_SUCCESS; + + void *in_buffer_ptr = param[1].memref.buffer; + void *out_buffer_ptr = param[2].memref.buffer; + uint32_t in_buffer_size_guard = param[1].memref.size; + uint32_t out_buffer_size_guard = param[2].memref.size; + + uint32_t has_priv_pwd = 0, has_shared_secret_pwd = 0; + KM_BinaryData priv_key_id = {0, NULL}; + KM_BinaryData priv_key = {0, NULL}; + KM_BinaryData shared_secret_id = {0, NULL}; + KM_BinaryData ciphertext = {0, NULL}; + KM_BinaryData encrypted_shared_secret = {0, NULL}; + KM_BinaryData shared_secret_tag = {0, NULL}; + KM_PwdData priv_pwd, shared_secret_pwd; + uint32_t priv_key_len = 0; + uint8_t* shared_secret = NULL; + OQS_KEM* kem = NULL; + TEE_ObjectHandle key = TEE_HANDLE_NULL; + + tz_kem kem_type = param[0].value.a; + + ret = KM_DeserializeBinaryData(&in_buffer_ptr, &in_buffer_size_guard, &priv_key_id); + if (ret != TEE_SUCCESS) { + LOG("Error in deserialization of hash(priv_key_id), ret = %x", ret); + goto clean; + } + + ret = KM_DeserializeFlagAndPw(&in_buffer_ptr, &in_buffer_size_guard, &has_priv_pwd, &priv_pwd); + if (ret != TEE_SUCCESS) { + LOG("Error in deserialization of private flag and password, ret = %x", ret); + goto clean; + } + + ret = KM_DeserializeFlagAndPw(&in_buffer_ptr, &in_buffer_size_guard, &has_shared_secret_pwd, &shared_secret_pwd); + if (ret != TEE_SUCCESS) { + LOG("Error in deserialization of shared secret flag and password, ret = %x", ret); + goto clean; + } + + ret = KM_DeserializeBinaryData(&in_buffer_ptr, &in_buffer_size_guard, &shared_secret_id); + if (ret != TEE_SUCCESS) { + LOG("Error in deserialization of hash(shared_secret_id), ret = %x", ret); + goto clean; + } + + ret = KM_DeserializeBinaryData(&in_buffer_ptr, &in_buffer_size_guard, &ciphertext); + if (ret != TEE_SUCCESS) { + LOG("Error in deserialization of hash(ciphertext), ret = %x", ret); + goto clean; + } + + kem = createNewKem(kem_type); + if (kem == NULL) { + LOG("Invalid OQS algorithm name was provided, or the \ + requested algorithm was disabled at compile-time."); + ret = TEE_ERROR_GENERIC; + goto clean; + } + + ret = KM_GetDataSize(&priv_key_len, &priv_key_id, + has_priv_pwd, &priv_pwd, TYPE_GENERIC_SECRET); + if (ret != TEE_SUCCESS) { + LOG("Failed to read object data size from storage"); + goto clean; + } + + if (priv_key_len != kem->length_secret_key) { + LOG("KEM type differs from private key KEM type"); + ret = TEE_ERROR_BAD_PARAMETERS; + goto clean; + } + + priv_key.data = TEE_Malloc(priv_key_len, 0); + if (priv_key.data == NULL) { + LOG("Failed to assign memory. requested size=%d", priv_key_len); + ret = TEE_ERROR_OUT_OF_MEMORY; + goto clean; + } + priv_key.data_size = priv_key_len; + + ret = KM_GetData(priv_key.data, priv_key.data_size, &priv_key_id, + has_priv_pwd, &priv_pwd, TYPE_GENERIC_SECRET); + if (ret != TEE_SUCCESS) { + LOG("Failed to read object data from storage"); + goto clean; + } + + shared_secret = TEE_Malloc(kem->length_shared_secret*sizeof(uint8_t), 0); + if (shared_secret == NULL) { + LOG("Failed to allocate buffer"); + ret = TEE_ERROR_OUT_OF_MEMORY; + goto clean; + } + + OQS_STATUS rc = OQS_KEM_decaps(kem, shared_secret, ciphertext.data, priv_key.data); + if (rc != OQS_SUCCESS) { + LOG("Error in KEM key decapsulation: %x", rc); + ret = TEE_ERROR_GENERIC; + goto clean; + } + + KM_BinaryData out_shared_secret = {kem->length_shared_secret, shared_secret}; + + if (has_shared_secret_pwd) { + ret = KM_EncryptBinary(&shared_secret_pwd, &out_shared_secret, &encrypted_shared_secret, &shared_secret_tag); + if (ret != TEE_SUCCESS) { + LOG("Failed to encrypt new key"); + goto clean; + } + ret = KM_Serialize(&out_buffer_ptr, &out_buffer_size_guard, shared_secret_tag.data, shared_secret_tag.data_size); + if (ret != TEE_SUCCESS) { + LOG("Error in serialization"); + goto clean; + } + ret = KM_CreateKey(TEE_TYPE_AES, encrypted_shared_secret.data_size * 8, encrypted_shared_secret.data, &key); + } else { + ret = KM_CreateKey(TEE_TYPE_AES, out_shared_secret.data_size * 8, out_shared_secret.data, &key); + } + if (ret != TEE_SUCCESS) { + LOG("Failed to create key"); + goto clean; + } + + ret = KM_SaveKey(NULL, 0, key, shared_secret_id.data, shared_secret_id.data_size); + if (TEE_SUCCESS != ret) { + LOG("Failed to save generated key"); + goto clean; + } + +clean: + TEE_CloseObject(key); + TEE_Free(priv_key.data); + TEE_Free(shared_secret_tag.data); + TEE_Free(encrypted_shared_secret.data); + TEE_Free(shared_secret); + OQS_KEM_free(kem); + return ret; +} + diff --git a/ta/src/km_ta.c b/ta/src/km_ta.c index d45bc9e..7331c50 100644 --- a/ta/src/km_ta.c +++ b/ta/src/km_ta.c @@ -233,6 +233,16 @@ TEE_Result TA_InvokeCommandEntryPoint( ret = KM_ExecCmdUnwrapConcatenatedData(param); break; } + case CMD_ENCAPSULATE_KEY: { + LOGD("!!! Generates shared secret, encapsulates it and produces a ciphertext !!!"); + ret = KM_ExecCmdEncapsulateKey(param); + break; + } + case CMD_DECAPSULATE_KEY: { + LOGD("!!! Decapsulates the shared secret from the ciphertext and key !!!"); + ret = KM_ExecCmdDecapsulateKey(param); + break; + } default: { LOG("Unknown commandID=%d.", commandID); ret = TEE_ERROR_BAD_PARAMETERS;