First Publicly Shared Version of ODKiTEE v15
This commit is contained in:
146
oemcrypto_ta/oemcrypto_key.c
Normal file
146
oemcrypto_ta/oemcrypto_key.c
Normal file
@@ -0,0 +1,146 @@
|
||||
/* 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.h"
|
||||
|
||||
#include "string.h"
|
||||
|
||||
#include "assert_interface.h"
|
||||
#include "oemcrypto_endianness.h"
|
||||
|
||||
/* Mask combined with key pointers for the CryptoKey struct to ensure that a key
|
||||
is well-formed. */
|
||||
static uint64_t COOKIE_MASK = 0x1bc15e9624a069ffULL;
|
||||
|
||||
static uint64_t calculate_cookie(CryptoKey* key) {
|
||||
ASSERT(key != NULL, "key is NULL");
|
||||
ASSERT(key->key_handle != NULL, "key_handle is NULL");
|
||||
return COOKIE_MASK ^ (uint64_t)((uintptr_t)key) ^
|
||||
(uint64_t)((uintptr_t)key->key_handle);
|
||||
}
|
||||
|
||||
OEMCryptoResult InitializeCryptoKey(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");
|
||||
ASSERT(serialized_bytes != NULL, "serialized_bytes is NULL");
|
||||
ASSERT(serialized_bytes_length > 0, "serialized_bytes_length is 0");
|
||||
ASSERT(key_type != UNKNOWN_KEY_TYPE, "key_type is UNKNOWN_KEY_TYPE");
|
||||
/* Note that for some keys, we can only know the size from context, since
|
||||
serialized_bytes_length corresponds to the size of the serialized key, not
|
||||
the key itself necessarily. So, it's okay for key_size to be unknown.
|
||||
Similarly, sometimes we want to just load the key without using it, so the
|
||||
operation is allowed to be unknown. */
|
||||
OEMCryptoResult result = CreateKeyHandle(
|
||||
serialized_bytes, serialized_bytes_length, key_type, &(key->key_handle));
|
||||
if (result != OEMCrypto_SUCCESS) return result;
|
||||
key->cookie = calculate_cookie(key);
|
||||
memset(key->key_id, 0, KEY_ID_MAX_SIZE);
|
||||
key->key_id_size = 0;
|
||||
key->key_type = key_type;
|
||||
key->key_operation = key_operation;
|
||||
key->key_size = key_size;
|
||||
key->allowed_schemes = 0;
|
||||
memset(&key->key_control_block, 0, sizeof(key->key_control_block));
|
||||
key->entitled_content_key_index = 0;
|
||||
key->has_entitled_content_key = false;
|
||||
key->entitlement_key_index = 0;
|
||||
key->is_entitled_content_key = false;
|
||||
return OEMCrypto_SUCCESS;
|
||||
}
|
||||
|
||||
OEMCryptoResult InitializeCryptoKeyFromWrappedKey(
|
||||
CryptoKey* key, const uint8_t* wrapped_key, uint32_t wrapped_key_length,
|
||||
CryptoKeyType key_type, CryptoKeyOperation key_operation,
|
||||
CryptoKeySize key_size) {
|
||||
ASSERT(key != NULL, "key is NULL");
|
||||
ASSERT(wrapped_key != NULL, "wrapped_key is NULL");
|
||||
ASSERT(wrapped_key_length > 0, "wrapped_key_length is 0");
|
||||
ASSERT(key_type != UNKNOWN_KEY_TYPE, "key_type is UNKNOWN_KEY_TYPE");
|
||||
/* Note that for some keys, we can only know the size from context, since
|
||||
wrapped_key_length corresponds to the size of the serialized key, not
|
||||
the key itself necessarily. So, it's okay for key_size to be unknown.
|
||||
Similarly, sometimes we want to just load the key without using it, so the
|
||||
operation is allowed to be unknown. */
|
||||
OEMCryptoResult result = UnwrapIntoKeyHandle(wrapped_key, wrapped_key_length,
|
||||
key_type, &(key->key_handle));
|
||||
if (result != OEMCrypto_SUCCESS) return result;
|
||||
key->cookie = calculate_cookie(key);
|
||||
memset(key->key_id, 0, KEY_ID_MAX_SIZE);
|
||||
key->key_id_size = 0;
|
||||
key->key_type = key_type;
|
||||
key->key_operation = key_operation;
|
||||
key->key_size = key_size;
|
||||
key->allowed_schemes = 0;
|
||||
memset(&key->key_control_block, 0, sizeof(key->key_control_block));
|
||||
key->entitled_content_key_index = 0;
|
||||
key->has_entitled_content_key = false;
|
||||
key->entitlement_key_index = 0;
|
||||
key->is_entitled_content_key = false;
|
||||
return OEMCrypto_SUCCESS;
|
||||
}
|
||||
|
||||
OEMCryptoResult WrapCryptoKey(CryptoKey* key, uint8_t* buffer,
|
||||
size_t buffer_length) {
|
||||
ASSERT(key != NULL, "key is NULL");
|
||||
ASSERT(buffer != NULL, "wrapped_key is NULL");
|
||||
ASSERT(buffer_length > 0, "wrapped_key_length is 0");
|
||||
return WrapKey(buffer, buffer_length, key->key_type, key->key_handle);
|
||||
}
|
||||
|
||||
OEMCryptoResult FreeCryptoKey(CryptoKey* key) {
|
||||
ASSERT(key != NULL, "key is NULL");
|
||||
if (key->key_handle != NULL) {
|
||||
OEMCryptoResult result = FreeKeyHandle(key->key_handle);
|
||||
if (result != OEMCrypto_SUCCESS) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
memset(key, 0, sizeof(CryptoKey));
|
||||
return OEMCrypto_SUCCESS;
|
||||
}
|
||||
|
||||
bool CheckKey(CryptoKey* key, CryptoKeyType key_type,
|
||||
CryptoKeyOperation key_operation) {
|
||||
return key != NULL && key->key_type == key_type &&
|
||||
key->key_operation == key_operation &&
|
||||
calculate_cookie(key) == key->cookie;
|
||||
}
|
||||
|
||||
/* This extracts 4 bytes in network byte order to a 32 bit integer in host byte
|
||||
order. */
|
||||
static uint32_t extract_field_from_KCB(const uint8_t* kcb, uint8_t index) {
|
||||
ASSERT(kcb != NULL && index <= 3,
|
||||
"Key control block is NULL or index is invalid");
|
||||
uint8_t byte_index = index * 4;
|
||||
return NetworkToHostU32(*(const uint32_t*)(&kcb[byte_index]));
|
||||
}
|
||||
|
||||
KeyControlBlock ParseKeyControlBlock(const uint8_t* kcb) {
|
||||
ASSERT(kcb != NULL, "kcb is NULL");
|
||||
KeyControlBlock key_control_block;
|
||||
memset(&key_control_block, 0, sizeof(key_control_block));
|
||||
memcpy(key_control_block.verification, kcb, 4);
|
||||
key_control_block.duration = extract_field_from_KCB(kcb, 1);
|
||||
key_control_block.nonce = extract_field_from_KCB(kcb, 2);
|
||||
key_control_block.control_bits = extract_field_from_KCB(kcb, 3);
|
||||
|
||||
const char* verification = key_control_block.verification;
|
||||
if (memcmp(verification, "kctl", 4) && /* original verification */
|
||||
memcmp(verification, "kc09", 4) && /* add in version 9 api */
|
||||
memcmp(verification, "kc10", 4) && /* add in version 10 api */
|
||||
memcmp(verification, "kc11", 4) && /* add in version 11 api */
|
||||
memcmp(verification, "kc12", 4) && /* add in version 12 api */
|
||||
memcmp(verification, "kc13", 4) && /* add in version 13 api */
|
||||
memcmp(verification, "kc14", 4) && /* add in version 14 api */
|
||||
memcmp(verification, "kc15", 4)) { /* add in version 15 api */
|
||||
key_control_block.valid = false;
|
||||
} else {
|
||||
key_control_block.valid = true;
|
||||
}
|
||||
return key_control_block;
|
||||
}
|
||||
Reference in New Issue
Block a user