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,
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;
+}