Support KBKDF 73/296173/24
authorDongsun Lee <ds73.lee@samsung.com>
Fri, 21 Jul 2023 03:09:09 +0000 (12:09 +0900)
committerDongsun Lee <ds73.lee@samsung.com>
Thu, 10 Aug 2023 04:35:06 +0000 (13:35 +0900)
Change-Id: I0ada7c5d18d242c25c17f526fafae6ef1fc11979

ta/include/crypto_derive.h
ta/src/cmd_exec.c
ta/src/crypto_derive.c

index b9f76299950acae9ab15601017d73242b69d877f..444f8d34e225fb915f13ecd07b0311d5be9d5ece 100644 (file)
 #define __CRYPTO_DERIVE_H__
 
 #include <tee_internal_api.h>
+#include <internal.h>
 
 TEE_Result KM_DeriveKey(void *pwd, uint32_t pwd_size, void *salt, uint32_t salt_size,
                                                uint32_t iterations, uint32_t key_type, uint32_t key_bits_size,
                                                TEE_ObjectHandle* out_key);
 
+TEE_Result KM_KbkdfHmacCtr(
+                                               unsigned char* keyIn, unsigned int KILen,
+                                               unsigned int hmacAlgo, unsigned int ctrLoc,
+                                               unsigned int rLenInBits, unsigned int lLenInBits,
+                                               unsigned char* Label, unsigned int LabelLen,
+                                               unsigned char* Context, unsigned int ContextLen,
+                                               unsigned char* fixedInput, unsigned int fixedInputLen,
+                                               unsigned int no_separator,
+                                               unsigned char* keyOut, unsigned int keyOutLen);
+
 #endif // __CRYPTO_DERIVE_H__
index fb0980295dcd6c5df8192d960045e1b782170955..b40ca1ea6781e93635677c2c8f6b581467736a61 100644 (file)
@@ -648,10 +648,240 @@ TEE_Result KM_ExecCmdGenerateECKey(TEE_Param param[4])
                                                        sizeof(ecParams) / sizeof(*ecParams));
 }
 
