Files
oemcrypto/oemcrypto/opk/oemcrypto_ta/oemcrypto_asymmetric_key_table.c
Fred Gylys-Colwell a11741f98d Initial OPK Partner Beta v16 Release
See https://developers.google.com/widevine/drm/client/opk
for documentation and an integration guide.
2021-12-16 00:18:35 +00:00

112 lines
3.8 KiB
C

/* Copyright 2021 Google LLC. All Rights Reserved. This file and proprietary
source code may only be used and distributed under the Widevine License
Agreement. */
#include "oemcrypto_asymmetric_key_table.h"
#include <stdbool.h>
#include <stdint.h>
#include <string.h>
#include "oemcrypto_object_table.h"
#include "wtpi_abort_interface.h"
#include "wtpi_logging_interface.h"
#if MAX_NUMBER_OF_ASYMMETRIC_KEYS <= 0
# error "MAX_NUMBER_OF_ASYMMETRIC_KEYS must be > 0"
#elif MAX_NUMBER_OF_ASYMMETRIC_KEYS >= UINT32_MAX - 1
# error "MAX_NUMBER_OF_ASYMMETRIC_KEYS is too large"
#endif
static OEMCryptoResult DtorTrampoline(void* key) {
return OPKI_FreeAsymmetricKey((AsymmetricKey*)key);
}
DEFINE_OBJECT_TABLE(key_table, AsymmetricKey, MAX_NUMBER_OF_ASYMMETRIC_KEYS,
&DtorTrampoline);
void OPKI_InitializeAsymmetricKeyTable(void) {
OPKI_UnsafeClearObjectTable(&key_table);
}
uint32_t OPKI_MaxNumberOfAsymmetricKeys(void) { return key_table.capacity; }
OEMCryptoResult OPKI_NumberOfUsedAsymmetricKeys(uint32_t* num_used_keys) {
if (num_used_keys == NULL) return OEMCrypto_ERROR_INVALID_CONTEXT;
*num_used_keys = OPKI_GetObjectTableUseCount(&key_table);
return OEMCrypto_SUCCESS;
}
OEMCryptoResult OPKI_CreateAsymmetricKey(
AsymmetricKey** key, AsymmetricKeyType key_type, const uint8_t* wrapped_key,
size_t wrapped_key_length, size_t key_size, uint32_t allowed_schemes) {
if (key == NULL || wrapped_key == NULL || wrapped_key_length == 0)
return OEMCrypto_ERROR_INVALID_CONTEXT;
OEMCryptoResult result;
if (*key != NULL) {
result = OPKI_FreeAsymmetricKeyFromTable(key);
if (result != OEMCrypto_SUCCESS) return result;
}
bool key_found = false;
AsymmetricKey* cur_key = NULL;
/* If the same wrapped key already exists in the key table, just updates the
* reference counter and returns a pointer to the existing key. */
for (uint32_t i = 0; i < key_table.capacity; i++) {
cur_key = (AsymmetricKey*)OPKI_GetFromObjectTable(&key_table, i);
if (cur_key != NULL && key_type == cur_key->key_type &&
wrapped_key_length == cur_key->wrapped_key_length &&
memcmp(wrapped_key, cur_key->wrapped_key, wrapped_key_length) == 0) {
key_found = true;
break;
}
}
if (!key_found) {
cur_key = OPKI_AllocFromObjectTable(&key_table, NULL);
if (cur_key == NULL) return OEMCrypto_ERROR_TOO_MANY_KEYS;
result = OPKI_InitializeAsymmetricKey(cur_key, key_type, wrapped_key,
wrapped_key_length, key_size,
allowed_schemes);
if (result != OEMCrypto_SUCCESS) {
OPKI_FreeAsymmetricKeyFromTable(key);
return result;
}
}
cur_key->ref_count++;
*key = cur_key;
return OEMCrypto_SUCCESS;
}
OEMCryptoResult OPKI_FreeAsymmetricKeyFromTable(AsymmetricKey** key) {
if (!key) return OEMCrypto_ERROR_INVALID_CONTEXT;
if ((*key) == NULL) return OEMCrypto_SUCCESS;
OEMCryptoResult result = OEMCrypto_SUCCESS;
if ((*key)->ref_count > 0) {
(*key)->ref_count--;
}
if ((*key)->ref_count == 0) {
result = OPKI_FreeFromObjectTable(&key_table, *key);
}
if (result == OEMCrypto_SUCCESS) *key = NULL;
return result;
}
OEMCryptoResult OPKI_TerminateAsymmetricKeyTable(void) {
OEMCryptoResult result = OEMCrypto_SUCCESS;
for (uint32_t i = 0; i < key_table.capacity; i++) {
AsymmetricKey* key = OPKI_GetFromObjectTable(&key_table, i);
if (key) {
/* Attempt to free the key. */
key->ref_count = 0;
OEMCryptoResult free_result = OPKI_FreeAsymmetricKeyFromTable(&key);
if (free_result != OEMCrypto_SUCCESS) {
LOGE("Could not free asymmetric key at index %u with error: %u", i,
free_result);
if (result == OEMCrypto_SUCCESS) {
result = OEMCrypto_ERROR_TERMINATE_FAILED;
}
}
}
}
return result;
}