Support ML-KEM (en/de)capsulation 23/315623/14
authorJan Wojtkowski <j.wojtkowski@samsung.com>
Mon, 5 Aug 2024 10:26:00 +0000 (12:26 +0200)
committerJan Wojtkowski <j.wojtkowski@samsung.com>
Tue, 3 Sep 2024 06:51:49 +0000 (08:51 +0200)
Change-Id: I88e9782f56b8ae95b9286bfd218c09bab9cff3c1

ta/include/cmd_exec.h
ta/include/km_ta_defines.h
ta/src/cmd_exec.c
ta/src/km_ta.c

index b0f9f08dc9c23231e275e1a327db6a4504c9ae07..a7defbcc9c3176be864dc8c661fdd624d9505b42 100644 (file)
@@ -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__
index af4cb920c0205b518bc2ab76d0a4830717eba044..856e07ccadb3284f430aac2132ed3895d8314c76 100644 (file)
@@ -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,
index f4e74753af856bc44fc5f0af10d98fdf5e4ef99f..9db25f842044b597049135800d2810566078fd6d 100644 (file)
@@ -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;
+}
+
index d45bc9e826505e5f2aa84708362c25b6160cb2f2..7331c50e061bd0bea4ff12066d844e9e5b8804b8 100644 (file)
@@ -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;