+static TEE_Result KM_GetSecretValue(KM_BinaryData *secret_id, KM_BinaryData* secret,
+                                                       uint32_t with_secret_pwd, KM_PwdData *secret_pwd_data)
+{
+       TEE_Result ret = TEE_SUCCESS;
+       TEE_ObjectHandle secret_handle = TEE_HANDLE_NULL;
+       TEE_ObjectHandle key_handle = TEE_HANDLE_NULL;
+       TEE_ObjectInfo secret_info;
+       KM_BinaryData output = {0, NULL};
+       uint32_t out_len = 0;
+
+       ret = KM_OpenKey(secret_id->data, secret_id->data_size, &secret_handle);
+       if (ret != TEE_SUCCESS) {
+               LOGD_ID("Failed to open object data from storage: ", secret_id->data, secret_id->data_size);
+               goto clean;
+       }
+       TEE_GetObjectInfo(secret_handle, &secret_info);
+       TEE_CloseObject(secret_handle);
+
+       if (secret_info.dataSize > 0) { // data
+               out_len = secret_info.dataSize;
+       } else {
+               out_len = secret_info.objectSize;
+       }
+
+       output.data = malloc(out_len);
+       if(output.data == NULL) {
+               LOG("Failed to assign memory. requested size=%d", out_len);
+               ret = TEE_ERROR_OUT_OF_MEMORY;
+               goto clean;
+       }
+       output.data_size = out_len;
+
+       if (secret_info.dataSize > 0) { // data
+               ret = KM_GetData(output.data, output.data_size, secret_id,
+                                               with_secret_pwd, secret_pwd_data, TYPE_GENERIC_SECRET);
+               if (ret != TEE_SUCCESS) {
+                       LOG("Failed to read object data from storage");
+                       goto clean;
+               }
+       } else { // key
+               if (with_secret_pwd) {
+                       ret = KM_DecryptKey(secret_id->data, secret_id->data_size, secret_pwd_data, &key_handle);
+               } else {
+                       ret = KM_OpenKey(secret_id->data, secret_id->data_size, &key_handle);
+               }
+               if (TEE_SUCCESS != ret) {
+                       LOG("KM_DecryptKey or KM_OpenKey has failed with=%x. with_secret_pwd=%d", ret, with_secret_pwd);
+                       goto clean;
+               }
+               ret = TEE_GetObjectBufferAttribute(key_handle, TEE_ATTR_SECRET_VALUE,
+                                                                       output.data, &output.data_size);
+               if (ret != TEE_SUCCESS) {
+                       LOG("Failed to acquire key from object: %x", ret);
+                       goto clean;
+               }
+       }
+
+       secret->data = output.data;
+       secret->data_size = output.data_size;
+
+clean:
+       TEE_CloseObject(key_handle);
+       if(ret != TEE_SUCCESS)
+               free(output.data);
+
+       return ret;
+}
+
 TEE_Result KM_ExecCmdDeriveKbkdf(TEE_Param param[4])
 {
-       // TODO
-    return TEE_SUCCESS;
+       TEE_Result ret = TEE_SUCCESS;
+       TEE_ObjectHandle key_handle = TEE_HANDLE_NULL;
+       KM_BinaryData secret_id = {0, NULL};
+       KM_BinaryData label = {0, NULL};
+       KM_BinaryData context = {0, NULL};
+       KM_BinaryData fixed = {0, NULL};
+       KM_BinaryData obj_id = {0, NULL};
+       KM_BinaryData key_in = {0, NULL};
+       KM_BinaryData derived_key = {0, NULL};
+       KM_BinaryData enc_drv_key = {0, NULL};
+       KM_BinaryData tag= {0, NULL};
+       uint32_t with_secret_pwd = 0;
+       KM_PwdData secret_pwd_data;
+       uint32_t outlen;
+       uint32_t prf;
+       uint32_t mode;
+       uint32_t ctrloc;
+       uint32_t rlen;
+       uint32_t llen;
+       uint32_t no_separator;
+       uint32_t with_pwd = 0;
+       KM_PwdData pwd_data;
+
+       void *in_buffer = param[1].memref.buffer;
+       void *out_buffer = param[2].memref.buffer;
+       uint32_t in_size_guard = param[1].memref.size;
+       uint32_t out_size_guard = param[2].memref.size;
+
+       // Deserialize data from REE
+       if (KM_DeserializeBinaryData(&in_buffer, &in_size_guard, &secret_id)) {
+               LOG("Error in deserialization");
+               return TEE_ERROR_BAD_PARAMETERS;
+       }
+
+       if (KM_DeserializeFlagAndPw(&in_buffer, &in_size_guard, &with_secret_pwd, &secret_pwd_data)) {
+               LOG("Error in deserialization");
+               return TEE_ERROR_BAD_PARAMETERS;
+       }
+
+       if (KM_DeserializeFlag(&in_buffer, &in_size_guard, &outlen)) {
+               LOG("Failed to deserialize pwd flag");
+               return TEE_ERROR_BAD_PARAMETERS;
+       }
+
+       if (KM_DeserializeBinaryData(&in_buffer, &in_size_guard, &label)) {
+               LOG("Error in deserialization");
+               return TEE_ERROR_BAD_PARAMETERS;
+       }
+
+       if (KM_DeserializeBinaryData(&in_buffer, &in_size_guard, &context)) {
+               LOG("Error in deserialization");
+               return TEE_ERROR_BAD_PARAMETERS;
+       }
+
+       if (KM_DeserializeBinaryData(&in_buffer, &in_size_guard, &fixed)) {
+               LOG("Error in deserialization");
+               return TEE_ERROR_BAD_PARAMETERS;
+       }
+
+       if (KM_DeserializeFlag(&in_buffer, &in_size_guard, &prf)) {
+               LOG("Failed to deserialize pwd flag");
+               return TEE_ERROR_BAD_PARAMETERS;
+       }
+
+       if (KM_DeserializeFlag(&in_buffer, &in_size_guard, &mode)) {
+               LOG("Failed to deserialize pwd flag");
+               return TEE_ERROR_BAD_PARAMETERS;
+       }
+
+       if (KM_DeserializeFlag(&in_buffer, &in_size_guard, &ctrloc)) {
+               LOG("Failed to deserialize pwd flag");
+               return TEE_ERROR_BAD_PARAMETERS;
+       }
+
+       if (KM_DeserializeFlag(&in_buffer, &in_size_guard, &rlen)) {
+               LOG("Failed to deserialize pwd flag");
+               return TEE_ERROR_BAD_PARAMETERS;
+       }
+
+       if (KM_DeserializeFlag(&in_buffer, &in_size_guard, &llen)) {
+               LOG("Failed to deserialize pwd flag");
+               return TEE_ERROR_BAD_PARAMETERS;
+       }
+
+       if (KM_DeserializeFlag(&in_buffer, &in_size_guard, &no_separator)) {
+               LOG("Failed to deserialize pwd flag");
+               return TEE_ERROR_BAD_PARAMETERS;
+       }
+
+       if (KM_DeserializeFlagAndPw(&in_buffer, &in_size_guard, &with_pwd, &pwd_data)) {
+               LOG("Error in deserialization");
+               return TEE_ERROR_BAD_PARAMETERS;
+       }
+
+       if (KM_DeserializeBinaryData(&in_buffer, &in_size_guard, &obj_id)) {
+               LOG("Error in deserialization of secret_hash(objId)");
+               return TEE_ERROR_BAD_PARAMETERS;
+       }
+
+       // Get Key_In from permanent storage
+       ret = KM_GetSecretValue(&secret_id, &key_in, with_secret_pwd, &secret_pwd_data);
+       if (ret != TEE_SUCCESS) {
+               LOGD_ID("Failed to get Secret Value from object: ", secret_id.data, secret_id.data_size);
+               goto clean;
+       }
+
+       // execute KBKDF
+       derived_key.data = (unsigned char *) malloc(outlen);
+       derived_key.data_size = outlen;
+       if (derived_key.data == NULL) {
+               LOG("Failed to allocate input buffer for derived_key");
+               ret = TEE_ERROR_OUT_OF_MEMORY;
+               goto clean;
+       }
+
+       ret = KM_KbkdfHmacCtr(key_in.data, key_in.data_size,
+                                                       prf, ctrloc, rlen, llen,
+                                                       label.data, label.data_size,
+                                                       context.data, context.data_size,
+                                                       fixed.data, fixed.data_size,
+                                                       no_separator,
+                                                       derived_key.data, outlen);
+       if (ret != TEE_SUCCESS) {
+               LOG("Failed in KM_KbkdfHmacCtr(): ret=%x", ret);
+               goto clean;
+       }
+
+       // Serialize data for sending to REE.
+       if (with_pwd) {
+               ret = KM_EncryptBinary(&pwd_data, &derived_key, &enc_drv_key, &tag);
+               if (TEE_SUCCESS != ret) {
+                       LOG("Failed to encrypt new key");
+                       goto clean;
+               }
+               // output tag
+               if (KM_Serialize(&out_buffer, &out_size_guard, tag.data, tag.data_size)) {
+                       LOG("Error in serialization");
+                       ret = TEE_ERROR_BAD_PARAMETERS;
+                       goto clean;
+               }
+               ret = KM_CreateKey(TEE_TYPE_AES, enc_drv_key.data_size * 8, enc_drv_key.data, &key_handle);
+       } else {
+               ret = KM_CreateKey(TEE_TYPE_AES, derived_key.data_size * 8, derived_key.data, &key_handle);
+       }
+       if (ret != TEE_SUCCESS) {
+               LOG("Failed to create key");
+               goto clean;
+       }
+
+       ret = KM_SaveKey(NULL, 0, key_handle, obj_id.data, obj_id.data_size);
+       if (TEE_SUCCESS != ret) {
+               LOG("Failed to save generated key");
+               goto clean;
+       }
+
+       LOGD_ID("Derive KBKDF key: ", obj_id.data, obj_id.data_size);
+clean:
+       TEE_CloseObject(key_handle);
+       free(key_in.data);
+       free(derived_key.data);
+       free(enc_drv_key.data);
+       free(tag.data);
+
+       return ret;
 }
 
 TEE_Result KM_DeriveEcdhSecret(const TEE_ObjectHandle prv_key, const KM_BinaryData *pub_x,
index 13a7ce07d29e415d708d59ba4fb25cafa10fd300..b58193f650fceac6f700ca5b8f151e768f36a56f 100644 (file)
@@ -208,3 +208,190 @@ end:
 
        return ret;
 }
