Support ML-KEM keypair creation 43/315143/15
authorJan Wojtkowski <j.wojtkowski@samsung.com>
Thu, 25 Jul 2024 11:07:11 +0000 (13:07 +0200)
committerJan Wojtkowski <j.wojtkowski@samsung.com>
Tue, 3 Sep 2024 06:28:00 +0000 (08:28 +0200)
Change-Id: I1be361f9855e7a901298b59955ce566e86df3c35

packaging/key-manager-ta.spec
ta/CMakeLists.txt
ta/include/cmd_exec.h
ta/include/km_ta_defines.h
ta/src/cmd_exec.c
ta/src/internal.c
ta/src/km_ta.c

index 0a97340a5b588012b312adb4248f8ed3c3b27891..44ab06dbf7f405c821ae4151e4005358a0dd572f 100644 (file)
@@ -38,6 +38,7 @@ Provides:   %{name}
 
 BuildRequires: cmake
 BuildRequires: unified-ta-devkit
+BuildRequires: liboqs
 
 %description
 Key Manager Trusted Application working in the ARMĀ® TrustZoneĀ® environment.
index 61dba2f8a67128c39126b8f710434f8fe361bc4a..51ad98822487fef52d0f9aa4c9be630bbeb67689 100644 (file)
@@ -66,6 +66,7 @@ ENDIF(SECRET_KEY_ENABLE)
 TARGET_LINK_LIBRARIES(${TARGET_KEY_MANAGER_TA}
     ${KEY_MANAGER_TA_DEPS_LIBRARIES}
     ${KEY_MANAGER_TA_DEPS_STATIC_LIBRARIES}
+    liboqs.a
     )
 
 GENERATE_TA_IMAGE(SIGNED_TA ${TARGET_KEY_MANAGER_TA} ${KEY_MANAGER_TA_PATH}/backends ${TA_NAME})
index 68a12d5c0a037038c60ccc4f03b1f0b9cdaaa876..b0f9f08dc9c23231e275e1a327db6a4504c9ae07 100644 (file)
@@ -34,6 +34,8 @@ TEE_Result KM_ExecCmdGenerateDSAKey(TEE_Param param[4]);
 
 TEE_Result KM_ExecCmdGenerateECKey(TEE_Param param[4]);
 
+TEE_Result KM_ExecCmdGenerateKEMKey(TEE_Param param[4]);
+
 TEE_Result KM_ExecCmdSymmetric(uint32_t commandID, TEE_Param param[4]);
 
 TEE_Result KM_ExecCmdAuth(uint32_t commandID, TEE_Param param[4]);
