/*
 * This file must contain crypto functions of engineering mode sources.
 * Internal functions for use only by engineering mode module.
 */
#include <ctype.h>
#include <stdio.h>
#include <string.h>
#include <tees_kdf.h>

#include "em_common.h"
#include "crypto/em_crypto_cert.h"

#include "openssl/crypto.h"
#include "openssl/err.h"
#include "openssl/err.h"
#include "openssl/evp.h"
#include "openssl/hmac.h"
#include "openssl/rsa.h"
#include "openssl/x509.h"

int em_get_random(unsigned char *buf, int required_len)
{
	int ret;

	EM_CHECK_NULL(__func__, EM_ERR_EM_GET_RANDOM, buf);

	if (required_len < 0) {
		LOGE("Unexpected length(%u)\n", required_len);
		ret = EM_ERR_EM_GET_RANDOME_LEN;
		goto out;
	}

	TEE_GenerateRandom(buf, (size_t)required_len);

	ret = required_len;
out:
	return ret;
}

int em_crypto_kdf(uint8_t *key, int32_t key_len, uint8_t *iv, uint32_t iv_len)
{
	const char key_label[] = {"EngineeringMode20 AES256 Key Label, MSTG."};
	const char key_context[] = {"EngineeringMode20 AES256 Key Context, MSTG."};
	const char iv_label[] = {"EngineeringMode20 AES256 GCM IV Label, MSTG."};
	const char iv_context[] = {"EngineeringMode20 AES256 GCM IV Context, MSTG."};

	TEE_ObjectHandle obj_key = TEE_HANDLE_NULL;
	TEE_ObjectHandle obj_iv = TEE_HANDLE_NULL;
	unsigned int out_len;
	TEE_Result tret;
	int ret = EM_ERR_EM_CRYPTO_KDF_TEEGRIS_ALL;

	EM_CHECK_NULL(__func__, EM_ERR_EM_CRYPTO_KDF_TEEGRIS, key, iv);

	tret = TEE_AllocateTransientObject(TEE_TYPE_GENERIC_SECRET, key_len * 8, &obj_key);
	if (tret != TEE_SUCCESS) {
		LOGE("(key)InitializeContext failed: 0x%08x\n", tret);
		goto out;
	}

	tret = TEES_DeriveKeyKDF(key_label, sizeof(key_label), key_context, sizeof(key_context), key_len, obj_key);
	if (tret != TEE_SUCCESS) {
		LOGE("(key)TEES_DeriveKeyKDF failed: 0x%08x\n", tret);
		goto out;
	}

	out_len = key_len;
	tret = TEE_GetObjectBufferAttribute(obj_key, TEE_ATTR_SECRET_VALUE, key, &out_len);
	if (tret != TEE_SUCCESS) {
		LOGE("(key)TEE_GetObjectBufferAttribute failed: 0x%08x\n", tret);
		goto out;
	}

	tret = TEE_AllocateTransientObject(TEE_TYPE_GENERIC_SECRET, iv_len * 8, &obj_iv);
	if (tret != TEE_SUCCESS) {
		LOGE("(iv)InitializeContext failed: 0x%08x\n", tret);
		goto out;
	}

	tret = TEES_DeriveKeyKDF(iv_label, sizeof(iv_label), iv_context, sizeof(iv_context), iv_len, obj_iv);
	if (tret != TEE_SUCCESS) {
		LOGE("(iv)TEES_DeriveKeyKDF failed: 0x%08x\n", tret);
		goto out;
	}

	out_len = iv_len;
	tret = TEE_GetObjectBufferAttribute(obj_iv, TEE_ATTR_SECRET_VALUE, iv, &out_len);
	if (tret != TEE_SUCCESS) {
		LOGE("(iv)TEE_GetObjectBufferAttribute failed: 0x%08x\n", tret);
		goto out;
	}

	ret = EM_SUCCESS;
out:
	if (obj_key != TEE_HANDLE_NULL) {
		TEE_CloseObject(obj_key);
	}

	if (obj_iv != TEE_HANDLE_NULL) {
		TEE_CloseObject(obj_iv);
	}

	return ret;
}