+
+
+// implements KBDKF key derivation routine
+#define ceiling(x,y)  ((x + y -1) / y)
+
+void word2byte(unsigned char* dst, const unsigned int src, const int srcLen)
+{
+       int i = 0, shift = 0;
+       for (i = 0; i < srcLen; i++)
+       {
+               shift = (srcLen - (i + 1)) * 8;
+               dst[i] = (unsigned char)((src >> shift) & 0xff);
+       }
+}
+
+static size_t getMacLen(unsigned int hmacAlgo)
+{
+       switch(hmacAlgo) {
+               case PRF_HMAC_SHA256: return 256 / 8;
+               case PRF_HMAC_SHA384: return 384 / 8;
+               case PRF_HMAC_SHA512: return 512 / 8;
+               default: return 0;
+       }
+}
+
+static unsigned int getObjectType(unsigned int hmacAlgo)
+{
+       switch(hmacAlgo) {
+               case PRF_HMAC_SHA256: return TEE_TYPE_HMAC_SHA256;
+               case PRF_HMAC_SHA384: return TEE_TYPE_HMAC_SHA384;
+               case PRF_HMAC_SHA512: return TEE_TYPE_HMAC_SHA512;
+               default: return 0;
+       }
+}
+
+static unsigned int getOperAlgo(unsigned int hmacAlgo)
+{
+       switch(hmacAlgo) {
+               case PRF_HMAC_SHA256: return TEE_ALG_HMAC_SHA256;
+               case PRF_HMAC_SHA384: return TEE_ALG_HMAC_SHA384;
+               case PRF_HMAC_SHA512: return TEE_ALG_HMAC_SHA512;
+               default: return 0;
+       }
+}
+
+TEE_Result KM_KbkdfHmacCtr(
+                                               unsigned char* keyIn, unsigned int KILen,
+                                               unsigned int hmacAlgo, unsigned int ctrLoc,
+                                               unsigned int rLenInBits, unsigned int lLenInBits,
+                                               unsigned char* Label, unsigned int LabelLen,
+                                               unsigned char* Context, unsigned int ContextLen,
+                                               unsigned char* fixedInput, unsigned int fixedInputLen,
+                                               unsigned int no_separator,
+                                               unsigned char* keyOut, unsigned int keyOutLen)
+{
+       // https://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-108r1.pdf
+       TEE_Result ret = TEE_SUCCESS;
+       TEE_OperationHandle hmacOp = TEE_HANDLE_NULL;
+       unsigned int keyType = 0, operAlgo = 0;
+       int n = 0, i = 0;
+       int inputLen = 0, macLen = 0, lLen = 0, rLen = 0;
+       unsigned char* input = NULL, *K = NULL;
+       unsigned int ctr = 0;
+       unsigned int separatorLen = 1; // 0x00 between Label and Context
+       size_t tmpOutLen = 0;
+
+       macLen = getMacLen(hmacAlgo);
+       if (macLen <= 0) {
+               LOG("Not supported hmacAlgo. hmacAlgo=%x", hmacAlgo);
+               ret = TEE_ERROR_BAD_PARAMETERS;
+               goto clean;
+       }
+
+       keyType = getObjectType(hmacAlgo);
+       if (keyType <= 0) {
+               LOG("Failed to convert key type. hmacAlgo=%x", hmacAlgo);
+               ret = TEE_ERROR_BAD_PARAMETERS;
+               goto clean;
+       }
+
+       operAlgo = getOperAlgo(hmacAlgo);
+       if (operAlgo <= 0) {
+               LOG("Failed to convert Operation Algorithm. hmacAlgo=%x", hmacAlgo);
+               ret = TEE_ERROR_BAD_PARAMETERS;
+               goto clean;
+       }
+
+       ret = KM_CreateOperationWithKey(keyIn, keyType, TEE_MODE_MAC, operAlgo, KILen * 8, &hmacOp);
+       if (ret != TEE_SUCCESS) {
+               LOG("Failed to create HMAC operation: %x", ret);
+               goto clean;
+       }
+
+       if (ctrLoc == KBKDF_LOC_MIDDLE_FIXED || no_separator)
+               separatorLen = 0;
+
+
+       n = ceiling(keyOutLen, macLen);
+
+       rLen = rLenInBits / 8;
+       lLen = lLenInBits / 8;
+       if (lLenInBits > 4 * 8) {
+               LOG("Not supported lLenInBits. lLenInBits=%d", lLenInBits);
+               ret = TEE_ERROR_BAD_PARAMETERS;
+               goto clean;
+       }
+
+       if (fixedInputLen > 0) {
+               inputLen = fixedInputLen + rLen;
+               input = (unsigned char*)calloc(inputLen, sizeof(unsigned char));
+               if(input == NULL) {
+                       LOG("Failed to allocate memory. requested_memory_size=%d", inputLen);
+                       ret = TEE_ERROR_OUT_OF_MEMORY;
+                       goto clean;
+               }
+
+               switch(ctrLoc) {
+                       case KBKDF_LOC_BEFORE_FIXED: {
+                               memcpy(input + rLen, fixedInput, sizeof(unsigned char) * fixedInputLen);
+                               break;
+                       };
+                       case KBKDF_LOC_AFTER_FIXED: { // Separator is not used
+                               memcpy(input, fixedInput, sizeof(unsigned char) * fixedInputLen);
+                               break;
+                       };
+                       default: {
+                               LOG("Not supported Counter Location for Fixed Input. ctrLoc=%d", ctrLoc);
+                               ret = TEE_ERROR_BAD_PARAMETERS;
+                               goto clean;
+                               break;
+                       }
+               }
+       } else {
+               inputLen = rLen + LabelLen + separatorLen + ContextLen + lLen;
+               input = (unsigned char*)calloc(inputLen, sizeof(unsigned char));
+
+               switch(ctrLoc) {
+                       case KBKDF_LOC_BEFORE_FIXED: {
+                               memcpy(input + rLen, Label, sizeof(unsigned char) * LabelLen);
+                               memcpy(input + rLen + LabelLen + separatorLen, Context, sizeof(unsigned char) * ContextLen);
+                               word2byte(input + rLen + LabelLen + separatorLen + ContextLen, keyOutLen * 8, lLen);
+                               break;
+                       };
+                       case KBKDF_LOC_AFTER_FIXED: {
+                               memcpy(input, Label, sizeof(unsigned char) * LabelLen);
+                               memcpy(input + LabelLen + separatorLen, Context, sizeof(unsigned char) * ContextLen);
+                               word2byte(input + LabelLen + separatorLen + ContextLen, keyOutLen * 8, lLen);
+                               break;
+                       };
+                       case KBKDF_LOC_MIDDLE_FIXED: { // Separator is not used
+                               memcpy(input, Label, sizeof(unsigned char) * LabelLen);
+                               memcpy(input + LabelLen + rLen, Context, sizeof(unsigned char) * ContextLen);
+                               word2byte(input + LabelLen + rLen + ContextLen, keyOutLen * 8, lLen);
+                               break;
+                       };
+               }
+       }
+
+       K = (unsigned char*)calloc(macLen * n, sizeof(unsigned char));
+
+       for (i = 0; i < n; i++) {
+               ctr++;
+               if(ctrLoc == KBKDF_LOC_BEFORE_FIXED) {
+                       word2byte(input, ctr, rLen);
+               } else if(ctrLoc == KBKDF_LOC_AFTER_FIXED) {
+                       word2byte(input + (inputLen - rLen), ctr, rLen);
+               } else { // KBKDF_LOC_MIDDLE_FIXED
+                       word2byte(input + LabelLen, ctr, rLen);
+               }
+
+               tmpOutLen = macLen; // GP TEE_MACComputeFinal requires a size of the output buffer.
+               ret = KM_DeriveKeyDoHMACIteration(hmacOp, input, inputLen, K + (i * macLen), &tmpOutLen);
+               if (ret != TEE_SUCCESS) {
+                       LOG("Failure during HMAC operation");
+                       goto clean;
+               }
+       }
+
+       memcpy(keyOut, K, sizeof(unsigned char) * keyOutLen);
+
+clean:
+       TEE_FreeOperation(hmacOp);
+       free(input);
+       free(K);
+
+       return TEE_SUCCESS;
+}