Files
odkitee/oemcrypto_ta/oemcrypto_key_table.c
2020-07-24 12:03:58 -07:00

144 lines
4.4 KiB
C

/* Copyright 2019 Google LLC. All Rights Reserved. This file and proprietary
source code may only be used and distributed under the Widevine Master
License Agreement. */
#include "oemcrypto_key_table.h"
#include "stdint.h"
#include "string.h"
#include "assert_interface.h"
#include "logging_interface.h"
static KeyTable key_table;
static bool key_table_initialized = false;
OEMCryptoResult InitializeKeyTable(void) {
ASSERT(MAX_NUMBER_OF_KEYS > 0, "MAX_NUMBER_OF_KEYS must be > 0");
ASSERT(MAX_NUMBER_OF_KEYS < UINT32_MAX - 1,
"MAX_NUMBER_OF_KEYS is too large");
if (key_table_initialized) {
return OEMCrypto_ERROR_INIT_FAILED;
}
key_table.size = MAX_NUMBER_OF_KEYS;
key_table.first_free_key = 0;
for (uint32_t i = 0; i < key_table.size; i++) {
key_table.next_free_key[i] = i + 1;
key_table.is_free[i] = true;
memset(&key_table.keys[i], 0, sizeof(CryptoKey));
}
key_table_initialized = true;
return OEMCrypto_SUCCESS;
}
uint32_t MaxNumberOfKeys(void) { return MAX_NUMBER_OF_KEYS; }
OEMCryptoResult NumberOfUsedKeys(uint32_t* num_used_keys) {
ASSERT(num_used_keys != NULL, "num_used_keys is NULL");
if (!key_table_initialized) {
return OEMCrypto_ERROR_SYSTEM_INVALIDATED;
}
for (uint32_t i = 0; i < key_table.size; i++) {
if (!key_table.is_free[i]) {
(*num_used_keys)++;
}
}
return OEMCrypto_SUCCESS;
}
OEMCryptoResult GrabKey(uint32_t* index) {
ASSERT(index != NULL, "index is NULL");
if (!key_table_initialized) {
return OEMCrypto_ERROR_SYSTEM_INVALIDATED;
}
if (key_table.first_free_key == MAX_NUMBER_OF_KEYS) {
return OEMCrypto_ERROR_TOO_MANY_KEYS;
}
*index = key_table.first_free_key;
key_table.first_free_key = key_table.next_free_key[*index];
key_table.is_free[*index] = false;
key_table.keys[*index].key_table_index = *index;
return OEMCrypto_SUCCESS;
}
OEMCryptoResult GetKey(uint32_t index, CryptoKey** key) {
ASSERT(key != NULL, "key is NULL");
if (!key_table_initialized) {
return OEMCrypto_ERROR_SYSTEM_INVALIDATED;
}
if (index >= key_table.size || key_table.is_free[index]) {
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
*key = &key_table.keys[index];
return OEMCrypto_SUCCESS;
}
OEMCryptoResult CreateKey(CryptoKey** key, const uint8_t* serialized_bytes,
uint32_t serialized_bytes_length,
CryptoKeyType key_type,
CryptoKeyOperation key_operation,
CryptoKeySize key_size) {
ASSERT(key != NULL, "key is NULL");
OEMCryptoResult result;
if (*key != NULL) {
result = FreeKey(key);
if (result != OEMCrypto_SUCCESS) return result;
}
uint32_t key_table_index = 0;
result = GrabKey(&key_table_index);
if (result != OEMCrypto_SUCCESS) return result;
result = GetKey(key_table_index, key);
if (result != OEMCrypto_SUCCESS) {
FreeKey(key);
return result;
}
result = InitializeCryptoKey(*key, serialized_bytes, serialized_bytes_length,
key_type, key_operation, key_size);
if (result != OEMCrypto_SUCCESS) {
FreeKey(key);
return result;
}
return OEMCrypto_SUCCESS;
}
OEMCryptoResult FreeKey(CryptoKey** key) {
ASSERT(key != NULL, "key is NULL");
if (*key == NULL) return OEMCrypto_SUCCESS;
uint32_t index = (*key)->key_table_index;
if (!key_table_initialized) {
return OEMCrypto_ERROR_SYSTEM_INVALIDATED;
}
if (index >= key_table.size || key_table.is_free[index]) {
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
OEMCryptoResult result = FreeCryptoKey(&key_table.keys[index]);
if (result != OEMCrypto_SUCCESS) {
return result;
}
key_table.next_free_key[index] = key_table.first_free_key;
key_table.is_free[index] = true;
key_table.first_free_key = index;
*key = NULL;
return OEMCrypto_SUCCESS;
}
OEMCryptoResult TerminateKeyTable(void) {
if (!key_table_initialized) {
return OEMCrypto_ERROR_TERMINATE_FAILED;
}
OEMCryptoResult result = OEMCrypto_SUCCESS;
for (uint32_t i = 0; i < key_table.size; i++) {
if (!key_table.is_free[i]) {
result = OEMCrypto_ERROR_TERMINATE_FAILED;
/* Attempt to free the key. */
CryptoKey* key = &key_table.keys[i];
OEMCryptoResult free_result = FreeKey(&key);
if (free_result != OEMCrypto_SUCCESS) {
LOGE("Could not free key at index %d with error: %d", i, free_result);
}
}
}
key_table_initialized = false;
return result;
}