index 5f2eb6ff2435b515339d609ec847ede4df1cdd0c..af4cb920c0205b518bc2ab76d0a4830717eba044 100644 (file)
@@ -55,6 +55,7 @@ typedef enum {
        CMD_GENERATE_RSA_KEYPAIR,   ///< Generate random RSA key pair.
        CMD_GENERATE_DSA_KEYPAIR,   ///< Generate random DSA key pair.
        CMD_GENERATE_EC_KEYPAIR,    ///< Generate random EC key pair.
+       CMD_GENERATE_KEM_KEYPAIR,   ///< Generate random KEM key pair.
        CMD_DERIVE,             ///< Derive secret or key
        CMD_IMPORT_WRAPPED_KEY, ///< Import a wrapped key
        CMD_EXPORT_WRAPPED_KEY, ///< Export a key in a wrapped form
@@ -122,6 +123,8 @@ typedef enum {
        TYPE_AKEY_PUBLIC_RSA,
        TYPE_AKEY_PRIVATE_EC,
        TYPE_AKEY_PUBLIC_EC,
+       TYPE_AKEY_PRIVATE_KEM,
+       TYPE_AKEY_PUBLIC_KEM,
 } tz_data_type;
 
 /** \enum tz_ec
@@ -135,6 +138,16 @@ typedef enum {
        EC_NIST_P384,
 } tz_ec;
 
+/** \enum tz_kem
+ * \brief tz_kem contains definitions of supported KEM types
+ *
+ * Each enum corresponds to KEM type supported by TA side.
+ */
+typedef enum {
+       ML_KEM_768,
+       ML_KEM_1024,
+} tz_kem;
+
 /** \enum tz_prf
  * \brief tz_prf contains definitions of supported keyed pseudo random functions
  *
index 058a9f171ba37563a803e0f9c2349bd692328b26..f4e74753af856bc44fc5f0af10d98fdf5e4ef99f 100644 (file)
@@ -36,6 +36,7 @@
 #include <cmd_exec.h>
 #include <cipher_ctx_list.h>
 #include <log.h>
+#include <oqs/kem.h>
 
 // random value to mark unsupported algorithm
 #define KM_TA_ALG_AES_CFB 0x50005050
 const uint32_t PBKDF2_ITERATIONS = 1024;
 const PaddingMode PADDING_MODE = KM_PADDING_PKCS7;
 
+OQS_KEM* createNewKem(const tz_kem kemType)
+{
+       switch (kemType) {
+       case ML_KEM_768: return OQS_KEM_new(OQS_KEM_alg_ml_kem_768);
+       case ML_KEM_1024: return OQS_KEM_new(OQS_KEM_alg_ml_kem_1024);
+       default: return NULL;
+       }
+}
 
 static uint32_t KM_AlgoType2TeeType(int algo)
 {
@@ -712,6 +721,135 @@ TEE_Result KM_ExecCmdGenerateECKey(TEE_Param param[4])
                                                        sizeof(ecParams) / sizeof(*ecParams));
 }
 
+TEE_Result KM_ExecCmdGenerateKEMKey(TEE_Param param[4])
+{
+       TEE_Result ret = TEE_SUCCESS;
+
+       void *in_buffer_ptr = param[1].memref.buffer;
+       uint32_t in_buffer_size_guard = param[1].memref.size;
+       void *out_buffer_ptr = param[2].memref.buffer;
+       uint32_t out_buffer_size_guard = param[2].memref.size;
+
+       uint32_t has_pub_pwd = 0, has_priv_pwd = 0;
+       KM_BinaryData pub_key_tag = {0, NULL};
+       KM_BinaryData priv_key_tag = {0, NULL};
+       KM_BinaryData pub_obj_id = {0, NULL};
+       KM_BinaryData priv_obj_id = {0, NULL};
+       KM_BinaryData encrypted_pub = {0, NULL};
+       KM_BinaryData encrypted_priv = {0, NULL};
+       KM_PwdData pub_key_pwd, priv_key_pwd;
+       uint8_t* public_key = NULL;
+       uint8_t* private_key = NULL;
+       OQS_KEM* kem = NULL;
+
+       tz_kem kem_type = param[0].value.b;
+
+       ret = KM_DeserializeFlagAndPw(&in_buffer_ptr, &in_buffer_size_guard, &has_pub_pwd, &pub_key_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, &in_buffer_size_guard, &has_priv_pwd, &priv_key_pwd);
+       if (ret != TEE_SUCCESS) {
+               LOG("Error in deserialization of private flag and password, ret = %x", ret);
+               goto clean;
+       }
+
+       ret = KM_DeserializeBinaryData(&in_buffer_ptr, &in_buffer_size_guard, &priv_obj_id);
+       if (ret != TEE_SUCCESS) {
+               LOG("Error in deserialization of hash(privobjid), ret = %x", ret);
+               goto clean;
+       }
+
+       ret = KM_DeserializeBinaryData(&in_buffer_ptr, &in_buffer_size_guard, &pub_obj_id);
+       if (ret != TEE_SUCCESS) {
+               LOG("Error in deserialization of hash(pubobjid), 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;
+       }
+
+       public_key = TEE_Malloc(kem->length_public_key*sizeof(uint8_t), 0);
+       private_key = TEE_Malloc(kem->length_secret_key*sizeof(uint8_t), 0);
+       if (public_key == NULL || private_key == NULL) {
+               LOG("Failed to allocate key buffers");
+               ret = TEE_ERROR_OUT_OF_MEMORY;
+               goto clean;
+       }
+
+       OQS_STATUS rc = OQS_KEM_keypair(kem, public_key, private_key);
+       if (rc != OQS_SUCCESS) {
+               LOG("Error in KEM key generation, ret = %x", rc);
+               ret = TEE_ERROR_GENERIC;
+               goto clean;
+       }
+
+       KM_BinaryData pub = {kem->length_public_key, public_key};
+       KM_BinaryData priv = {kem->length_secret_key, private_key};
+
+       // encrypt both keys and serialize tags if needed and save
+       if (has_pub_pwd) {
+               ret = KM_EncryptBinary(&pub_key_pwd, &pub, &encrypted_pub, &pub_key_tag);
+               if (ret != TEE_SUCCESS) {
+                       LOG("Failed to encrypt new key, ret = %x", ret);
+                       goto clean;
+               }
+
+               ret = KM_Serialize(&out_buffer_ptr, &out_buffer_size_guard, pub_key_tag.data, pub_key_tag.data_size);
+               if (ret != TEE_SUCCESS)
+                       goto clean;
+
+               ret = KM_SaveData(encrypted_pub.data, encrypted_pub.data_size, pub_obj_id.data, pub_obj_id.data_size);
+               if (ret != TEE_SUCCESS)
+                       goto clean;
+
+       } else {
+               ret = KM_SaveData(pub.data, pub.data_size, pub_obj_id.data, pub_obj_id.data_size);
+               if (ret != TEE_SUCCESS)
+                       goto clean;
+       }
+
+       if (has_priv_pwd) {
+               ret = KM_EncryptBinary(&priv_key_pwd, &priv, &encrypted_priv, &priv_key_tag);
+               if (ret != TEE_SUCCESS)
+                       goto clean;
+
+               ret = KM_Serialize(&out_buffer_ptr, &out_buffer_size_guard, priv_key_tag.data, priv_key_tag.data_size);
+               if (ret != TEE_SUCCESS)
+                       goto clean;
+
+               ret = KM_SaveData(encrypted_priv.data, encrypted_priv.data_size, priv_obj_id.data, priv_obj_id.data_size);
+               if (ret != TEE_SUCCESS)
+                       goto clean;
+
+       } else {
+               ret = KM_SaveData(priv.data, priv.data_size, priv_obj_id.data, priv_obj_id.data_size);
+               if (ret != TEE_SUCCESS)
+                       goto clean;
+       }
+
+       LOGD_ID("Generated KEM public key: ", pub_obj_id.data, pub_obj_id.data_size);
+       LOGD_ID("Generated KEM private key: ", priv_obj_id.data, priv_obj_id.data_size);
+
+clean:
+       TEE_Free(pub_key_tag.data);
+       TEE_Free(priv_key_tag.data);
+       TEE_Free(encrypted_pub.data);
+       TEE_Free(encrypted_priv.data);
+       TEE_Free(public_key);
+       TEE_Free(private_key);
+       OQS_KEM_free(kem);
+
+       return ret;
+}
+
 static TEE_Result KM_GetSecretValue(KM_BinaryData *secret_id, KM_BinaryData* secret,
                                                        uint32_t with_secret_pwd, KM_PwdData *secret_pwd_data)
 {
@@ -2548,7 +2686,9 @@ TEE_Result KM_ExecCmdSaveData(TEE_Param param[4])
        }
 
        // Let's save data
-       if (dataTypeFlag == TYPE_GENERIC_SECRET) {
+       if (dataTypeFlag == TYPE_GENERIC_SECRET ||
+               dataTypeFlag == TYPE_AKEY_PRIVATE_KEM ||
+               dataTypeFlag == TYPE_AKEY_PUBLIC_KEM) {
                if (with_pwd) {
                        ret = KM_EncryptBinary(&pwdData, &dataToSave, &encData, &tag);
                        if (TEE_SUCCESS != ret) {
index 7f0ef6752ae59c20b7ffb35365a5d8e7657ae9c3..9d389b2777973ef6abc2da36d2fa792486ab0bf7 100644 (file)
@@ -1406,7 +1406,7 @@ TEE_Result KM_GetData(void *data, uint32_t expected_data_size, KM_BinaryData *ob
                        goto clean;
                }
                memcpy(data, buffer.data, buffer.data_size);
-       } else if(obj_type == TYPE_GENERIC_SECRET) {
+       } else if(obj_type == TYPE_GENERIC_SECRET || obj_type == TYPE_AKEY_PUBLIC_KEM) {
                ret = TEE_OpenPersistentObject(TEE_STORAGE_PRIVATE, obj_id->data, obj_id->data_size, flags, &hndl);
                if (TEE_SUCCESS != ret) {
                        LOG("TEE_OpenPersistentObject has failed with=%x.", ret);
@@ -1472,7 +1472,9 @@ TEE_Result KM_GetDataSize(uint32_t *data_size, KM_BinaryData *obj_id,
        TEE_ObjectInfo info;
        KM_BinaryData der = {0, NULL};
 
-       if (obj_type == TYPE_GENERIC_SECRET || obj_type == TYPE_SKEY) {
+       if (obj_type == TYPE_GENERIC_SECRET || obj_type == TYPE_SKEY ||
+               obj_type == TYPE_AKEY_PUBLIC_KEM) {
+
                ret = TEE_OpenPersistentObject(TEE_STORAGE_PRIVATE, obj_id->data, obj_id->data_size, flags, &hndl);
                if (TEE_SUCCESS != ret) {
                        LOG("TEE_OpenPersistentObject has failed with=%x.", ret);
index 9bd3cca4095423714dfabf63ee8ba3e33ffcec84..d45bc9e826505e5f2aa84708362c25b6160cb2f2 100644 (file)
@@ -173,6 +173,11 @@ TEE_Result TA_InvokeCommandEntryPoint(
                ret = KM_ExecCmdGenerateECKey(param);
                break;
        }
+       case CMD_GENERATE_KEM_KEYPAIR: {
+               LOGD("!!! Generating KEM key pair !!!");
+               ret = KM_ExecCmdGenerateKEMKey(param);
+               break;
+       }
        case CMD_DERIVE: {
                LOGD("!!! Deriving a key !!!");
                ret = KM_ExecCmdDeriveKey(param);